Skip to content

Commit 9536dc3

Browse files
committed
Make call recordings private and share them at creation
Declare callRecording PRIVATE in the standard application, have the fathom, fireflies and call-recorder apps state who may read each recording through shareWith when they create it, and add two 2.39 workspace commands: one flips the readability of the existing callRecording object, the other backfills one EVERYONE FULL share row per existing recording so enabling IS_RECORD_SHARING_ENABLED loses nothing a workspace member could already do.
1 parent a88e941 commit 9536dc3

28 files changed

Lines changed: 625 additions & 35 deletions

packages/twenty-apps/public/call-recorder/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"name": "@twentyhq/call-recorder",
3-
"version": "1.12.0",
3+
"version": "1.12.1",
44
"license": "MIT",
55
"engines": {
66
"node": "^24.5.0",
77
"npm": "please-use-yarn",
88
"yarn": ">=4.0.2",
9-
"twenty": ">=2.37.0"
9+
"twenty": ">=2.39.0"
1010
},
1111
"keywords": [
1212
"twenty-app"

packages/twenty-apps/public/call-recorder/src/__tests__/call-recorder-lifecycle.integration-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ describe('call recorder app lifecycle (integration)', () => {
491491
calendarEventId,
492492
...overrides,
493493
},
494+
shareWith: [{ everyone: true, accessLevel: 'READ' }],
494495
},
495496
id: true,
496497
},

packages/twenty-apps/public/call-recorder/src/logic-functions/data/create-call-recording.util.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const createCallRecording = async (
2525
createCallRecording: {
2626
__args: {
2727
data: { id, ...data },
28+
shareWith: [{ everyone: true, accessLevel: 'READ' }],
2829
},
2930
id: true,
3031
},

packages/twenty-apps/public/call-recorder/src/logic-functions/flows/__tests__/reconcile-call-recorder.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class FakeCoreApiClient {
124124

125125
async mutation(mutation: any): Promise<any> {
126126
if (mutation.createCallRecording !== undefined) {
127-
const data = mutation.createCallRecording.__args.data;
127+
const { data, shareWith } = mutation.createCallRecording.__args;
128128

129129
if (this.callRecordings.some((candidate) => candidate.id === data.id)) {
130130
throw new Error(`Duplicate call recording id ${data.id}`);
@@ -135,7 +135,7 @@ class FakeCoreApiClient {
135135
this.callRecordings.push(createdCallRecording);
136136
this.mutations.push({
137137
name: 'createCallRecording',
138-
args: data,
138+
args: { data, shareWith },
139139
});
140140

141141
return {
@@ -274,6 +274,12 @@ describe('reconcileCallRecorderForCalendarEventIds', () => {
274274
callRecordingId: buildCustomerSyncCallRecordingId(),
275275
}),
276276
]);
277+
expect(client.mutations).toContainEqual({
278+
name: 'createCallRecording',
279+
args: expect.objectContaining({
280+
shareWith: [{ everyone: true, accessLevel: 'READ' }],
281+
}),
282+
});
277283
expect(client.callRecordings).toEqual([
278284
{
279285
id: buildCustomerSyncCallRecordingId(),

packages/twenty-apps/public/fathom/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to this application are documented in this file.
44

5+
## 0.1.1
6+
7+
- State who may read each synced Call Recording at creation: the connecting
8+
workspace member for a personal Fathom connection, everyone otherwise.
9+
Requires Twenty 2.39.0 or later.
10+
511
## 0.1.0
612

713
- Add per-user Fathom OAuth and signed webhook registration.

packages/twenty-apps/public/fathom/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
"name": "@twentyhq/fathom",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"license": "MIT",
55
"engines": {
66
"node": "^24.5.0",
77
"npm": "please-use-yarn",
8-
"yarn": ">=4.0.2"
8+
"yarn": ">=4.0.2",
9+
"twenty": ">=2.39.0"
910
},
1011
"keywords": [],
1112
"packageManager": "yarn@4.13.0",
@@ -26,8 +27,8 @@
2627
"@types/node": "^24.7.2",
2728
"@typescript/native-preview": "^7.0.0-dev.20260116.1",
2829
"oxlint": "^0.16.0",
29-
"twenty-client-sdk": "2.35.0",
30-
"twenty-sdk": "2.35.0",
30+
"twenty-client-sdk": "2.37.0",
31+
"twenty-sdk": "2.37.0",
3132
"typescript": "^5.9.3",
3233
"vite-tsconfig-paths": "^4.2.1",
3334
"vitest": "^4.0.0"

packages/twenty-apps/public/fathom/src/logic-functions/fathom-backfill-batch.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@ export const fathomBackfillBatchHandler = async (payload: {
5151
// meetings already imported, which costs calls but cannot duplicate
5252
// records: the CallRecording id is derived from the recording.
5353
results.push(
54-
await syncFathomMeetingToCallRecording({ coreApiClient, meeting }).catch(
55-
(error: unknown) => {
56-
throw new RetryableLogicFunctionError(toErrorMessage(error));
57-
},
58-
),
54+
await syncFathomMeetingToCallRecording({
55+
coreApiClient,
56+
meeting,
57+
connection,
58+
}).catch((error: unknown) => {
59+
throw new RetryableLogicFunctionError(toErrorMessage(error));
60+
}),
5961
);
6062
}
6163

packages/twenty-apps/public/fathom/src/logic-functions/fathom-sync-call.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export const fathomSyncCallHandler = async (
8080
fathomClient,
8181
serializedMeeting: serializeFathomMeeting(meeting),
8282
}),
83+
connection,
8384
});
8485

8586
return { success: true, recordingId, ...syncResult };

packages/twenty-apps/public/fathom/src/logic-functions/fathom-webhook.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { FATHOM_WEBHOOK_CONNECTION_QUERY_PARAMETER } from 'src/constants/fathom.
1010
import { FATHOM_WEBHOOK_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
1111
import { type FathomWebhookRegistration } from 'src/logic-functions/types/fathom-webhook-registration.type';
1212
import { getFathomWebhookRegistrationKey } from 'src/logic-functions/utils/get-fathom-webhook-registration-key.util';
13+
import { listFathomConnections } from 'src/logic-functions/utils/list-fathom-connections.util';
1314
import { syncFathomMeetingToCallRecording } from 'src/logic-functions/utils/sync-fathom-meeting-to-call-recording.util';
1415

1516
type FathomWebhookResult =
@@ -86,9 +87,18 @@ export const fathomWebhookHandler = async (
8687
return { success: false, error: 'Invalid Fathom meeting payload' };
8788
}
8889

90+
const connection = (await listFathomConnections()).find(
91+
(candidate) => candidate.id === connectedAccountId,
92+
);
93+
94+
if (!isDefined(connection)) {
95+
return { success: false, error: 'Fathom connection must be reconnected' };
96+
}
97+
8998
const syncResult = await syncFathomMeetingToCallRecording({
9099
coreApiClient: new CoreApiClient({ runAs: 'application' }),
91100
meeting: meetingParseResult.value,
101+
connection,
92102
});
93103

94104
return { success: true, ...syncResult };
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type CallRecordingShareWith =
2+
| { workspaceMemberId: string; accessLevel: 'FULL' }
3+
| { everyone: true; accessLevel: 'READ' };

0 commit comments

Comments
 (0)