document-drive 1.3.4 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-drive",
3
- "version": "1.3.4",
3
+ "version": "1.4.1",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "module": "./src/index.ts",
@@ -26,34 +26,32 @@
26
26
  "./src"
27
27
  ],
28
28
  "peerDependencies": {
29
+ "@powerhousedao/scalars": "latest",
30
+ "change-case": "^5.4.4",
29
31
  "document-model": "^2.3.1",
30
32
  "document-model-libs": "^1.104.0",
31
- "@powerhousedao/scalars": "latest"
33
+ "graphql": "^16.9.0",
34
+ "graphql-request": "^6.1.0",
35
+ "json-stringify-deterministic": "^1.0.12",
36
+ "nanoevents": "^9.0.0",
37
+ "sanitize-filename": "^1.6.3",
38
+ "uuid": "^9.0.1"
32
39
  },
33
40
  "optionalDependencies": {
34
41
  "@prisma/client": "^5.18.0",
42
+ "exponential-backoff": "^3.1.1",
35
43
  "localforage": "^1.10.0",
36
44
  "redis": "^4.6.15",
37
45
  "sequelize": "^6.37.3",
38
46
  "sqlite3": "^5.1.7"
39
47
  },
40
- "dependencies": {
41
- "change-case": "^5.4.4",
42
- "exponential-backoff": "^3.1.1",
43
- "graphql": "^16.9.0",
44
- "graphql-request": "^6.1.0",
45
- "json-stringify-deterministic": "^1.0.12",
46
- "nanoevents": "^9.0.0",
47
- "sanitize-filename": "^1.6.3",
48
- "uuid": "^9.0.1"
49
- },
50
48
  "devDependencies": {
51
49
  "@powerhousedao/scalars": "latest",
52
50
  "@prisma/client": "5.17.0",
53
51
  "@types/node": "^20.14.11",
54
52
  "@types/uuid": "^9.0.8",
55
53
  "document-model": "^2.6.0",
56
- "document-model-libs": "^1.110.0",
54
+ "document-model-libs": "^1.111.0",
57
55
  "fake-indexeddb": "^5.0.2",
58
56
  "localforage": "^1.10.0",
59
57
  "msw": "^2.3.1",
@@ -61,7 +59,15 @@
61
59
  "sequelize": "^6.37.2",
62
60
  "sqlite3": "^5.1.7",
63
61
  "webdriverio": "^9.0.9",
64
- "vitest-fetch-mock": "^0.3.0"
62
+ "vitest-fetch-mock": "^0.3.0",
63
+ "change-case": "^5.4.4",
64
+ "exponential-backoff": "^3.1.1",
65
+ "graphql": "^16.9.0",
66
+ "graphql-request": "^6.1.0",
67
+ "json-stringify-deterministic": "^1.0.12",
68
+ "nanoevents": "^9.0.0",
69
+ "sanitize-filename": "^1.6.3",
70
+ "uuid": "^9.0.1"
65
71
  },
66
72
  "scripts": {
67
73
  "check-types": "tsc --noEmit",
@@ -136,7 +136,7 @@ export class BaseDocumentDriveServer
136
136
  storage: IDriveStorage = new MemoryStorage(),
137
137
  cache: ICache = new InMemoryCache(),
138
138
  queueManager: IQueueManager = new BaseQueueManager(),
139
- options?: DocumentDriveServerOptions
139
+ options?: DocumentDriveServerOptions,
140
140
  ) {
141
141
  super();
142
142
  this.options = {
@@ -157,7 +157,7 @@ export class BaseDocumentDriveServer
157
157
  this.listenerStateManager = new ListenerManager(
158
158
  this,
159
159
  undefined,
160
- options?.listenerManager
160
+ options?.listenerManager,
161
161
  );
162
162
  this.documentModels = documentModels;
163
163
  this.storage = storage;
@@ -166,7 +166,7 @@ export class BaseDocumentDriveServer
166
166
  this.defaultDrivesManager = new DefaultDrivesManager(
167
167
  this,
168
168
  this.defaultDrivesManagerDelegate,
169
- options
169
+ options,
170
170
  );
171
171
 
172
172
  this.storage.setStorageDelegate?.({
@@ -210,7 +210,7 @@ export class BaseDocumentDriveServer
210
210
  }
211
211
 
212
212
  private getCombinedSyncUnitStatus(
213
- syncUnitStatus: SyncUnitStatusObject
213
+ syncUnitStatus: SyncUnitStatusObject,
214
214
  ): SyncStatus {
215
215
  if (!syncUnitStatus.pull && !syncUnitStatus.push) return "INITIAL_SYNC";
216
216
  if (syncUnitStatus.pull === "INITIAL_SYNC") return "INITIAL_SYNC";
@@ -225,7 +225,7 @@ export class BaseDocumentDriveServer
225
225
  "SUCCESS",
226
226
  ];
227
227
  const sortedStatus = Object.values(syncUnitStatus).sort(
228
- (a, b) => order.indexOf(a) - order.indexOf(b)
228
+ (a, b) => order.indexOf(a) - order.indexOf(b),
229
229
  );
230
230
 
231
231
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -234,10 +234,10 @@ export class BaseDocumentDriveServer
234
234
 
235
235
  private initSyncStatus(
236
236
  syncUnitId: string,
237
- status: Partial<SyncUnitStatusObject>
237
+ status: Partial<SyncUnitStatusObject>,
238
238
  ) {
239
239
  const defaultSyncUnitStatus: SyncUnitStatusObject = Object.entries(
240
- status
240
+ status,
241
241
  ).reduce((acc, [key, _status]) => {
242
242
  return {
243
243
  ...acc,
@@ -251,13 +251,13 @@ export class BaseDocumentDriveServer
251
251
  syncUnitId,
252
252
  this.getCombinedSyncUnitStatus(defaultSyncUnitStatus),
253
253
  undefined,
254
- defaultSyncUnitStatus
254
+ defaultSyncUnitStatus,
255
255
  );
256
256
  }
257
257
 
258
258
  private async initializeDriveSyncStatus(
259
259
  driveId: string,
260
- drive: DocumentDriveDocument
260
+ drive: DocumentDriveDocument,
261
261
  ) {
262
262
  const syncUnits = await this.getSynchronizationUnitsIds(driveId);
263
263
  const syncStatus: SyncUnitStatusObject = {
@@ -277,7 +277,7 @@ export class BaseDocumentDriveServer
277
277
  private updateSyncUnitStatus(
278
278
  syncUnitId: string,
279
279
  status: Partial<SyncUnitStatusObject> | null,
280
- error?: Error
280
+ error?: Error,
281
281
  ) {
282
282
  if (status === null) {
283
283
  this.syncStatus.delete(syncUnitId);
@@ -293,7 +293,7 @@ export class BaseDocumentDriveServer
293
293
 
294
294
  const shouldUpdateStatus = Object.entries(status).some(
295
295
  ([key, _status]) =>
296
- syncUnitStatus[key as keyof SyncUnitStatusObject] !== _status
296
+ syncUnitStatus[key as keyof SyncUnitStatusObject] !== _status,
297
297
  );
298
298
 
299
299
  if (shouldUpdateStatus) {
@@ -321,7 +321,7 @@ export class BaseDocumentDriveServer
321
321
  syncUnitId,
322
322
  this.getCombinedSyncUnitStatus(newstatus),
323
323
  error,
324
- newstatus
324
+ newstatus,
325
325
  );
326
326
  }
327
327
  }
@@ -338,7 +338,7 @@ export class BaseDocumentDriveServer
338
338
  ? this.queueDriveOperations(
339
339
  strand.driveId,
340
340
  operations as Operation<DocumentDriveAction | BaseAction>[],
341
- { source }
341
+ { source },
342
342
  )
343
343
  : this.queueOperations(strand.driveId, strand.documentId, operations, {
344
344
  source,
@@ -352,7 +352,7 @@ export class BaseDocumentDriveServer
352
352
  strand.driveId,
353
353
  [strand.documentId],
354
354
  [strand.scope],
355
- [strand.branch]
355
+ [strand.branch],
356
356
  )
357
357
  ).map((s) => s.syncId)
358
358
  : [strand.driveId];
@@ -363,7 +363,7 @@ export class BaseDocumentDriveServer
363
363
  this.updateSyncUnitStatus(
364
364
  syncUnit,
365
365
  { [operationSource]: result.status },
366
- result.error
366
+ result.error,
367
367
  );
368
368
  }
369
369
  }
@@ -374,11 +374,11 @@ export class BaseDocumentDriveServer
374
374
  private handleListenerError(
375
375
  error: Error,
376
376
  driveId: string,
377
- listener: ListenerState
377
+ listener: ListenerState,
378
378
  ) {
379
379
  logger.error(
380
380
  `Listener ${listener.listener.label ?? listener.listener.listenerId} error:`,
381
- error
381
+ error,
382
382
  );
383
383
 
384
384
  const status = error instanceof OperationError ? error.status : "ERROR";
@@ -403,7 +403,7 @@ export class BaseDocumentDriveServer
403
403
  undefined,
404
404
  undefined,
405
405
  undefined,
406
- drive
406
+ drive,
407
407
  );
408
408
 
409
409
  for (const trigger of drive.state.local.triggers) {
@@ -439,13 +439,13 @@ export class BaseDocumentDriveServer
439
439
  driveId,
440
440
  trigger,
441
441
  error.response.status,
442
- error.message
442
+ error.message,
443
443
  );
444
444
  }
445
445
  },
446
446
  (revisions) => {
447
447
  const errorRevision = revisions.filter(
448
- (r) => r.status !== "SUCCESS"
448
+ (r) => r.status !== "SUCCESS",
449
449
  );
450
450
 
451
451
  if (errorRevision.length < 1) {
@@ -462,14 +462,14 @@ export class BaseDocumentDriveServer
462
462
  .then((revSyncUnits) => {
463
463
  for (const syncUnit of revSyncUnits) {
464
464
  const fileErrorRevision = errorRevision.find(
465
- (r) => r.documentId === syncUnit.documentId
465
+ (r) => r.documentId === syncUnit.documentId,
466
466
  );
467
467
 
468
468
  if (fileErrorRevision) {
469
469
  this.updateSyncUnitStatus(
470
470
  syncUnit.syncId,
471
471
  { pull: fileErrorRevision.status },
472
- fileErrorRevision.error
472
+ fileErrorRevision.error,
473
473
  );
474
474
  } else {
475
475
  this.updateSyncUnitStatus(syncUnit.syncId, {
@@ -485,7 +485,7 @@ export class BaseDocumentDriveServer
485
485
  if (firstPull) {
486
486
  firstPull = false;
487
487
  const pushListener = drive.state.local.listeners.find(
488
- (listener) => trigger.data.url === listener.callInfo?.data
488
+ (listener) => trigger.data.url === listener.callInfo?.data,
489
489
  );
490
490
  if (pushListener) {
491
491
  this.getSynchronizationUnitsRevision(driveId, syncUnits)
@@ -496,7 +496,7 @@ export class BaseDocumentDriveServer
496
496
  pushListener.listenerId,
497
497
  driveId,
498
498
  revision.syncId,
499
- revision.revision
499
+ revision.revision,
500
500
  )
501
501
  .catch(logger.error);
502
502
  }
@@ -504,7 +504,7 @@ export class BaseDocumentDriveServer
504
504
  .catch(logger.error);
505
505
  }
506
506
  }
507
- }
507
+ },
508
508
  );
509
509
  driveTriggers.set(trigger.id, cancelPullLoop);
510
510
  this.triggerMap.set(driveId, driveTriggers);
@@ -537,7 +537,7 @@ export class BaseDocumentDriveServer
537
537
  private queueDelegate = {
538
538
  checkDocumentExists: (
539
539
  driveId: string,
540
- documentId: string
540
+ documentId: string,
541
541
  ): Promise<boolean> =>
542
542
  this.storage.checkDocumentExists(driveId, documentId),
543
543
  processOperationJob: async ({
@@ -551,7 +551,7 @@ export class BaseDocumentDriveServer
551
551
  : this.addDriveOperations(
552
552
  driveId,
553
553
  operations as Operation<DocumentDriveAction | BaseAction>[],
554
- options
554
+ options,
555
555
  );
556
556
  },
557
557
  processActionJob: async ({
@@ -565,7 +565,7 @@ export class BaseDocumentDriveServer
565
565
  : this.addDriveActions(
566
566
  driveId,
567
567
  actions as Operation<DocumentDriveAction | BaseAction>[],
568
- options
568
+ options,
569
569
  );
570
570
  },
571
571
  processJob: async (job: Job) => {
@@ -616,7 +616,7 @@ export class BaseDocumentDriveServer
616
616
  .triggerUpdate(
617
617
  false,
618
618
  { type: "local" },
619
- this.handleListenerError.bind(this)
619
+ this.handleListenerError.bind(this),
620
620
  )
621
621
  .catch((error) => {
622
622
  logger.error("Non handled error updating listeners", error);
@@ -644,7 +644,7 @@ export class BaseDocumentDriveServer
644
644
  scope?: string[],
645
645
  branch?: string[],
646
646
  documentType?: string[],
647
- loadedDrive?: DocumentDriveDocument
647
+ loadedDrive?: DocumentDriveDocument,
648
648
  ) {
649
649
  const drive = loadedDrive || (await this.getDrive(driveId));
650
650
 
@@ -654,19 +654,19 @@ export class BaseDocumentDriveServer
654
654
  scope,
655
655
  branch,
656
656
  documentType,
657
- drive
657
+ drive,
658
658
  );
659
659
  return this.getSynchronizationUnitsRevision(
660
660
  driveId,
661
661
  synchronizationUnitsQuery,
662
- drive
662
+ drive,
663
663
  );
664
664
  }
665
665
 
666
666
  public async getSynchronizationUnitsRevision(
667
667
  driveId: string,
668
668
  syncUnitsQuery: SynchronizationUnitQuery[],
669
- loadedDrive?: DocumentDriveDocument
669
+ loadedDrive?: DocumentDriveDocument,
670
670
  ): Promise<SynchronizationUnit[]> {
671
671
  const drive = loadedDrive || (await this.getDrive(driveId));
672
672
 
@@ -678,7 +678,7 @@ export class BaseDocumentDriveServer
678
678
  ...s,
679
679
  lastUpdated: drive.created,
680
680
  revision: -1,
681
- })
681
+ }),
682
682
  );
683
683
  for (const revision of revisions) {
684
684
  const syncUnit = synchronizationUnits.find(
@@ -686,7 +686,7 @@ export class BaseDocumentDriveServer
686
686
  revision.driveId === s.driveId &&
687
687
  revision.documentId === s.documentId &&
688
688
  revision.scope === s.scope &&
689
- revision.branch === s.branch
689
+ revision.branch === s.branch,
690
690
  );
691
691
  if (syncUnit) {
692
692
  syncUnit.revision = revision.revision;
@@ -702,7 +702,7 @@ export class BaseDocumentDriveServer
702
702
  scope?: string[],
703
703
  branch?: string[],
704
704
  documentType?: string[],
705
- loadedDrive?: DocumentDriveDocument
705
+ loadedDrive?: DocumentDriveDocument,
706
706
  ): Promise<SynchronizationUnitQuery[]> {
707
707
  const drive = loadedDrive ?? (await this.getDrive(driveId));
708
708
  const nodes = drive.state.global.nodes.filter(
@@ -713,7 +713,7 @@ export class BaseDocumentDriveServer
713
713
  documentId.includes("*")) &&
714
714
  (!documentType?.length ||
715
715
  documentType.includes(node.documentType) ||
716
- documentType.includes("*"))
716
+ documentType.includes("*")),
717
717
  ) as Pick<FileNode, "id" | "documentType" | "synchronizationUnits">[];
718
718
 
719
719
  // checks if document drive synchronization unit should be added
@@ -750,7 +750,7 @@ export class BaseDocumentDriveServer
750
750
  scope.includes("*")) &&
751
751
  (!branch?.length ||
752
752
  branch.includes(unit.branch) ||
753
- branch.includes("*"))
753
+ branch.includes("*")),
754
754
  )
755
755
  : node.synchronizationUnits;
756
756
  if (!nodeUnits.length) {
@@ -764,7 +764,7 @@ export class BaseDocumentDriveServer
764
764
  documentType: node.documentType,
765
765
  scope: n.scope,
766
766
  branch: n.branch,
767
- }))
767
+ })),
768
768
  );
769
769
  }
770
770
  return synchronizationUnitsQuery;
@@ -773,13 +773,13 @@ export class BaseDocumentDriveServer
773
773
  public async getSynchronizationUnitIdInfo(
774
774
  driveId: string,
775
775
  syncId: string,
776
- loadedDrive?: DocumentDriveDocument
776
+ loadedDrive?: DocumentDriveDocument,
777
777
  ): Promise<SynchronizationUnitQuery | undefined> {
778
778
  const drive = loadedDrive || (await this.getDrive(driveId));
779
779
  const node = drive.state.global.nodes.find(
780
780
  (node) =>
781
781
  isFileNode(node) &&
782
- node.synchronizationUnits.find((unit) => unit.syncId === syncId)
782
+ node.synchronizationUnits.find((unit) => unit.syncId === syncId),
783
783
  );
784
784
 
785
785
  if (!node || !isFileNode(node)) {
@@ -787,7 +787,7 @@ export class BaseDocumentDriveServer
787
787
  }
788
788
 
789
789
  const syncUnit = node.synchronizationUnits.find(
790
- (unit) => unit.syncId === syncId
790
+ (unit) => unit.syncId === syncId,
791
791
  );
792
792
  if (!syncUnit) {
793
793
  return undefined;
@@ -806,12 +806,12 @@ export class BaseDocumentDriveServer
806
806
  public async getSynchronizationUnit(
807
807
  driveId: string,
808
808
  syncId: string,
809
- loadedDrive?: DocumentDriveDocument
809
+ loadedDrive?: DocumentDriveDocument,
810
810
  ): Promise<SynchronizationUnit | undefined> {
811
811
  const syncUnit = await this.getSynchronizationUnitIdInfo(
812
812
  driveId,
813
813
  syncId,
814
- loadedDrive
814
+ loadedDrive,
815
815
  );
816
816
 
817
817
  if (!syncUnit) {
@@ -841,7 +841,7 @@ export class BaseDocumentDriveServer
841
841
  driveId: string,
842
842
  syncId: string,
843
843
  filter: GetStrandsOptions,
844
- loadedDrive?: DocumentDriveDocument
844
+ loadedDrive?: DocumentDriveDocument,
845
845
  ): Promise<OperationUpdate[]> {
846
846
  const syncUnit =
847
847
  syncId === "0"
@@ -866,7 +866,7 @@ export class BaseDocumentDriveServer
866
866
  ((filter.since === undefined ||
867
867
  isBefore(filter.since, operation.timestamp)) &&
868
868
  (filter.fromRevision === undefined ||
869
- operation.index > filter.fromRevision))
869
+ operation.index > filter.fromRevision)),
870
870
  );
871
871
 
872
872
  const limitedOperations = filter.limit
@@ -887,7 +887,7 @@ export class BaseDocumentDriveServer
887
887
 
888
888
  protected getDocumentModel(documentType: string) {
889
889
  const documentModel = this.documentModels.find(
890
- (model) => model.documentModel.id === documentType
890
+ (model) => model.documentModel.id === documentType,
891
891
  );
892
892
  if (!documentModel) {
893
893
  throw new Error(`Document type ${documentType} not supported`);
@@ -929,7 +929,7 @@ export class BaseDocumentDriveServer
929
929
 
930
930
  async addRemoteDrive(
931
931
  url: string,
932
- options: RemoteDriveOptions
932
+ options: RemoteDriveOptions,
933
933
  ): Promise<DocumentDriveDocument> {
934
934
  const { id, name, slug, icon } =
935
935
  options.expectedDriveInfo || (await requestPublicDrive(url));
@@ -968,13 +968,13 @@ export class BaseDocumentDriveServer
968
968
  public async registerPullResponderTrigger(
969
969
  id: string,
970
970
  url: string,
971
- options: Pick<RemoteDriveOptions, "pullFilter" | "pullInterval">
971
+ options: Pick<RemoteDriveOptions, "pullFilter" | "pullInterval">,
972
972
  ) {
973
973
  const pullTrigger =
974
974
  await PullResponderTransmitter.createPullResponderTrigger(
975
975
  id,
976
976
  url,
977
- options
977
+ options,
978
978
  );
979
979
 
980
980
  return pullTrigger;
@@ -1106,14 +1106,14 @@ export class BaseDocumentDriveServer
1106
1106
  await this.storage.addDriveOperations(
1107
1107
  driveId,
1108
1108
  operations as Operation<DocumentDriveAction>[],
1109
- document
1109
+ document,
1110
1110
  );
1111
1111
  } else {
1112
1112
  await this.storage.addDocumentOperations(
1113
1113
  driveId,
1114
1114
  input.id,
1115
1115
  operations,
1116
- document
1116
+ document,
1117
1117
  );
1118
1118
  }
1119
1119
  }
@@ -1141,7 +1141,7 @@ export class BaseDocumentDriveServer
1141
1141
  drive: string,
1142
1142
  documentId: string | undefined,
1143
1143
  documentStorage: DocumentStorage<T>,
1144
- operations: Operation<A | BaseAction>[]
1144
+ operations: Operation<A | BaseAction>[],
1145
1145
  ) {
1146
1146
  const operationsApplied: Operation<A | BaseAction>[] = [];
1147
1147
  const signals: SignalResult[] = [];
@@ -1149,7 +1149,7 @@ export class BaseDocumentDriveServer
1149
1149
  const documentStorageWithState = await this._addDocumentResultingStage(
1150
1150
  documentStorage,
1151
1151
  drive,
1152
- documentId
1152
+ documentId,
1153
1153
  );
1154
1154
 
1155
1155
  let document: T = this._buildDocument(documentStorageWithState);
@@ -1163,7 +1163,7 @@ export class BaseDocumentDriveServer
1163
1163
  // TODO two equal operations done by two clients will be considered the same, ie: { type: "INCREMENT" }
1164
1164
  const branch = removeExistingOperations(
1165
1165
  operationsByScope[scope as OperationScope] || [],
1166
- storageDocumentOperations
1166
+ storageDocumentOperations,
1167
1167
  );
1168
1168
 
1169
1169
  // No operations to apply
@@ -1181,7 +1181,7 @@ export class BaseDocumentDriveServer
1181
1181
  : merge(trunk, invertedTrunk, reshuffleByTimestamp);
1182
1182
 
1183
1183
  const newOperations = newHistory.filter(
1184
- (op) => trunk.length < 1 || precedes(trunk[trunk.length - 1]!, op)
1184
+ (op) => trunk.length < 1 || precedes(trunk[trunk.length - 1]!, op),
1185
1185
  );
1186
1186
 
1187
1187
  for (const nextOperation of newOperations) {
@@ -1191,7 +1191,7 @@ export class BaseDocumentDriveServer
1191
1191
  // for the operations that were re-indexed (previous hash becomes invalid due the new position in the history)
1192
1192
  if (tail.length > 0) {
1193
1193
  const sourceOperation = operations.find(
1194
- (op) => op.hash === nextOperation.hash
1194
+ (op) => op.hash === nextOperation.hash,
1195
1195
  );
1196
1196
 
1197
1197
  skipHashValidation =
@@ -1209,7 +1209,7 @@ export class BaseDocumentDriveServer
1209
1209
  documentId,
1210
1210
  document,
1211
1211
  nextOperation,
1212
- skipHashValidation
1212
+ skipHashValidation,
1213
1213
  );
1214
1214
  const appliedResult = await (taskQueueMethod
1215
1215
  ? runAsapAsync(task, taskQueueMethod)
@@ -1227,7 +1227,7 @@ export class BaseDocumentDriveServer
1227
1227
  "ERROR",
1228
1228
  nextOperation,
1229
1229
  (e as Error).message,
1230
- (e as Error).cause
1230
+ (e as Error).cause,
1231
1231
  );
1232
1232
 
1233
1233
  // TODO: don't break on errors...
@@ -1248,7 +1248,7 @@ export class BaseDocumentDriveServer
1248
1248
  document: DocumentStorage<T>,
1249
1249
  drive: string,
1250
1250
  documentId?: string,
1251
- options?: GetDocumentOptions
1251
+ options?: GetDocumentOptions,
1252
1252
  ): Promise<DocumentStorage<T>> {
1253
1253
  // apply skip header operations to all scopes
1254
1254
  const operations =
@@ -1257,7 +1257,7 @@ export class BaseDocumentDriveServer
1257
1257
  : document.operations;
1258
1258
  const documentOperations =
1259
1259
  DocumentUtils.documentHelpers.garbageCollectDocumentOperations(
1260
- operations
1260
+ operations,
1261
1261
  );
1262
1262
 
1263
1263
  for (const scope of Object.keys(documentOperations)) {
@@ -1272,13 +1272,13 @@ export class BaseDocumentDriveServer
1272
1272
  documentId,
1273
1273
  lastRemainingOperation.index,
1274
1274
  lastRemainingOperation.scope,
1275
- "main"
1275
+ "main",
1276
1276
  )
1277
1277
  : this.storage.getDriveOperationResultingState?.(
1278
1278
  drive,
1279
1279
  lastRemainingOperation.index,
1280
1280
  lastRemainingOperation.scope,
1281
- "main"
1281
+ "main",
1282
1282
  ));
1283
1283
  }
1284
1284
  }
@@ -1291,7 +1291,7 @@ export class BaseDocumentDriveServer
1291
1291
 
1292
1292
  private _buildDocument<T extends Document>(
1293
1293
  documentStorage: DocumentStorage<T>,
1294
- options?: GetDocumentOptions
1294
+ options?: GetDocumentOptions,
1295
1295
  ): T {
1296
1296
  if (documentStorage.state && (!options || options.checkHashes === false)) {
1297
1297
  return documentStorage as T;
@@ -1303,12 +1303,12 @@ export class BaseDocumentDriveServer
1303
1303
  options?.revisions !== undefined
1304
1304
  ? filterOperationsByRevision(
1305
1305
  documentStorage.operations,
1306
- options.revisions
1306
+ options.revisions,
1307
1307
  )
1308
1308
  : documentStorage.operations;
1309
1309
  const operations =
1310
1310
  baseUtils.documentHelpers.garbageCollectDocumentOperations(
1311
- revisionOperations
1311
+ revisionOperations,
1312
1312
  );
1313
1313
 
1314
1314
  return baseUtils.replayDocument(
@@ -1322,7 +1322,7 @@ export class BaseDocumentDriveServer
1322
1322
  ...options,
1323
1323
  checkHashes: options?.checkHashes ?? true,
1324
1324
  reuseOperationResultingState: options?.checkHashes ?? true,
1325
- }
1325
+ },
1326
1326
  ) as T;
1327
1327
  }
1328
1328
 
@@ -1331,7 +1331,7 @@ export class BaseDocumentDriveServer
1331
1331
  id: string | undefined,
1332
1332
  document: T,
1333
1333
  operation: Operation,
1334
- skipHashValidation = false
1334
+ skipHashValidation = false,
1335
1335
  ) {
1336
1336
  const documentModel = this.getDocumentModel(document.documentType);
1337
1337
 
@@ -1344,7 +1344,7 @@ export class BaseDocumentDriveServer
1344
1344
  ...document.operations,
1345
1345
  [scope]: DocumentUtils.documentHelpers.skipHeaderOperations(
1346
1346
  document.operations[scope],
1347
- operation
1347
+ operation,
1348
1348
  ),
1349
1349
  });
1350
1350
 
@@ -1358,13 +1358,13 @@ export class BaseDocumentDriveServer
1358
1358
  id,
1359
1359
  lastRemainingOperation.index,
1360
1360
  lastRemainingOperation.scope,
1361
- "main"
1361
+ "main",
1362
1362
  )
1363
1363
  : this.storage.getDriveOperationResultingState?.(
1364
1364
  drive,
1365
1365
  lastRemainingOperation.index,
1366
1366
  lastRemainingOperation.scope,
1367
- "main"
1367
+ "main",
1368
1368
  ));
1369
1369
  }
1370
1370
 
@@ -1389,21 +1389,21 @@ export class BaseDocumentDriveServer
1389
1389
  documentType: documentToCopy.documentType,
1390
1390
  document: documentToCopy,
1391
1391
  synchronizationUnits: signal.input.synchronizationUnits,
1392
- })
1392
+ }),
1393
1393
  );
1394
1394
  break;
1395
1395
  }
1396
1396
  if (handler) {
1397
1397
  operationSignals.push(() =>
1398
- handler().then((result) => ({ signal, result }))
1398
+ handler().then((result) => ({ signal, result })),
1399
1399
  );
1400
1400
  }
1401
1401
  },
1402
- { skip: operation.skip, reuseOperationResultingState: true }
1402
+ { skip: operation.skip, reuseOperationResultingState: true },
1403
1403
  ) as T;
1404
1404
 
1405
1405
  const appliedOperations = newDocument.operations[operation.scope].filter(
1406
- (op) => op.index == operation.index && op.skip == operation.skip
1406
+ (op) => op.index == operation.index && op.skip == operation.skip,
1407
1407
  );
1408
1408
  const appliedOperation = appliedOperations.at(0);
1409
1409
 
@@ -1411,7 +1411,7 @@ export class BaseDocumentDriveServer
1411
1411
  throw new OperationError(
1412
1412
  "ERROR",
1413
1413
  operation,
1414
- `Operation with index ${operation.index}:${operation.skip} was not applied.`
1414
+ `Operation with index ${operation.index}:${operation.skip} was not applied.`,
1415
1415
  );
1416
1416
  }
1417
1417
  if (
@@ -1438,7 +1438,7 @@ export class BaseDocumentDriveServer
1438
1438
  drive: string,
1439
1439
  id: string,
1440
1440
  operation: Operation,
1441
- options?: AddOperationOptions
1441
+ options?: AddOperationOptions,
1442
1442
  ): Promise<IOperationResult> {
1443
1443
  return this.addOperations(drive, id, [operation], options);
1444
1444
  }
@@ -1449,7 +1449,7 @@ export class BaseDocumentDriveServer
1449
1449
  callback: (document: DocumentStorage) => Promise<{
1450
1450
  operations: Operation[];
1451
1451
  header: DocumentHeader;
1452
- }>
1452
+ }>,
1453
1453
  ) {
1454
1454
  if (!this.storage.addDocumentOperationsWithTransaction) {
1455
1455
  const documentStorage = await this.storage.getDocument(drive, id);
@@ -1460,14 +1460,14 @@ export class BaseDocumentDriveServer
1460
1460
  drive,
1461
1461
  id,
1462
1462
  result.operations,
1463
- result.header
1463
+ result.header,
1464
1464
  );
1465
1465
  }
1466
1466
  } else {
1467
1467
  await this.storage.addDocumentOperationsWithTransaction(
1468
1468
  drive,
1469
1469
  id,
1470
- callback
1470
+ callback,
1471
1471
  );
1472
1472
  }
1473
1473
  }
@@ -1476,7 +1476,7 @@ export class BaseDocumentDriveServer
1476
1476
  drive: string,
1477
1477
  id: string,
1478
1478
  operation: Operation,
1479
- options?: AddOperationOptions
1479
+ options?: AddOperationOptions,
1480
1480
  ): Promise<IOperationResult> {
1481
1481
  return this.queueOperations(drive, id, [operation], options);
1482
1482
  }
@@ -1484,7 +1484,7 @@ export class BaseDocumentDriveServer
1484
1484
  private async resultIfExistingOperations(
1485
1485
  drive: string,
1486
1486
  id: string,
1487
- operations: Operation[]
1487
+ operations: Operation[],
1488
1488
  ): Promise<IOperationResult | undefined> {
1489
1489
  try {
1490
1490
  const document = await this.getDocument(drive, id);
@@ -1496,8 +1496,8 @@ export class BaseDocumentDriveServer
1496
1496
  existingOp.id === op.id &&
1497
1497
  existingOp.index === op.index &&
1498
1498
  existingOp.type === op.type &&
1499
- existingOp.hash === op.hash
1500
- )
1499
+ existingOp.hash === op.hash,
1500
+ ),
1501
1501
  );
1502
1502
  if (!newOperation) {
1503
1503
  return {
@@ -1523,7 +1523,7 @@ export class BaseDocumentDriveServer
1523
1523
  drive: string,
1524
1524
  id: string,
1525
1525
  operations: Operation[],
1526
- options?: AddOperationOptions
1526
+ options?: AddOperationOptions,
1527
1527
  ) {
1528
1528
  // if operations are already stored then returns cached document
1529
1529
  const result = await this.resultIfExistingOperations(drive, id, operations);
@@ -1547,7 +1547,7 @@ export class BaseDocumentDriveServer
1547
1547
  unsubscribeError();
1548
1548
  resolve(result);
1549
1549
  }
1550
- }
1550
+ },
1551
1551
  );
1552
1552
  const unsubscribeError = this.queueManager.on(
1553
1553
  "jobFailed",
@@ -1557,7 +1557,7 @@ export class BaseDocumentDriveServer
1557
1557
  unsubscribeError();
1558
1558
  reject(error);
1559
1559
  }
1560
- }
1560
+ },
1561
1561
  );
1562
1562
  });
1563
1563
  } catch (error) {
@@ -1570,7 +1570,7 @@ export class BaseDocumentDriveServer
1570
1570
  drive: string,
1571
1571
  id: string,
1572
1572
  action: Action,
1573
- options?: AddOperationOptions
1573
+ options?: AddOperationOptions,
1574
1574
  ): Promise<IOperationResult> {
1575
1575
  return this.queueActions(drive, id, [action], options);
1576
1576
  }
@@ -1579,7 +1579,7 @@ export class BaseDocumentDriveServer
1579
1579
  drive: string,
1580
1580
  id: string,
1581
1581
  actions: Action[],
1582
- options?: AddOperationOptions
1582
+ options?: AddOperationOptions,
1583
1583
  ): Promise<IOperationResult> {
1584
1584
  try {
1585
1585
  const jobId = await this.queueManager.addJob({
@@ -1598,7 +1598,7 @@ export class BaseDocumentDriveServer
1598
1598
  unsubscribeError();
1599
1599
  resolve(result);
1600
1600
  }
1601
- }
1601
+ },
1602
1602
  );
1603
1603
  const unsubscribeError = this.queueManager.on(
1604
1604
  "jobFailed",
@@ -1608,7 +1608,7 @@ export class BaseDocumentDriveServer
1608
1608
  unsubscribeError();
1609
1609
  reject(error);
1610
1610
  }
1611
- }
1611
+ },
1612
1612
  );
1613
1613
  });
1614
1614
  } catch (error) {
@@ -1620,7 +1620,7 @@ export class BaseDocumentDriveServer
1620
1620
  async queueDriveAction(
1621
1621
  drive: string,
1622
1622
  action: DocumentDriveAction | BaseAction,
1623
- options?: AddOperationOptions
1623
+ options?: AddOperationOptions,
1624
1624
  ): Promise<IOperationResult<DocumentDriveDocument>> {
1625
1625
  return this.queueDriveActions(drive, [action], options);
1626
1626
  }
@@ -1628,7 +1628,7 @@ export class BaseDocumentDriveServer
1628
1628
  async queueDriveActions(
1629
1629
  drive: string,
1630
1630
  actions: (DocumentDriveAction | BaseAction)[],
1631
- options?: AddOperationOptions
1631
+ options?: AddOperationOptions,
1632
1632
  ): Promise<IOperationResult<DocumentDriveDocument>> {
1633
1633
  try {
1634
1634
  const jobId = await this.queueManager.addJob({
@@ -1646,7 +1646,7 @@ export class BaseDocumentDriveServer
1646
1646
  unsubscribeError();
1647
1647
  resolve(result as IOperationResult<DocumentDriveDocument>);
1648
1648
  }
1649
- }
1649
+ },
1650
1650
  );
1651
1651
  const unsubscribeError = this.queueManager.on(
1652
1652
  "jobFailed",
@@ -1656,9 +1656,9 @@ export class BaseDocumentDriveServer
1656
1656
  unsubscribeError();
1657
1657
  reject(error);
1658
1658
  }
1659
- }
1659
+ },
1660
1660
  );
1661
- }
1661
+ },
1662
1662
  );
1663
1663
  } catch (error) {
1664
1664
  logger.error("Error adding drive job", error);
@@ -1670,7 +1670,7 @@ export class BaseDocumentDriveServer
1670
1670
  drive: string,
1671
1671
  id: string,
1672
1672
  operations: Operation[],
1673
- options?: AddOperationOptions
1673
+ options?: AddOperationOptions,
1674
1674
  ) {
1675
1675
  // if operations are already stored then returns the result
1676
1676
  const result = await this.resultIfExistingOperations(drive, id, operations);
@@ -1688,7 +1688,7 @@ export class BaseDocumentDriveServer
1688
1688
  drive,
1689
1689
  id,
1690
1690
  documentStorage,
1691
- operations
1691
+ operations,
1692
1692
  );
1693
1693
 
1694
1694
  if (!result.document) {
@@ -1720,14 +1720,14 @@ export class BaseDocumentDriveServer
1720
1720
  }
1721
1721
  return acc;
1722
1722
  },
1723
- { scopes: [] as string[], branches: ["main"] }
1723
+ { scopes: [] as string[], branches: ["main"] },
1724
1724
  );
1725
1725
 
1726
1726
  const syncUnits = await this.getSynchronizationUnits(
1727
1727
  drive,
1728
1728
  [id],
1729
1729
  scopes,
1730
- branches
1730
+ branches,
1731
1731
  );
1732
1732
 
1733
1733
  // checks if any of the provided operations where reshufled
@@ -1738,8 +1738,8 @@ export class BaseDocumentDriveServer
1738
1738
  o.id === appliedOp.id &&
1739
1739
  o.index === appliedOp.index &&
1740
1740
  o.skip === appliedOp.skip &&
1741
- o.hash === appliedOp.hash
1742
- )
1741
+ o.hash === appliedOp.hash,
1742
+ ),
1743
1743
  );
1744
1744
 
1745
1745
  // if there are no new operations then reuses the provided source
@@ -1770,7 +1770,7 @@ export class BaseDocumentDriveServer
1770
1770
  }
1771
1771
  },
1772
1772
  this.handleListenerError.bind(this),
1773
- options?.forceSync ?? source.type === "local"
1773
+ options?.forceSync ?? source.type === "local",
1774
1774
  )
1775
1775
  .then((updates) => {
1776
1776
  if (updates.length) {
@@ -1792,7 +1792,7 @@ export class BaseDocumentDriveServer
1792
1792
  {
1793
1793
  [operationSource]: "ERROR",
1794
1794
  },
1795
- error as Error
1795
+ error as Error,
1796
1796
  );
1797
1797
 
1798
1798
  for (const syncUnit of syncUnits) {
@@ -1801,7 +1801,7 @@ export class BaseDocumentDriveServer
1801
1801
  {
1802
1802
  [operationSource]: "ERROR",
1803
1803
  },
1804
- error as Error
1804
+ error as Error,
1805
1805
  );
1806
1806
  }
1807
1807
  });
@@ -1826,7 +1826,7 @@ export class BaseDocumentDriveServer
1826
1826
  "ERROR",
1827
1827
  undefined,
1828
1828
  (error as Error).message,
1829
- (error as Error).cause
1829
+ (error as Error).cause,
1830
1830
  );
1831
1831
 
1832
1832
  return {
@@ -1842,7 +1842,7 @@ export class BaseDocumentDriveServer
1842
1842
  addDriveOperation(
1843
1843
  drive: string,
1844
1844
  operation: Operation<DocumentDriveAction | BaseAction>,
1845
- options?: AddOperationOptions
1845
+ options?: AddOperationOptions,
1846
1846
  ) {
1847
1847
  return this.addDriveOperations(drive, [operation], options);
1848
1848
  }
@@ -1860,7 +1860,7 @@ export class BaseDocumentDriveServer
1860
1860
  callback: (document: DocumentDriveStorage) => Promise<{
1861
1861
  operations: Operation<DocumentDriveAction | BaseAction>[];
1862
1862
  header: DocumentHeader;
1863
- }>
1863
+ }>,
1864
1864
  ) {
1865
1865
  if (!this.storage.addDriveOperationsWithTransaction) {
1866
1866
  const documentStorage = await this.storage.getDrive(drive);
@@ -1870,7 +1870,7 @@ export class BaseDocumentDriveServer
1870
1870
  await this.storage.addDriveOperations(
1871
1871
  drive,
1872
1872
  result.operations,
1873
- result.header
1873
+ result.header,
1874
1874
  );
1875
1875
  }
1876
1876
  return result;
@@ -1882,14 +1882,14 @@ export class BaseDocumentDriveServer
1882
1882
  queueDriveOperation(
1883
1883
  drive: string,
1884
1884
  operation: Operation<DocumentDriveAction | BaseAction>,
1885
- options?: AddOperationOptions
1885
+ options?: AddOperationOptions,
1886
1886
  ): Promise<IOperationResult<DocumentDriveDocument>> {
1887
1887
  return this.queueDriveOperations(drive, [operation], options);
1888
1888
  }
1889
1889
 
1890
1890
  private async resultIfExistingDriveOperations(
1891
1891
  driveId: string,
1892
- operations: Operation<DocumentDriveAction | BaseAction>[]
1892
+ operations: Operation<DocumentDriveAction | BaseAction>[],
1893
1893
  ): Promise<IOperationResult<DocumentDriveDocument> | undefined> {
1894
1894
  try {
1895
1895
  const drive = await this.getDrive(driveId);
@@ -1901,8 +1901,8 @@ export class BaseDocumentDriveServer
1901
1901
  existingOp.id === op.id &&
1902
1902
  existingOp.index === op.index &&
1903
1903
  existingOp.type === op.type &&
1904
- existingOp.hash === op.hash
1905
- )
1904
+ existingOp.hash === op.hash,
1905
+ ),
1906
1906
  );
1907
1907
  if (!newOperation) {
1908
1908
  return {
@@ -1923,12 +1923,12 @@ export class BaseDocumentDriveServer
1923
1923
  async queueDriveOperations(
1924
1924
  drive: string,
1925
1925
  operations: Operation<DocumentDriveAction | BaseAction>[],
1926
- options?: AddOperationOptions
1926
+ options?: AddOperationOptions,
1927
1927
  ): Promise<IOperationResult<DocumentDriveDocument>> {
1928
1928
  // if operations are already stored then returns cached document
1929
1929
  const result = await this.resultIfExistingDriveOperations(
1930
1930
  drive,
1931
- operations
1931
+ operations,
1932
1932
  );
1933
1933
  if (result) {
1934
1934
  return result;
@@ -1949,7 +1949,7 @@ export class BaseDocumentDriveServer
1949
1949
  unsubscribeError();
1950
1950
  resolve(result as IOperationResult<DocumentDriveDocument>);
1951
1951
  }
1952
- }
1952
+ },
1953
1953
  );
1954
1954
  const unsubscribeError = this.queueManager.on(
1955
1955
  "jobFailed",
@@ -1959,9 +1959,9 @@ export class BaseDocumentDriveServer
1959
1959
  unsubscribeError();
1960
1960
  reject(error);
1961
1961
  }
1962
- }
1962
+ },
1963
1963
  );
1964
- }
1964
+ },
1965
1965
  );
1966
1966
  } catch (error) {
1967
1967
  logger.error("Error adding drive job", error);
@@ -1972,7 +1972,7 @@ export class BaseDocumentDriveServer
1972
1972
  async addDriveOperations(
1973
1973
  drive: string,
1974
1974
  operations: Operation<DocumentDriveAction | BaseAction>[],
1975
- options?: AddOperationOptions
1975
+ options?: AddOperationOptions,
1976
1976
  ) {
1977
1977
  let document: DocumentDriveDocument | undefined;
1978
1978
  const operationsApplied: Operation<DocumentDriveAction | BaseAction>[] = [];
@@ -1982,7 +1982,7 @@ export class BaseDocumentDriveServer
1982
1982
  // if operations are already stored then returns cached drive
1983
1983
  const result = await this.resultIfExistingDriveOperations(
1984
1984
  drive,
1985
- operations
1985
+ operations,
1986
1986
  );
1987
1987
  if (result) {
1988
1988
  return result;
@@ -2039,8 +2039,8 @@ export class BaseDocumentDriveServer
2039
2039
  o.id === appliedOp.id &&
2040
2040
  o.index === appliedOp.index &&
2041
2041
  o.skip === appliedOp.skip &&
2042
- o.hash === appliedOp.hash
2043
- )
2042
+ o.hash === appliedOp.hash,
2043
+ ),
2044
2044
  );
2045
2045
 
2046
2046
  // if there are no new operations then reuses the provided source
@@ -2074,7 +2074,7 @@ export class BaseDocumentDriveServer
2074
2074
  });
2075
2075
  },
2076
2076
  this.handleListenerError.bind(this),
2077
- options?.forceSync ?? source.type === "local"
2077
+ options?.forceSync ?? source.type === "local",
2078
2078
  )
2079
2079
  .then((updates) => {
2080
2080
  if (updates.length) {
@@ -2088,7 +2088,7 @@ export class BaseDocumentDriveServer
2088
2088
  this.updateSyncUnitStatus(
2089
2089
  drive,
2090
2090
  { [operationSource]: "ERROR" },
2091
- error as Error
2091
+ error as Error,
2092
2092
  );
2093
2093
  });
2094
2094
  }
@@ -2119,7 +2119,7 @@ export class BaseDocumentDriveServer
2119
2119
  "ERROR",
2120
2120
  undefined,
2121
2121
  (error as Error).message,
2122
- (error as Error).cause
2122
+ (error as Error).cause,
2123
2123
  );
2124
2124
 
2125
2125
  return {
@@ -2134,7 +2134,7 @@ export class BaseDocumentDriveServer
2134
2134
 
2135
2135
  private _buildOperations<T extends Action>(
2136
2136
  document: Document,
2137
- actions: (T | BaseAction)[]
2137
+ actions: (T | BaseAction)[],
2138
2138
  ): Operation<T | BaseAction>[] {
2139
2139
  const operations: Operation<T | BaseAction>[] = [];
2140
2140
  const { reducer } = this.getDocumentModel(document.documentType);
@@ -2153,7 +2153,7 @@ export class BaseDocumentDriveServer
2153
2153
  drive: string,
2154
2154
  id: string,
2155
2155
  action: Action,
2156
- options?: AddOperationOptions
2156
+ options?: AddOperationOptions,
2157
2157
  ): Promise<IOperationResult> {
2158
2158
  return this.addActions(drive, id, [action], options);
2159
2159
  }
@@ -2162,7 +2162,7 @@ export class BaseDocumentDriveServer
2162
2162
  drive: string,
2163
2163
  id: string,
2164
2164
  actions: Action[],
2165
- options?: AddOperationOptions
2165
+ options?: AddOperationOptions,
2166
2166
  ): Promise<IOperationResult> {
2167
2167
  const document = await this.getDocument(drive, id);
2168
2168
  const operations = this._buildOperations(document, actions);
@@ -2172,7 +2172,7 @@ export class BaseDocumentDriveServer
2172
2172
  async addDriveAction(
2173
2173
  drive: string,
2174
2174
  action: DocumentDriveAction | BaseAction,
2175
- options?: AddOperationOptions
2175
+ options?: AddOperationOptions,
2176
2176
  ): Promise<IOperationResult<DocumentDriveDocument>> {
2177
2177
  return this.addDriveActions(drive, [action], options);
2178
2178
  }
@@ -2180,7 +2180,7 @@ export class BaseDocumentDriveServer
2180
2180
  async addDriveActions(
2181
2181
  drive: string,
2182
2182
  actions: (DocumentDriveAction | BaseAction)[],
2183
- options?: AddOperationOptions
2183
+ options?: AddOperationOptions,
2184
2184
  ): Promise<IOperationResult<DocumentDriveDocument>> {
2185
2185
  const document = await this.getDrive(drive);
2186
2186
  const operations = this._buildOperations(document, actions);
@@ -2196,7 +2196,7 @@ export class BaseDocumentDriveServer
2196
2196
  label: string;
2197
2197
  block: boolean;
2198
2198
  filter: ListenerFilter;
2199
- }
2199
+ },
2200
2200
  ) {
2201
2201
  const listener: AddListenerInput["listener"] = {
2202
2202
  callInfo: {
@@ -2230,26 +2230,26 @@ export class BaseDocumentDriveServer
2230
2230
  for (const listener of listeners) {
2231
2231
  await this.addDriveAction(
2232
2232
  driveId,
2233
- actions.removeListener({ listenerId: listener.listenerId })
2233
+ actions.removeListener({ listenerId: listener.listenerId }),
2234
2234
  );
2235
2235
  }
2236
2236
 
2237
2237
  for (const trigger of triggers) {
2238
2238
  await this.addDriveAction(
2239
2239
  driveId,
2240
- actions.removeTrigger({ triggerId: trigger.id })
2240
+ actions.removeTrigger({ triggerId: trigger.id }),
2241
2241
  );
2242
2242
  }
2243
2243
 
2244
2244
  await this.addDriveAction(
2245
2245
  driveId,
2246
- actions.setSharingType({ type: "LOCAL" })
2246
+ actions.setSharingType({ type: "LOCAL" }),
2247
2247
  );
2248
2248
  }
2249
2249
 
2250
2250
  private async addListener(
2251
2251
  driveId: string,
2252
- operation: Operation<Action<"ADD_LISTENER", AddListenerInput>>
2252
+ operation: Operation<Action<"ADD_LISTENER", AddListenerInput>>,
2253
2253
  ) {
2254
2254
  const { listener } = operation.input;
2255
2255
  await this.listenerStateManager.addListener({
@@ -2273,7 +2273,7 @@ export class BaseDocumentDriveServer
2273
2273
 
2274
2274
  private async removeListener(
2275
2275
  driveId: string,
2276
- operation: Operation<Action<"REMOVE_LISTENER", RemoveListenerInput>>
2276
+ operation: Operation<Action<"REMOVE_LISTENER", RemoveListenerInput>>,
2277
2277
  ) {
2278
2278
  const { listenerId } = operation.input;
2279
2279
  await this.listenerStateManager.removeListener(driveId, listenerId);
@@ -2281,26 +2281,26 @@ export class BaseDocumentDriveServer
2281
2281
 
2282
2282
  getTransmitter(
2283
2283
  driveId: string,
2284
- listenerId: string
2284
+ listenerId: string,
2285
2285
  ): Promise<ITransmitter | undefined> {
2286
2286
  return this.listenerStateManager.getTransmitter(driveId, listenerId);
2287
2287
  }
2288
2288
 
2289
2289
  getListener(
2290
2290
  driveId: string,
2291
- listenerId: string
2291
+ listenerId: string,
2292
2292
  ): Promise<ListenerState | undefined> {
2293
2293
  return this.listenerStateManager.getListener(driveId, listenerId);
2294
2294
  }
2295
2295
 
2296
2296
  getSyncStatus(
2297
- syncUnitId: string
2297
+ syncUnitId: string,
2298
2298
  ): SyncStatus | SynchronizationUnitNotFoundError {
2299
2299
  const status = this.syncStatus.get(syncUnitId);
2300
2300
  if (!status) {
2301
2301
  return new SynchronizationUnitNotFoundError(
2302
2302
  `Sync status not found for syncUnitId: ${syncUnitId}`,
2303
- syncUnitId
2303
+ syncUnitId,
2304
2304
  );
2305
2305
  }
2306
2306
  return this.getCombinedSyncUnitStatus(status);
@@ -27,6 +27,10 @@ export type InternalTransmitterUpdate<
27
27
  state: T["state"][S];
28
28
  };
29
29
 
30
+ export interface IInternalTransmitter extends ITransmitter {
31
+ setReceiver(receiver: IReceiver): void;
32
+ }
33
+
30
34
  export class InternalTransmitter implements ITransmitter {
31
35
  private drive: IBaseDocumentDriveServer;
32
36
  private listener: Listener;
@@ -22,6 +22,10 @@ import type {
22
22
  } from "document-model/document";
23
23
  import { Unsubscribe } from "nanoevents";
24
24
  import { BaseDocumentDriveServer } from ".";
25
+ import {
26
+ IReceiver as IInternalListener,
27
+ IInternalTransmitter,
28
+ } from "./listener/transmitter/internal";
25
29
  import { IReadModeDriveServer } from "../read-mode/types";
26
30
  import { RunAsap } from "../utils";
27
31
  import { IDefaultDrivesManager } from "../utils/default-drives-manager";
@@ -443,6 +447,17 @@ export abstract class AbstractDocumentDriveServer {
443
447
  syncUnitId: string,
444
448
  ): SyncStatus | SynchronizationUnitNotFoundError;
445
449
 
450
+ abstract addInternalListener(
451
+ driveId: string,
452
+ receiver: IInternalListener,
453
+ options: {
454
+ listenerId: string;
455
+ label: string;
456
+ block: boolean;
457
+ filter: ListenerFilter;
458
+ },
459
+ ): Promise<IInternalTransmitter>;
460
+
446
461
  /** Synchronization methods */
447
462
  abstract getSynchronizationUnits(
448
463
  driveId: string,
@@ -486,12 +501,10 @@ export abstract class AbstractDocumentDriveServer {
486
501
 
487
502
  /** Event methods **/
488
503
  protected abstract emit<K extends keyof DriveEvents>(
489
- this: this,
490
504
  event: K,
491
505
  ...args: Parameters<DriveEvents[K]>
492
506
  ): void;
493
507
  abstract on<K extends keyof DriveEvents>(
494
- this: this,
495
508
  event: K,
496
509
  cb: DriveEvents[K],
497
510
  ): Unsubscribe;
@@ -518,10 +531,13 @@ export const DefaultListenerManagerOptions = {
518
531
  sequentialUpdates: true,
519
532
  };
520
533
 
521
- export type IBaseDocumentDriveServer = Pick<
522
- AbstractDocumentDriveServer,
523
- keyof AbstractDocumentDriveServer
524
- >;
534
+ type PublicKeys<T> = {
535
+ [K in keyof T]: T extends { [P in K]: T[K] } ? K : never;
536
+ }[keyof T];
537
+
538
+ type PublicPart<T> = Pick<T, PublicKeys<T>>;
539
+
540
+ export type IBaseDocumentDriveServer = PublicPart<AbstractDocumentDriveServer>;
525
541
 
526
542
  export type IDocumentDriveServer = IBaseDocumentDriveServer &
527
543
  IDefaultDrivesManager &