document-drive 6.0.0-dev.105 → 6.0.0-dev.107
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/dist/chunk-CX61OkwL.mjs +16 -0
- package/dist/index-HOJm2mt2.d.mts +205 -0
- package/dist/index-HOJm2mt2.d.mts.map +1 -0
- package/dist/index.d.ts +1944 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5170 -1
- package/dist/index.js.map +1 -1
- package/dist/storage/filesystem.d.mts +49 -0
- package/dist/storage/filesystem.d.mts.map +1 -0
- package/dist/storage/filesystem.mjs +371 -0
- package/dist/storage/filesystem.mjs.map +1 -0
- package/dist/storage/prisma.d.mts +11508 -0
- package/dist/storage/prisma.d.mts.map +1 -0
- package/dist/storage/prisma.mjs +7582 -0
- package/dist/storage/prisma.mjs.map +1 -0
- package/dist/utils-BI7cwVSp.mjs +74 -0
- package/dist/utils-BI7cwVSp.mjs.map +1 -0
- package/package.json +21 -38
- package/dist/prisma/schema.prisma +0 -93
- package/dist/src/cache/index.d.ts +0 -4
- package/dist/src/cache/index.d.ts.map +0 -1
- package/dist/src/cache/index.js +0 -4
- package/dist/src/cache/index.js.map +0 -1
- package/dist/src/cache/lru.d.ts +0 -22
- package/dist/src/cache/lru.d.ts.map +0 -1
- package/dist/src/cache/lru.js +0 -40
- package/dist/src/cache/lru.js.map +0 -1
- package/dist/src/cache/memory.d.ts +0 -27
- package/dist/src/cache/memory.d.ts.map +0 -1
- package/dist/src/cache/memory.js +0 -104
- package/dist/src/cache/memory.js.map +0 -1
- package/dist/src/cache/redis.d.ts +0 -22
- package/dist/src/cache/redis.d.ts.map +0 -1
- package/dist/src/cache/redis.js +0 -91
- package/dist/src/cache/redis.js.map +0 -1
- package/dist/src/cache/types.d.ts +0 -37
- package/dist/src/cache/types.d.ts.map +0 -1
- package/dist/src/cache/types.js +0 -2
- package/dist/src/cache/types.js.map +0 -1
- package/dist/src/cache/util.d.ts +0 -3
- package/dist/src/cache/util.d.ts.map +0 -1
- package/dist/src/cache/util.js +0 -16
- package/dist/src/cache/util.js.map +0 -1
- package/dist/src/drive-document-model/constants.d.ts +0 -2
- package/dist/src/drive-document-model/constants.d.ts.map +0 -1
- package/dist/src/drive-document-model/constants.js +0 -2
- package/dist/src/drive-document-model/constants.js.map +0 -1
- package/dist/src/drive-document-model/gen/creators.d.ts +0 -3
- package/dist/src/drive-document-model/gen/creators.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/creators.js +0 -3
- package/dist/src/drive-document-model/gen/creators.js.map +0 -1
- package/dist/src/drive-document-model/gen/document-model.d.ts +0 -3
- package/dist/src/drive-document-model/gen/document-model.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/document-model.js +0 -210
- package/dist/src/drive-document-model/gen/document-model.js.map +0 -1
- package/dist/src/drive-document-model/gen/document-schema.d.ts +0 -68
- package/dist/src/drive-document-model/gen/document-schema.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/document-schema.js +0 -35
- package/dist/src/drive-document-model/gen/document-schema.js.map +0 -1
- package/dist/src/drive-document-model/gen/document-type.d.ts +0 -2
- package/dist/src/drive-document-model/gen/document-type.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/document-type.js +0 -2
- package/dist/src/drive-document-model/gen/document-type.js.map +0 -1
- package/dist/src/drive-document-model/gen/drive/actions.d.ts +0 -46
- package/dist/src/drive-document-model/gen/drive/actions.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/drive/actions.js +0 -2
- package/dist/src/drive-document-model/gen/drive/actions.js.map +0 -1
- package/dist/src/drive-document-model/gen/drive/creators.d.ts +0 -10
- package/dist/src/drive-document-model/gen/drive/creators.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/drive/creators.js +0 -11
- package/dist/src/drive-document-model/gen/drive/creators.js.map +0 -1
- package/dist/src/drive-document-model/gen/drive/error.d.ts +0 -2
- package/dist/src/drive-document-model/gen/drive/error.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/drive/error.js +0 -2
- package/dist/src/drive-document-model/gen/drive/error.js.map +0 -1
- package/dist/src/drive-document-model/gen/drive/index.d.ts +0 -2
- package/dist/src/drive-document-model/gen/drive/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/drive/index.js +0 -2
- package/dist/src/drive-document-model/gen/drive/index.js.map +0 -1
- package/dist/src/drive-document-model/gen/drive/types.d.ts +0 -2
- package/dist/src/drive-document-model/gen/drive/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/drive/types.js +0 -2
- package/dist/src/drive-document-model/gen/drive/types.js.map +0 -1
- package/dist/src/drive-document-model/gen/index.d.ts +0 -10
- package/dist/src/drive-document-model/gen/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/index.js +0 -10
- package/dist/src/drive-document-model/gen/index.js.map +0 -1
- package/dist/src/drive-document-model/gen/node/actions.d.ts +0 -41
- package/dist/src/drive-document-model/gen/node/actions.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/node/actions.js +0 -2
- package/dist/src/drive-document-model/gen/node/actions.js.map +0 -1
- package/dist/src/drive-document-model/gen/node/creators.d.ts +0 -13
- package/dist/src/drive-document-model/gen/node/creators.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/node/creators.js +0 -17
- package/dist/src/drive-document-model/gen/node/creators.js.map +0 -1
- package/dist/src/drive-document-model/gen/node/error.d.ts +0 -2
- package/dist/src/drive-document-model/gen/node/error.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/node/error.js +0 -2
- package/dist/src/drive-document-model/gen/node/error.js.map +0 -1
- package/dist/src/drive-document-model/gen/node/index.d.ts +0 -2
- package/dist/src/drive-document-model/gen/node/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/node/index.js +0 -2
- package/dist/src/drive-document-model/gen/node/index.js.map +0 -1
- package/dist/src/drive-document-model/gen/node/types.d.ts +0 -2
- package/dist/src/drive-document-model/gen/node/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/node/types.js +0 -2
- package/dist/src/drive-document-model/gen/node/types.js.map +0 -1
- package/dist/src/drive-document-model/gen/ph-factories.d.ts +0 -12
- package/dist/src/drive-document-model/gen/ph-factories.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/ph-factories.js +0 -46
- package/dist/src/drive-document-model/gen/ph-factories.js.map +0 -1
- package/dist/src/drive-document-model/gen/reducer.d.ts +0 -4
- package/dist/src/drive-document-model/gen/reducer.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/reducer.js +0 -76
- package/dist/src/drive-document-model/gen/reducer.js.map +0 -1
- package/dist/src/drive-document-model/gen/schema/index.d.ts +0 -2
- package/dist/src/drive-document-model/gen/schema/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/schema/index.js +0 -2
- package/dist/src/drive-document-model/gen/schema/index.js.map +0 -1
- package/dist/src/drive-document-model/gen/schema/types.d.ts +0 -283
- package/dist/src/drive-document-model/gen/schema/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/schema/types.js +0 -2
- package/dist/src/drive-document-model/gen/schema/types.js.map +0 -1
- package/dist/src/drive-document-model/gen/schema/zod.d.ts +0 -67
- package/dist/src/drive-document-model/gen/schema/zod.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/schema/zod.js +0 -229
- package/dist/src/drive-document-model/gen/schema/zod.js.map +0 -1
- package/dist/src/drive-document-model/gen/types.d.ts +0 -21
- package/dist/src/drive-document-model/gen/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/types.js +0 -4
- package/dist/src/drive-document-model/gen/types.js.map +0 -1
- package/dist/src/drive-document-model/gen/utils.d.ts +0 -13
- package/dist/src/drive-document-model/gen/utils.d.ts.map +0 -1
- package/dist/src/drive-document-model/gen/utils.js +0 -48
- package/dist/src/drive-document-model/gen/utils.js.map +0 -1
- package/dist/src/drive-document-model/index.d.ts +0 -5
- package/dist/src/drive-document-model/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/index.js +0 -5
- package/dist/src/drive-document-model/index.js.map +0 -1
- package/dist/src/drive-document-model/module.d.ts +0 -3
- package/dist/src/drive-document-model/module.d.ts.map +0 -1
- package/dist/src/drive-document-model/module.js +0 -24
- package/dist/src/drive-document-model/module.js.map +0 -1
- package/dist/src/drive-document-model/src/index.d.ts +0 -3
- package/dist/src/drive-document-model/src/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/index.js +0 -3
- package/dist/src/drive-document-model/src/index.js.map +0 -1
- package/dist/src/drive-document-model/src/reducers/drive.d.ts +0 -8
- package/dist/src/drive-document-model/src/reducers/drive.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/reducers/drive.js +0 -66
- package/dist/src/drive-document-model/src/reducers/drive.js.map +0 -1
- package/dist/src/drive-document-model/src/reducers/index.d.ts +0 -3
- package/dist/src/drive-document-model/src/reducers/index.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/reducers/index.js +0 -3
- package/dist/src/drive-document-model/src/reducers/index.js.map +0 -1
- package/dist/src/drive-document-model/src/reducers/node.d.ts +0 -8
- package/dist/src/drive-document-model/src/reducers/node.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/reducers/node.js +0 -187
- package/dist/src/drive-document-model/src/reducers/node.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/actions.test.d.ts +0 -2
- package/dist/src/drive-document-model/src/tests/actions.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/actions.test.js +0 -197
- package/dist/src/drive-document-model/src/tests/actions.test.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/base.test.d.ts +0 -2
- package/dist/src/drive-document-model/src/tests/base.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/base.test.js +0 -44
- package/dist/src/drive-document-model/src/tests/base.test.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/document-model.test.d.ts +0 -6
- package/dist/src/drive-document-model/src/tests/document-model.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/document-model.test.js +0 -19
- package/dist/src/drive-document-model/src/tests/document-model.test.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/drive.test.d.ts +0 -6
- package/dist/src/drive-document-model/src/tests/drive.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/drive.test.js +0 -38
- package/dist/src/drive-document-model/src/tests/drive.test.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/generate-mock.d.ts +0 -3
- package/dist/src/drive-document-model/src/tests/generate-mock.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/generate-mock.js +0 -5
- package/dist/src/drive-document-model/src/tests/generate-mock.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/node.test.d.ts +0 -6
- package/dist/src/drive-document-model/src/tests/node.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/node.test.js +0 -343
- package/dist/src/drive-document-model/src/tests/node.test.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/test-factories.d.ts +0 -9
- package/dist/src/drive-document-model/src/tests/test-factories.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/test-factories.js +0 -17
- package/dist/src/drive-document-model/src/tests/test-factories.js.map +0 -1
- package/dist/src/drive-document-model/src/tests/utils.test.d.ts +0 -2
- package/dist/src/drive-document-model/src/tests/utils.test.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/tests/utils.test.js +0 -232
- package/dist/src/drive-document-model/src/tests/utils.test.js.map +0 -1
- package/dist/src/drive-document-model/src/types.d.ts +0 -8
- package/dist/src/drive-document-model/src/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/types.js +0 -2
- package/dist/src/drive-document-model/src/types.js.map +0 -1
- package/dist/src/drive-document-model/src/utils.d.ts +0 -23
- package/dist/src/drive-document-model/src/utils.d.ts.map +0 -1
- package/dist/src/drive-document-model/src/utils.js +0 -102
- package/dist/src/drive-document-model/src/utils.js.map +0 -1
- package/dist/src/drive-document-model/types.d.ts +0 -10
- package/dist/src/drive-document-model/types.d.ts.map +0 -1
- package/dist/src/drive-document-model/types.js +0 -3
- package/dist/src/drive-document-model/types.js.map +0 -1
- package/dist/src/index.d.ts +0 -17
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -17
- package/dist/src/index.js.map +0 -1
- package/dist/src/processors/index.d.ts +0 -4
- package/dist/src/processors/index.d.ts.map +0 -1
- package/dist/src/processors/index.js +0 -4
- package/dist/src/processors/index.js.map +0 -1
- package/dist/src/processors/processor-manager.d.ts +0 -21
- package/dist/src/processors/processor-manager.d.ts.map +0 -1
- package/dist/src/processors/processor-manager.js +0 -104
- package/dist/src/processors/processor-manager.js.map +0 -1
- package/dist/src/processors/relational.d.ts +0 -49
- package/dist/src/processors/relational.d.ts.map +0 -1
- package/dist/src/processors/relational.js +0 -57
- package/dist/src/processors/relational.js.map +0 -1
- package/dist/src/processors/types.d.ts +0 -94
- package/dist/src/processors/types.d.ts.map +0 -1
- package/dist/src/processors/types.js +0 -2
- package/dist/src/processors/types.js.map +0 -1
- package/dist/src/processors/utils.d.ts +0 -29
- package/dist/src/processors/utils.d.ts.map +0 -1
- package/dist/src/processors/utils.js +0 -72
- package/dist/src/processors/utils.js.map +0 -1
- package/dist/src/queue/base.d.ts +0 -22
- package/dist/src/queue/base.d.ts.map +0 -1
- package/dist/src/queue/base.js +0 -54
- package/dist/src/queue/base.js.map +0 -1
- package/dist/src/queue/event.d.ts +0 -40
- package/dist/src/queue/event.d.ts.map +0 -1
- package/dist/src/queue/event.js +0 -226
- package/dist/src/queue/event.js.map +0 -1
- package/dist/src/queue/index.d.ts +0 -5
- package/dist/src/queue/index.d.ts.map +0 -1
- package/dist/src/queue/index.js +0 -5
- package/dist/src/queue/index.js.map +0 -1
- package/dist/src/queue/redis.d.ts +0 -2
- package/dist/src/queue/redis.d.ts.map +0 -1
- package/dist/src/queue/redis.js +0 -123
- package/dist/src/queue/redis.js.map +0 -1
- package/dist/src/queue/types.d.ts +0 -59
- package/dist/src/queue/types.d.ts.map +0 -1
- package/dist/src/queue/types.js +0 -2
- package/dist/src/queue/types.js.map +0 -1
- package/dist/src/queue/utils.d.ts +0 -5
- package/dist/src/queue/utils.d.ts.map +0 -1
- package/dist/src/queue/utils.js +0 -10
- package/dist/src/queue/utils.js.map +0 -1
- package/dist/src/read-mode/errors.d.ts +0 -12
- package/dist/src/read-mode/errors.d.ts.map +0 -1
- package/dist/src/read-mode/errors.js +0 -18
- package/dist/src/read-mode/errors.js.map +0 -1
- package/dist/src/read-mode/index.d.ts +0 -4
- package/dist/src/read-mode/index.d.ts.map +0 -1
- package/dist/src/read-mode/index.js +0 -4
- package/dist/src/read-mode/index.js.map +0 -1
- package/dist/src/read-mode/server.d.ts +0 -3
- package/dist/src/read-mode/server.d.ts.map +0 -1
- package/dist/src/read-mode/server.js +0 -78
- package/dist/src/read-mode/server.js.map +0 -1
- package/dist/src/read-mode/service.d.ts +0 -17
- package/dist/src/read-mode/service.d.ts.map +0 -1
- package/dist/src/read-mode/service.js +0 -119
- package/dist/src/read-mode/service.js.map +0 -1
- package/dist/src/read-mode/types.d.ts +0 -31
- package/dist/src/read-mode/types.d.ts.map +0 -1
- package/dist/src/read-mode/types.js +0 -2
- package/dist/src/read-mode/types.js.map +0 -1
- package/dist/src/server/base-server.d.ts +0 -177
- package/dist/src/server/base-server.d.ts.map +0 -1
- package/dist/src/server/base-server.js +0 -2000
- package/dist/src/server/base-server.js.map +0 -1
- package/dist/src/server/builder.d.ts +0 -27
- package/dist/src/server/builder.d.ts.map +0 -1
- package/dist/src/server/builder.js +0 -97
- package/dist/src/server/builder.js.map +0 -1
- package/dist/src/server/error.d.ts +0 -34
- package/dist/src/server/error.d.ts.map +0 -1
- package/dist/src/server/error.js +0 -56
- package/dist/src/server/error.js.map +0 -1
- package/dist/src/server/event-emitter.d.ts +0 -8
- package/dist/src/server/event-emitter.d.ts.map +0 -1
- package/dist/src/server/event-emitter.js +0 -11
- package/dist/src/server/event-emitter.js.map +0 -1
- package/dist/src/server/index.d.ts +0 -10
- package/dist/src/server/index.d.ts.map +0 -1
- package/dist/src/server/index.js +0 -10
- package/dist/src/server/index.js.map +0 -1
- package/dist/src/server/listener/constants.d.ts +0 -4
- package/dist/src/server/listener/constants.d.ts.map +0 -1
- package/dist/src/server/listener/constants.js +0 -4
- package/dist/src/server/listener/constants.js.map +0 -1
- package/dist/src/server/listener/index.d.ts +0 -4
- package/dist/src/server/listener/index.d.ts.map +0 -1
- package/dist/src/server/listener/index.js +0 -4
- package/dist/src/server/listener/index.js.map +0 -1
- package/dist/src/server/listener/listener-manager.d.ts +0 -28
- package/dist/src/server/listener/listener-manager.d.ts.map +0 -1
- package/dist/src/server/listener/listener-manager.js +0 -415
- package/dist/src/server/listener/listener-manager.js.map +0 -1
- package/dist/src/server/listener/util.d.ts +0 -2
- package/dist/src/server/listener/util.d.ts.map +0 -1
- package/dist/src/server/listener/util.js +0 -23
- package/dist/src/server/listener/util.js.map +0 -1
- package/dist/src/server/sync-manager.d.ts +0 -28
- package/dist/src/server/sync-manager.d.ts.map +0 -1
- package/dist/src/server/sync-manager.js +0 -222
- package/dist/src/server/sync-manager.js.map +0 -1
- package/dist/src/server/sync-unit-map.d.ts +0 -116
- package/dist/src/server/sync-unit-map.d.ts.map +0 -1
- package/dist/src/server/sync-unit-map.js +0 -233
- package/dist/src/server/sync-unit-map.js.map +0 -1
- package/dist/src/server/transmitter/constants.d.ts +0 -2
- package/dist/src/server/transmitter/constants.d.ts.map +0 -1
- package/dist/src/server/transmitter/constants.js +0 -2
- package/dist/src/server/transmitter/constants.js.map +0 -1
- package/dist/src/server/transmitter/factory.d.ts +0 -7
- package/dist/src/server/transmitter/factory.d.ts.map +0 -1
- package/dist/src/server/transmitter/factory.js +0 -25
- package/dist/src/server/transmitter/factory.js.map +0 -1
- package/dist/src/server/transmitter/index.d.ts +0 -6
- package/dist/src/server/transmitter/index.d.ts.map +0 -1
- package/dist/src/server/transmitter/index.js +0 -5
- package/dist/src/server/transmitter/index.js.map +0 -1
- package/dist/src/server/transmitter/internal.d.ts +0 -12
- package/dist/src/server/transmitter/internal.d.ts.map +0 -1
- package/dist/src/server/transmitter/internal.js +0 -113
- package/dist/src/server/transmitter/internal.js.map +0 -1
- package/dist/src/server/transmitter/pull-responder.d.ts +0 -30
- package/dist/src/server/transmitter/pull-responder.d.ts.map +0 -1
- package/dist/src/server/transmitter/pull-responder.js +0 -543
- package/dist/src/server/transmitter/pull-responder.js.map +0 -1
- package/dist/src/server/transmitter/switchboard-push.d.ts +0 -11
- package/dist/src/server/transmitter/switchboard-push.d.ts.map +0 -1
- package/dist/src/server/transmitter/switchboard-push.js +0 -130
- package/dist/src/server/transmitter/switchboard-push.js.map +0 -1
- package/dist/src/server/transmitter/types.d.ts +0 -53
- package/dist/src/server/transmitter/types.d.ts.map +0 -1
- package/dist/src/server/transmitter/types.js +0 -2
- package/dist/src/server/transmitter/types.js.map +0 -1
- package/dist/src/server/types.d.ts +0 -419
- package/dist/src/server/types.d.ts.map +0 -1
- package/dist/src/server/types.js +0 -10
- package/dist/src/server/types.js.map +0 -1
- package/dist/src/server/utils.d.ts +0 -19
- package/dist/src/server/utils.d.ts.map +0 -1
- package/dist/src/server/utils.js +0 -110
- package/dist/src/server/utils.js.map +0 -1
- package/dist/src/storage/browser.d.ts +0 -52
- package/dist/src/storage/browser.d.ts.map +0 -1
- package/dist/src/storage/browser.js +0 -430
- package/dist/src/storage/browser.js.map +0 -1
- package/dist/src/storage/filesystem.d.ts +0 -45
- package/dist/src/storage/filesystem.d.ts.map +0 -1
- package/dist/src/storage/filesystem.js +0 -457
- package/dist/src/storage/filesystem.js.map +0 -1
- package/dist/src/storage/index.d.ts +0 -5
- package/dist/src/storage/index.d.ts.map +0 -1
- package/dist/src/storage/index.js +0 -5
- package/dist/src/storage/index.js.map +0 -1
- package/dist/src/storage/ipfs.d.ts +0 -2
- package/dist/src/storage/ipfs.d.ts.map +0 -1
- package/dist/src/storage/ipfs.js +0 -491
- package/dist/src/storage/ipfs.js.map +0 -1
- package/dist/src/storage/memory.d.ts +0 -42
- package/dist/src/storage/memory.d.ts.map +0 -1
- package/dist/src/storage/memory.js +0 -355
- package/dist/src/storage/memory.js.map +0 -1
- package/dist/src/storage/path-encoding.d.ts +0 -21
- package/dist/src/storage/path-encoding.d.ts.map +0 -1
- package/dist/src/storage/path-encoding.js +0 -53
- package/dist/src/storage/path-encoding.js.map +0 -1
- package/dist/src/storage/prisma/client/default.d.ts +0 -1
- package/dist/src/storage/prisma/client/default.js +0 -1
- package/dist/src/storage/prisma/client/edge.d.ts +0 -1
- package/dist/src/storage/prisma/client/edge.js +0 -263
- package/dist/src/storage/prisma/client/index-browser.js +0 -246
- package/dist/src/storage/prisma/client/index.d.ts +0 -10318
- package/dist/src/storage/prisma/client/index.js +0 -292
- package/dist/src/storage/prisma/client/libquery_engine-darwin-arm64.dylib.node +0 -0
- package/dist/src/storage/prisma/client/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
- package/dist/src/storage/prisma/client/libquery_engine-linux-musl.so.node +0 -0
- package/dist/src/storage/prisma/client/package.json +0 -84
- package/dist/src/storage/prisma/client/runtime/edge-esm.js +0 -31
- package/dist/src/storage/prisma/client/runtime/edge.js +0 -31
- package/dist/src/storage/prisma/client/runtime/index-browser.d.ts +0 -365
- package/dist/src/storage/prisma/client/runtime/index-browser.js +0 -13
- package/dist/src/storage/prisma/client/runtime/library.d.ts +0 -3273
- package/dist/src/storage/prisma/client/runtime/library.js +0 -143
- package/dist/src/storage/prisma/client/runtime/react-native.js +0 -80
- package/dist/src/storage/prisma/client/runtime/wasm.js +0 -32
- package/dist/src/storage/prisma/client/schema.prisma +0 -93
- package/dist/src/storage/prisma/client/wasm.d.ts +0 -1
- package/dist/src/storage/prisma/client/wasm.js +0 -246
- package/dist/src/storage/prisma/factory.d.ts +0 -10
- package/dist/src/storage/prisma/factory.d.ts.map +0 -1
- package/dist/src/storage/prisma/factory.js +0 -23
- package/dist/src/storage/prisma/factory.js.map +0 -1
- package/dist/src/storage/prisma/index.d.ts +0 -3
- package/dist/src/storage/prisma/index.d.ts.map +0 -1
- package/dist/src/storage/prisma/index.js +0 -3
- package/dist/src/storage/prisma/index.js.map +0 -1
- package/dist/src/storage/prisma/prisma.d.ts +0 -73
- package/dist/src/storage/prisma/prisma.d.ts.map +0 -1
- package/dist/src/storage/prisma/prisma.js +0 -760
- package/dist/src/storage/prisma/prisma.js.map +0 -1
- package/dist/src/storage/types.d.ts +0 -187
- package/dist/src/storage/types.d.ts.map +0 -1
- package/dist/src/storage/types.js +0 -2
- package/dist/src/storage/types.js.map +0 -1
- package/dist/src/storage/utils.d.ts +0 -6
- package/dist/src/storage/utils.d.ts.map +0 -1
- package/dist/src/storage/utils.js +0 -33
- package/dist/src/storage/utils.js.map +0 -1
- package/dist/src/utils/default-drives-manager.d.ts +0 -18
- package/dist/src/utils/default-drives-manager.d.ts.map +0 -1
- package/dist/src/utils/default-drives-manager.js +0 -208
- package/dist/src/utils/default-drives-manager.js.map +0 -1
- package/dist/src/utils/errors.d.ts +0 -5
- package/dist/src/utils/errors.d.ts.map +0 -1
- package/dist/src/utils/errors.js +0 -10
- package/dist/src/utils/errors.js.map +0 -1
- package/dist/src/utils/gql-transformations.d.ts +0 -32
- package/dist/src/utils/gql-transformations.d.ts.map +0 -1
- package/dist/src/utils/gql-transformations.js +0 -39
- package/dist/src/utils/gql-transformations.js.map +0 -1
- package/dist/src/utils/graphql.d.ts +0 -13
- package/dist/src/utils/graphql.d.ts.map +0 -1
- package/dist/src/utils/graphql.js +0 -196
- package/dist/src/utils/graphql.js.map +0 -1
- package/dist/src/utils/index.d.ts +0 -9
- package/dist/src/utils/index.d.ts.map +0 -1
- package/dist/src/utils/index.js +0 -9
- package/dist/src/utils/index.js.map +0 -1
- package/dist/src/utils/logger.d.ts +0 -3
- package/dist/src/utils/logger.d.ts.map +0 -1
- package/dist/src/utils/logger.js +0 -2
- package/dist/src/utils/logger.js.map +0 -1
- package/dist/src/utils/migrations.d.ts +0 -4
- package/dist/src/utils/migrations.d.ts.map +0 -1
- package/dist/src/utils/migrations.js +0 -112
- package/dist/src/utils/migrations.js.map +0 -1
- package/dist/src/utils/misc.d.ts +0 -21
- package/dist/src/utils/misc.d.ts.map +0 -1
- package/dist/src/utils/misc.js +0 -55
- package/dist/src/utils/misc.js.map +0 -1
- package/dist/src/utils/run-asap.d.ts +0 -8
- package/dist/src/utils/run-asap.d.ts.map +0 -1
- package/dist/src/utils/run-asap.js +0 -120
- package/dist/src/utils/run-asap.js.map +0 -1
- package/dist/src/utils/test.d.ts +0 -63
- package/dist/src/utils/test.d.ts.map +0 -1
- package/dist/src/utils/test.js +0 -161
- package/dist/src/utils/test.js.map +0 -1
- package/dist/src/utils/types.d.ts +0 -44
- package/dist/src/utils/types.d.ts.map +0 -1
- package/dist/src/utils/types.js +0 -2
- package/dist/src/utils/types.js.map +0 -1
- package/dist/test/benchmarks/getDrive.json +0 -10
- package/dist/test/benchmarks/processOperations.bench.d.ts +0 -2
- package/dist/test/benchmarks/processOperations.bench.d.ts.map +0 -1
- package/dist/test/benchmarks/processOperations.bench.js +0 -148
- package/dist/test/benchmarks/processOperations.bench.js.map +0 -1
- package/dist/test/benchmarks/queue.bench.d.ts +0 -2
- package/dist/test/benchmarks/queue.bench.d.ts.map +0 -1
- package/dist/test/benchmarks/queue.bench.js +0 -55
- package/dist/test/benchmarks/queue.bench.js.map +0 -1
- package/dist/test/benchmarks/strands.small.json +0 -37085
- package/dist/test/cache.test.d.ts +0 -2
- package/dist/test/cache.test.d.ts.map +0 -1
- package/dist/test/cache.test.js +0 -276
- package/dist/test/cache.test.js.map +0 -1
- package/dist/test/default-remote-drives.test.d.ts +0 -2
- package/dist/test/default-remote-drives.test.d.ts.map +0 -1
- package/dist/test/default-remote-drives.test.js +0 -445
- package/dist/test/default-remote-drives.test.js.map +0 -1
- package/dist/test/drive-operations.test.d.ts +0 -2
- package/dist/test/drive-operations.test.d.ts.map +0 -1
- package/dist/test/drive-operations.test.js +0 -134
- package/dist/test/drive-operations.test.js.map +0 -1
- package/dist/test/dual-action-create.test.d.ts +0 -2
- package/dist/test/dual-action-create.test.d.ts.map +0 -1
- package/dist/test/dual-action-create.test.js +0 -187
- package/dist/test/dual-action-create.test.js.map +0 -1
- package/dist/test/dual-action-migration.test.d.ts +0 -2
- package/dist/test/dual-action-migration.test.d.ts.map +0 -1
- package/dist/test/dual-action-migration.test.js +0 -348
- package/dist/test/dual-action-migration.test.js.map +0 -1
- package/dist/test/graphql.test.d.ts +0 -2
- package/dist/test/graphql.test.d.ts.map +0 -1
- package/dist/test/graphql.test.js +0 -9
- package/dist/test/graphql.test.js.map +0 -1
- package/dist/test/internal-listener.test.d.ts +0 -2
- package/dist/test/internal-listener.test.d.ts.map +0 -1
- package/dist/test/internal-listener.test.js +0 -262
- package/dist/test/internal-listener.test.js.map +0 -1
- package/dist/test/path-encoding.test.d.ts +0 -2
- package/dist/test/path-encoding.test.d.ts.map +0 -1
- package/dist/test/path-encoding.test.js +0 -116
- package/dist/test/path-encoding.test.js.map +0 -1
- package/dist/test/queue.test.d.ts +0 -2
- package/dist/test/queue.test.d.ts.map +0 -1
- package/dist/test/queue.test.js +0 -325
- package/dist/test/queue.test.js.map +0 -1
- package/dist/test/reactor.test.d.ts +0 -2
- package/dist/test/reactor.test.d.ts.map +0 -1
- package/dist/test/reactor.test.js +0 -32
- package/dist/test/reactor.test.js.map +0 -1
- package/dist/test/read-mode.test.d.ts +0 -2
- package/dist/test/read-mode.test.d.ts.map +0 -1
- package/dist/test/read-mode.test.js +0 -569
- package/dist/test/read-mode.test.js.map +0 -1
- package/dist/test/server/driveOperationsConflictResolution.test.d.ts +0 -2
- package/dist/test/server/driveOperationsConflictResolution.test.d.ts.map +0 -1
- package/dist/test/server/driveOperationsConflictResolution.test.js +0 -486
- package/dist/test/server/driveOperationsConflictResolution.test.js.map +0 -1
- package/dist/test/server/mergeOperations.test.d.ts +0 -2
- package/dist/test/server/mergeOperations.test.d.ts.map +0 -1
- package/dist/test/server/mergeOperations.test.js +0 -131
- package/dist/test/server/mergeOperations.test.js.map +0 -1
- package/dist/test/server/processOperations.test.d.ts +0 -2
- package/dist/test/server/processOperations.test.d.ts.map +0 -1
- package/dist/test/server/processOperations.test.js +0 -392
- package/dist/test/server/processOperations.test.js.map +0 -1
- package/dist/test/server.test.d.ts +0 -2
- package/dist/test/server.test.d.ts.map +0 -1
- package/dist/test/server.test.js +0 -957
- package/dist/test/server.test.js.map +0 -1
- package/dist/test/signature-migration.test.d.ts +0 -2
- package/dist/test/signature-migration.test.d.ts.map +0 -1
- package/dist/test/signature-migration.test.js +0 -241
- package/dist/test/signature-migration.test.js.map +0 -1
- package/dist/test/storage.test.d.ts +0 -2
- package/dist/test/storage.test.d.ts.map +0 -1
- package/dist/test/storage.test.js +0 -457
- package/dist/test/storage.test.js.map +0 -1
- package/dist/test/switchboard-push-listener.test.d.ts +0 -2
- package/dist/test/switchboard-push-listener.test.d.ts.map +0 -1
- package/dist/test/switchboard-push-listener.test.js +0 -133
- package/dist/test/switchboard-push-listener.test.js.map +0 -1
- package/dist/test/sync-manager.test.d.ts +0 -2
- package/dist/test/sync-manager.test.d.ts.map +0 -1
- package/dist/test/sync-manager.test.js +0 -354
- package/dist/test/sync-manager.test.js.map +0 -1
- package/dist/test/undo-redo-clipboard.test.d.ts +0 -2
- package/dist/test/undo-redo-clipboard.test.d.ts.map +0 -1
- package/dist/test/undo-redo-clipboard.test.js +0 -108
- package/dist/test/undo-redo-clipboard.test.js.map +0 -1
- package/dist/test/utils.test.d.ts +0 -2
- package/dist/test/utils.test.d.ts.map +0 -1
- package/dist/test/utils.test.js +0 -86
- package/dist/test/utils.test.js.map +0 -1
- package/dist/test/vitest-setup.d.ts +0 -2
- package/dist/test/vitest-setup.d.ts.map +0 -1
- package/dist/test/vitest-setup.js +0 -5
- package/dist/test/vitest-setup.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/vitest.config.d.ts +0 -3
- package/dist/vitest.config.d.ts.map +0 -1
- package/dist/vitest.config.js +0 -28
- package/dist/vitest.config.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["BaseLRUCache","#getDocumentModelModule","#fetchDrive","#parseGraphQLErrors","#drives","#readModeStorage","#buildDrives","#notifyListeners","#listeners","#buildInternalOperationUpdate"],"sources":["../src/cache/lru.ts","../src/cache/util.ts","../src/cache/memory.ts","../src/cache/redis.ts","../src/queue/base.ts","../src/queue/utils.ts","../src/queue/event.ts","../src/read-mode/errors.ts","../src/utils/graphql.ts","../src/utils/default-drives-manager.ts","../src/utils/errors.ts","../src/utils/gql-transformations.ts","../src/utils/migrations.ts","../src/utils/misc.ts","../src/utils/run-asap.ts","../src/utils/test.ts","../src/read-mode/service.ts","../src/read-mode/server.ts","../src/server/error.ts","../src/server/listener/constants.ts","../src/server/transmitter/constants.ts","../src/server/transmitter/pull-responder.ts","../src/server/transmitter/switchboard-push.ts","../src/server/utils.ts","../src/server/base-server.ts","../src/storage/utils.ts","../src/storage/browser.ts","../src/storage/memory.ts","../src/storage/path-encoding.ts","../src/server/event-emitter.ts","../src/server/sync-unit-map.ts","../src/server/listener/util.ts","../src/server/listener/listener-manager.ts","../src/server/sync-manager.ts","../src/server/transmitter/factory.ts","../src/server/builder.ts","../src/server/transmitter/internal.ts","../src/processors/utils.ts","../src/processors/relational.ts","../src/processors/processor-manager.ts","../src/server/types.ts"],"sourcesContent":["import type { ICacheStorage, LRUCacheStorageOptions } from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport type { LRUCache } from \"lru-cache\";\nimport { LRUCache as BaseLRUCache } from \"lru-cache\";\nimport sizeof from \"object-sizeof\";\n\n/**\n * An implementation of a Least Recently Used (LRU) cache storage that evicts items\n * based on their total size in bytes. This cache storage is designed to work with\n * the InMemoryCache class to provide size-limited caching of documents and drives.\n *\n * When the cache reaches its maximum size limit, it automatically removes the least\n * recently accessed items to make space for new ones. The size of each cached item\n * is calculated using the provided sizeCalculation function (defaults to object-sizeof).\n *\n * @template Value - The type of values stored in the cache.\n */\n\nexport class LRUCacheStorage<Value extends {}> implements ICacheStorage {\n private cache: LRUCache<string, Value>;\n private logger = childLogger([\"cache\", \"LRUCache\"]);\n\n constructor(options: LRUCacheStorageOptions) {\n const { maxSize, sizeCalculation = sizeof } = options;\n this.cache = new BaseLRUCache<string, Value>({\n maxSize,\n sizeCalculation,\n });\n this.logger.info(\"Created LRUCache with maxSize: @maxSize bytes\", maxSize);\n }\n\n get(key: string) {\n return this.cache.get(key);\n }\n set(key: string, value: Value) {\n this.cache.set(key, value);\n return this;\n }\n delete(key: string) {\n return this.cache.delete(key);\n }\n clear(): void {\n return this.cache.clear();\n }\n}\n","import type {\n DocumentOperations,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\n\n// Deletes the resulting state on all operations in a document.\n// NOTE: THE RESULT IS THE CACHES MUTATE DOCUMENTS\nexport const trimResultingState = <TDocument extends PHDocument>(\n document: TDocument,\n): TDocument => {\n // Handle all scopes dynamically, not just global and local\n const trimmedOperations: DocumentOperations = {};\n\n for (const [scope, operations] of Object.entries(document.operations)) {\n if (operations) {\n trimmedOperations[scope] = operations.map((e) => {\n delete e.resultingState;\n return e;\n });\n }\n }\n\n return { ...document, operations: trimmedOperations };\n};\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n ICache,\n ICacheStorage,\n ICacheStorageManager,\n} from \"document-drive\";\nimport type { PHDocument } from \"@powerhousedao/shared/document-model\";\nimport { trimResultingState } from \"./util.js\";\n\nexport class CacheStorageManager implements ICacheStorageManager {\n private index = 0;\n private cache: ICacheStorage;\n\n constructor(cache: ICacheStorage) {\n this.cache = cache;\n }\n createStorage<Value>(): ICacheStorage<Value> {\n const index = this.index;\n this.index += 1;\n\n function buildKey(key: string) {\n return `${index}-${key}`;\n }\n\n const storage: ICacheStorage<Value> = {\n get: (key: string) => {\n return this.cache.get(buildKey(key)) as Value;\n },\n set: (key: string, value: Value): ICacheStorage<Value> => {\n this.cache.set(buildKey(key), value);\n return storage;\n },\n delete: (key) => {\n return this.cache.delete(buildKey(key));\n },\n clear: () => {\n this.cache.clear();\n },\n };\n return storage;\n }\n}\n\nexport class InMemoryCache implements ICache {\n private cacheStorageManager: ICacheStorageManager;\n private idToDocument: ICacheStorage<PHDocument>;\n private idToDrive: ICacheStorage<DocumentDriveDocument>;\n private slugToDriveId: ICacheStorage<string>;\n\n constructor(private cache: ICacheStorage = new Map<string, unknown>()) {\n this.cacheStorageManager = new CacheStorageManager(cache);\n this.idToDocument = this.cacheStorageManager.createStorage<PHDocument>();\n this.idToDrive =\n this.cacheStorageManager.createStorage<DocumentDriveDocument>();\n this.slugToDriveId = this.cacheStorageManager.createStorage<string>();\n }\n\n clear() {\n this.idToDocument.clear();\n this.idToDrive.clear();\n this.slugToDriveId.clear();\n }\n\n /////////////////////////////////////////////////////////////////////////////\n // ICache\n /////////////////////////////////////////////////////////////////////////////\n\n async setDocument(documentId: string, document: PHDocument) {\n const doc = trimResultingState(document);\n this.idToDocument.set(documentId, doc);\n }\n\n async getDocument<TDocument extends PHDocument>(\n documentId: string,\n ): Promise<TDocument | undefined> {\n return this.idToDocument.get(documentId) as TDocument | undefined;\n }\n\n async deleteDocument(documentId: string) {\n return this.idToDocument.delete(documentId);\n }\n\n async setDrive(driveId: string, drive: DocumentDriveDocument) {\n const doc = trimResultingState(drive);\n this.idToDrive.set(driveId, doc);\n }\n\n async getDrive(driveId: string): Promise<DocumentDriveDocument | undefined> {\n return this.idToDrive.get(driveId);\n }\n\n async deleteDrive(driveId: string) {\n // look up the slug\n const drive = this.idToDrive.get(driveId);\n if (!drive) {\n return false;\n }\n\n const slug = drive.header.slug.length > 0 ? drive.header.slug : driveId;\n if (slug) {\n this.slugToDriveId.delete(slug);\n }\n\n return this.idToDrive.delete(driveId);\n }\n\n async setDriveBySlug(slug: string, drive: DocumentDriveDocument) {\n const driveId = drive.header.id;\n this.slugToDriveId.set(slug, driveId);\n this.setDrive(driveId, drive);\n }\n\n async getDriveBySlug(\n slug: string,\n ): Promise<DocumentDriveDocument | undefined> {\n const driveId = this.slugToDriveId.get(slug);\n if (!driveId) {\n return undefined;\n }\n return this.getDrive(driveId);\n }\n\n async deleteDriveBySlug(slug: string) {\n const driveId = this.slugToDriveId.get(slug);\n if (!driveId) {\n return false;\n }\n\n this.slugToDriveId.delete(slug);\n return this.deleteDrive(driveId);\n }\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { PHDocument } from \"@powerhousedao/shared/document-model\";\nimport type { ICache } from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport type { RedisClientType } from \"redis\";\nimport { trimResultingState } from \"./util.js\";\n\nexport class RedisCache implements ICache {\n private logger = childLogger([\"RedisCache\"]);\n\n private redis: RedisClientType;\n private timeoutInSeconds: number;\n\n constructor(\n redis: RedisClientType,\n timeoutInSeconds: number | undefined = 5 * 60,\n ) {\n this.redis = redis;\n this.timeoutInSeconds = timeoutInSeconds;\n }\n\n private static _getDocumentKey(documentId: string) {\n return `cache:document:${documentId}`;\n }\n\n private static _getDriveKey(driveId: string) {\n return `cache:drive:${driveId}`;\n }\n\n private static _getDriveBySlugKey(slug: string) {\n return `cache:drive:slug:${slug}`;\n }\n\n /////////////////////////////////////////////////////////////////////////////\n // ICache\n /////////////////////////////////////////////////////////////////////////////\n\n async setDocument(documentId: string, document: PHDocument) {\n const doc = trimResultingState(document);\n const redisId = RedisCache._getDocumentKey(documentId);\n const result = await this.redis.set(redisId, JSON.stringify(doc), {\n EX: this.timeoutInSeconds ? this.timeoutInSeconds : undefined,\n });\n\n if (result !== \"OK\") {\n throw new Error(\n `Failed to set document ${documentId} in redis. Got '${result}'`,\n );\n }\n }\n\n async getDocument<TDocument extends PHDocument>(\n documentId: string,\n ): Promise<TDocument | undefined> {\n const redisId = RedisCache._getDocumentKey(documentId);\n const doc = await this.redis.get(redisId);\n\n return doc ? (JSON.parse(doc) as TDocument) : undefined;\n }\n\n async deleteDocument(documentId: string) {\n const redisId = RedisCache._getDocumentKey(documentId);\n return (await this.redis.del(redisId)) > 0;\n }\n\n async setDrive(driveId: string, drive: DocumentDriveDocument) {\n const doc = trimResultingState(drive);\n const redisId = RedisCache._getDriveKey(driveId);\n const result = await this.redis.set(redisId, JSON.stringify(doc), {\n EX: this.timeoutInSeconds ? this.timeoutInSeconds : undefined,\n });\n\n if (result !== \"OK\") {\n throw new Error(\n `Failed to set drive ${driveId} in redis. Got '${result}'`,\n );\n }\n }\n\n async getDrive(driveId: string): Promise<DocumentDriveDocument | undefined> {\n const redisId = RedisCache._getDriveKey(driveId);\n const doc = await this.redis.get(redisId);\n return doc ? (JSON.parse(doc) as DocumentDriveDocument) : undefined;\n }\n\n async deleteDrive(driveId: string) {\n const redisId = RedisCache._getDriveKey(driveId);\n const drive = await this.getDrive(driveId);\n if (!drive) {\n return false;\n }\n\n if (drive.header.slug.length > 0) {\n const slugRedisId = RedisCache._getDriveBySlugKey(drive.header.slug);\n await this.redis.del(slugRedisId);\n }\n\n return (await this.redis.del(redisId)) > 0;\n }\n\n // We store two pices: slug -> driveId, and driveId -> drive\n async setDriveBySlug(slug: string, drive: DocumentDriveDocument) {\n const driveId = drive.header.id;\n const redisId = RedisCache._getDriveBySlugKey(slug);\n const result = await this.redis.set(redisId, driveId, {\n EX: this.timeoutInSeconds ? this.timeoutInSeconds : undefined,\n });\n\n if (result !== \"OK\") {\n throw new Error(\n `Failed to set drive slug mapping for ${slug} -> ${driveId} in redis. Got '${result}'`,\n );\n }\n\n await this.setDrive(driveId, drive);\n }\n\n async getDriveBySlug(\n slug: string,\n ): Promise<DocumentDriveDocument | undefined> {\n const redisId = RedisCache._getDriveBySlugKey(slug);\n const driveId = await this.redis.get(redisId);\n return driveId ? await this.getDrive(driveId) : undefined;\n }\n\n async deleteDriveBySlug(slug: string) {\n const redisId = RedisCache._getDriveBySlugKey(slug);\n return (await this.redis.del(redisId)) > 0;\n }\n}\n","import type { IJob, IQueue, Job, JobId } from \"document-drive\";\n\nexport class MemoryQueue<T> implements IQueue<T> {\n private id: string;\n private running = false;\n private deleted = false;\n private items: IJob<T>[] = [];\n private dependencies = new Array<JobId>();\n\n constructor(id: string) {\n this.id = id;\n }\n async isRunning(): Promise<boolean> {\n return this.running;\n }\n async setRunning(running: boolean) {\n this.running = running;\n }\n\n async setDeleted(deleted: boolean) {\n this.deleted = deleted;\n }\n\n async isDeleted() {\n return this.deleted;\n }\n\n async addJob(data: IJob<T>) {\n this.items.push(data);\n return Promise.resolve();\n }\n\n async getNextJob() {\n const job = this.items.shift();\n return Promise.resolve(job);\n }\n\n async amountOfJobs() {\n return Promise.resolve(this.items.length);\n }\n\n getId() {\n return this.id;\n }\n\n async isBlocked() {\n return this.running || this.deleted || this.dependencies.length > 0;\n }\n\n async getJobs() {\n return this.items;\n }\n\n async addDependency(job: IJob<Job>) {\n if (!this.dependencies.includes(job.jobId)) {\n this.dependencies.push(job.jobId);\n }\n }\n\n async removeDependency(job: IJob<Job>) {\n const index = this.dependencies.indexOf(job.jobId);\n if (index > -1) {\n this.dependencies.splice(index, 1);\n }\n }\n}\n","import type { ActionJob, DocumentJob, Job, OperationJob } from \"document-drive\";\n\nexport function isDocumentJob(job: Job): job is DocumentJob {\n return \"documentType\" in job;\n}\n\nexport function isOperationJob(job: Job): job is OperationJob {\n return \"operations\" in job;\n}\n\nexport function isActionJob(job: Job): job is ActionJob {\n return \"actions\" in job;\n}\n","import { generateId } from \"@powerhousedao/shared/document-model\";\nimport type {\n IJob,\n IJobQueue,\n IOperationResult,\n IQueueManager,\n IServerDelegate,\n Job,\n JobId,\n QueueEvents,\n} from \"document-drive\";\nimport { childLogger, logger } from \"document-model\";\nimport type { Unsubscribe } from \"nanoevents\";\nimport { createNanoEvents } from \"nanoevents\";\nimport { MemoryQueue } from \"./base.js\";\nimport { isDocumentJob, isOperationJob } from \"./utils.js\";\n\ntype DocId = string;\n\ninterface EnqueuedJob {\n jobId: string;\n documentId: string;\n scope: string;\n timestampUtcMs: string;\n}\n\nexport class EventQueueManager implements IQueueManager {\n protected logger = childLogger([\"EventQueueManager\"]);\n protected emitter = createNanoEvents<QueueEvents>();\n protected queues = new Map<DocId, Map<string, IJobQueue>>();\n protected globalQueue = new Array<EnqueuedJob>();\n protected isFindingJob = false;\n protected maxWorkers: number;\n protected workers: number;\n protected runningJobs = new Array<IJob<Job>>();\n protected timeout: number;\n protected delegate: IServerDelegate | undefined;\n protected onError: ((error: Error) => void) | undefined;\n\n constructor(maxWorkers = 1, timeout = 0) {\n this.maxWorkers = maxWorkers;\n this.workers = 0;\n this.timeout = timeout;\n }\n\n async init(\n delegate: IServerDelegate,\n onError: (error: Error) => void,\n ): Promise<void> {\n this.delegate = delegate;\n this.onError = onError;\n\n function wrapErrorHandler<T extends (...args: any) => Promise<void> | void>(\n method: T,\n ): T {\n return (async (...args: any) => {\n try {\n await method(...args);\n } catch (error) {\n throw error instanceof Error\n ? error\n : new Error(JSON.stringify(error));\n }\n }) as T;\n }\n\n this.emitter.on(\n \"jobAdded\",\n wrapErrorHandler(async (job) => {\n this.logger.verbose(\"Added job: @job\", job);\n await this.processNextJob();\n }),\n );\n\n this.emitter.on(\n \"jobStarted\",\n wrapErrorHandler(async (job) => {\n this.logger.verbose(\"Started job: @jobId\", job.jobId);\n this.runningJobs.push(job);\n await this.processNextJob();\n }),\n );\n\n this.emitter.on(\n \"jobCompleted\",\n wrapErrorHandler(async (job, result) => {\n this.logger.verbose(\"Completed job: @jobId\", job.jobId);\n await this.handleJobCompleted(job, result);\n }),\n );\n\n this.emitter.on(\n \"jobFailed\",\n wrapErrorHandler(async (job, error) => {\n this.logger.error(\"Failed job: @job @error\", job, error);\n this.removeJob(job);\n onError(error);\n await this.processNextJob();\n }),\n );\n\n return Promise.resolve();\n }\n\n async addJob(job: Job): Promise<JobId> {\n if (!this.delegate) {\n throw new Error(\"No server delegate defined\");\n }\n\n const jobId = generateId();\n\n const documentJob = isDocumentJob(job);\n const jobActions = isDocumentJob(job)\n ? undefined\n : isOperationJob(job)\n ? job.operations\n : job.actions;\n\n if (!documentJob && !jobActions?.length) {\n throw new Error(\n \"Job has no operations or actions: \" + JSON.stringify(job),\n );\n }\n\n const firstItem = jobActions?.at(0);\n const scope = firstItem\n ? \"action\" in firstItem\n ? firstItem.action.scope\n : firstItem.scope\n : \"global\";\n if (\n jobActions?.find(\n (j) => (\"action\" in j ? j.action.scope : j.scope) !== scope,\n )\n ) {\n throw new Error(\"Job has actions with different scopes\");\n }\n const queue = this.getQueue(job.documentId, scope);\n\n // checks if the job is for a document:scope that has been deleted\n if (!isDocumentJob(job) && (await queue.isDeleted())) {\n throw new Error(\"Job has operations for deleted document\");\n }\n\n // TODO should create document job be a dependency of all jobs to the same document?\n\n const jobValue = Object.freeze({ jobId, ...job });\n await queue.addJob(jobValue);\n this.globalQueue.push({\n jobId,\n documentId: job.documentId,\n scope,\n timestampUtcMs: new Date().toUTCString(),\n });\n\n this.emit(\"jobAdded\", jobValue);\n return jobId;\n }\n\n getQueue(documentId: string, scope: string) {\n let docQueue = this.queues.get(documentId);\n if (!docQueue) {\n docQueue = new Map();\n this.queues.set(documentId, docQueue);\n }\n\n let scopeQueue = docQueue.get(scope);\n if (!scopeQueue) {\n scopeQueue = new MemoryQueue(scope);\n docQueue.set(scope, scopeQueue);\n }\n\n return scopeQueue;\n }\n\n getDocumentQueues(documentId: string) {\n return this.queues.get(documentId);\n }\n\n removeQueue(documentId: string, scope: string) {\n const docQueues = this.queues.get(documentId);\n const deleted = docQueues?.delete(scope);\n if (deleted) {\n this.emit(\"queueRemoved\", { documentId, scope });\n }\n return deleted;\n }\n\n removeDocumentQueues(documentId: string) {\n const docQueues = this.queues.get(documentId);\n docQueues?.keys().forEach((scope) => {\n this.removeQueue(documentId, scope);\n });\n }\n\n protected removeJob(job: IJob<Job>) {\n const indexRunning = this.runningJobs.findIndex(\n (j) => j.jobId === job.jobId,\n );\n if (indexRunning === -1) {\n this.logger.warn(\"Running job not found: @jobId\", job.jobId);\n }\n this.runningJobs.splice(indexRunning, 1);\n\n const indexGlobal = this.globalQueue.findIndex(\n (j) => j.jobId === job.jobId,\n );\n if (indexGlobal === -1) {\n this.logger.warn(\"Job not found on global queue: @jobId\", job.jobId);\n }\n this.globalQueue.splice(indexGlobal, 1);\n }\n\n protected async handleJobCompleted(job: IJob<Job>, result: IOperationResult) {\n this.removeJob(job);\n return this.processNextJob();\n }\n protected isBusy() {\n return this.workers >= this.maxWorkers;\n }\n\n protected async processNextJob() {\n // if there is already a worker looking for a job then waits for it to finish\n if (this.isFindingJob) {\n return;\n }\n\n if (!this.delegate) {\n throw new Error(\"No server delegate defined\");\n }\n\n // returns if there are no jobs available\n if (this.globalQueue.length === 0) {\n return;\n }\n\n // returns if there are no workers available\n if (this.isBusy()) {\n return;\n }\n\n this.isFindingJob = true;\n this.workers++;\n let queue: IJobQueue | undefined;\n let job: IJob<Job> | undefined;\n try {\n const queueJob = await this.findNextJob();\n queue = queueJob?.queue;\n job = queueJob?.job;\n } catch (error) {\n logger.error(\"Error finding next job: @error\", error);\n }\n if (!queue || !job) {\n this.workers--;\n this.isFindingJob = false;\n return;\n }\n\n try {\n await queue.setRunning(true);\n this.isFindingJob = false;\n this.emit(\"jobStarted\", job);\n const result = await this.delegate.processJob(job);\n this.workers--;\n await queue.setRunning(false);\n this.emit(\"jobCompleted\", job, result);\n } catch (error) {\n logger.error(\"Job failed: @error\", error);\n this.workers--;\n this.isFindingJob = false;\n await queue.setRunning(false);\n this.emit(\n \"jobFailed\",\n job,\n error instanceof Error ? error : new Error(JSON.stringify(error)),\n );\n }\n }\n\n protected async findNextJob(): Promise<\n { queue: IJobQueue; job: IJob<Job> } | undefined\n > {\n const skippedQueues = new Set<string>();\n for (const job of this.globalQueue) {\n const queue = this.getQueue(job.documentId, job.scope);\n const queueId = queue.getId();\n if (skippedQueues.has(queueId)) {\n continue;\n }\n if (await queue.isBlocked()) {\n skippedQueues.add(queue.getId());\n continue;\n }\n const queueJob = await queue.getNextJob();\n if (queueJob?.jobId !== job.jobId) {\n logger.warn(\"Queue has different job waiting to be picked up\"); // TODO ensure this is not possible\n logger.error(\"@job @queueJob\", job, queueJob);\n continue;\n }\n\n return { queue, job: queueJob };\n }\n }\n\n protected emit<K extends keyof QueueEvents>(\n event: K,\n ...args: Parameters<QueueEvents[K]>\n ) {\n this.emitter.emit(event, ...args);\n }\n\n public on<K extends keyof QueueEvents>(\n event: K,\n cb: QueueEvents[K],\n ): Unsubscribe {\n return this.emitter.on(event, cb);\n }\n}\n","export abstract class ReadDriveError extends Error {}\n\nexport class ReadDriveNotFoundError extends ReadDriveError {\n constructor(driveId: string) {\n super(`Read drive ${driveId} not found.`);\n }\n}\n\nexport class ReadDriveSlugNotFoundError extends ReadDriveError {\n constructor(slug: string) {\n super(`Read drive with slug ${slug} not found.`);\n }\n}\n\nexport class ReadDocumentNotFoundError extends ReadDriveError {\n constructor(drive: string, id: string) {\n super(`Document with id ${id} not found on read drive ${drive}.`);\n }\n}\n","import type {\n DocumentModelGlobalState,\n DocumentModelModule,\n PHBaseState,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport { pascalCase } from \"change-case\";\nimport type {\n DocumentGraphQLResult,\n DriveInfo,\n GraphQLResult,\n IBaseDocumentDriveServer,\n} from \"document-drive\";\nimport { logger } from \"document-model\";\nimport type {\n BuildSchemaOptions,\n GraphQLOutputType,\n ParseOptions,\n} from \"graphql\";\nimport {\n GraphQLError,\n GraphQLList,\n GraphQLNonNull,\n GraphQLObjectType,\n GraphQLScalarType,\n GraphQLUnionType,\n buildSchema,\n} from \"graphql\";\nimport { GraphQLClient, gql } from \"graphql-request\";\n\nexport { gql } from \"graphql-request\";\n\ntype ReqGraphQLError = {\n message: string;\n};\n\n// replaces fetch so it can be used in Node and Browser envs\nexport async function requestGraphql<T>(\n url: string,\n document: string,\n variables?: Record<string, unknown>,\n headers?: Record<string, string>,\n): Promise<GraphQLResult<T>> {\n const client = new GraphQLClient(url, {\n fetch,\n headers: headers || {},\n });\n const { errors, ...response } = await client.request<\n { [K in keyof T]: T[K] | null } & { errors?: ReqGraphQLError[] }\n >(document, variables);\n\n const result = { ...response } as GraphQLResult<T>;\n if (errors?.length) {\n result.errors = errors.map(\n ({ message, ...options }) => new GraphQLError(message, options),\n );\n }\n return result;\n}\n\nfunction getFields(type: GraphQLOutputType, prefix: string): string {\n if (type instanceof GraphQLObjectType) {\n return Object.entries(type.getFields())\n .map(([fieldName, field]) => {\n const fieldType =\n field.type instanceof GraphQLNonNull ? field.type.ofType : field.type;\n\n if (\n fieldType instanceof GraphQLObjectType ||\n fieldType instanceof GraphQLUnionType\n ) {\n return `${fieldName} { ${getFields(fieldType, prefix)} }`;\n }\n\n if (fieldType instanceof GraphQLList) {\n const listItemType =\n fieldType.ofType instanceof GraphQLNonNull\n ? fieldType.ofType.ofType\n : fieldType.ofType;\n\n if (listItemType instanceof GraphQLScalarType) {\n return fieldName;\n } else if (\n listItemType instanceof GraphQLObjectType ||\n listItemType instanceof GraphQLUnionType\n ) {\n return `${fieldName} { ${getFields(listItemType, prefix)} }`;\n } else {\n throw new Error(\n `List item type ${listItemType.toString()} is not handled`,\n );\n }\n }\n\n return fieldName;\n })\n .join(\" \");\n } else if (type instanceof GraphQLUnionType) {\n return type\n .getTypes()\n .map((unionType) => {\n return `... on ${prefix ? `${prefix}_` : \"\"}${unionType.name} { ${getFields(unionType, prefix)} }`;\n })\n .join(\" \");\n }\n return \"\";\n}\n\nexport function generateDocumentStateQueryFields(\n documentModelState: DocumentModelGlobalState,\n prefix: string,\n options?: BuildSchemaOptions & ParseOptions,\n): string {\n const name = pascalCase(documentModelState.name);\n const spec = documentModelState.specifications.at(-1);\n if (!spec) {\n throw new Error(\"No document model specification found\");\n }\n const source = `${spec.state.global.schema} type Query { ${name}: ${name}State }`;\n const schema = buildSchema(source, options);\n const queryType = schema.getQueryType();\n if (!queryType) {\n throw new Error(\"No query type found\");\n }\n const fields = queryType.getFields();\n const stateQuery = fields[name];\n\n if (!stateQuery) {\n throw new Error(\"No state query found\");\n }\n\n const queryFields = getFields(stateQuery.type, prefix);\n return queryFields;\n}\n\nexport async function requestPublicDriveWithTokenFromReactor(\n url: string,\n server: IBaseDocumentDriveServer,\n): Promise<DriveInfo> {\n const token = await server.generateJwtHandler?.(url);\n const headers: Record<string, string> = token\n ? { Authorization: `Bearer ${token}` }\n : {};\n return requestPublicDrive(url, headers);\n}\n\nexport async function requestPublicDrive(\n url: string,\n headers?: Record<string, string>,\n): Promise<DriveInfo> {\n let drive: DriveInfo;\n try {\n const result = await requestGraphql<{ drive: DriveInfo }>(\n url,\n gql`\n query getDrive {\n drive {\n id\n name\n icon\n slug\n meta {\n preferredEditor\n }\n }\n }\n `,\n undefined,\n headers,\n );\n if (result.errors?.length || !result.drive) {\n throw result.errors?.at(0) ?? new Error(\"Drive not found\");\n }\n drive = result.drive;\n } catch (e) {\n logger.error(\"@error\", e);\n throw new Error(\"Couldn't find drive info\");\n }\n\n return drive;\n}\n\nexport async function requestPublicDriveFromReactor(\n url: string,\n headers?: Record<string, string>,\n): Promise<DriveInfo> {\n try {\n const response = await fetch(url, { headers: headers ?? {} });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n return (await response.json()) as DriveInfo;\n } catch (e) {\n logger.error(\"@error\", e);\n throw new Error(\"Couldn't find drive info\");\n }\n}\n\nexport async function fetchDocument<TState extends PHBaseState = PHBaseState>(\n url: string,\n documentId: string,\n documentModelModule: DocumentModelModule<TState>,\n): Promise<\n GraphQLResult<{\n document: DocumentGraphQLResult<TState>;\n }>\n> {\n const { documentModel } = documentModelModule;\n const name = pascalCase(documentModel.global.name);\n const stateFields = generateDocumentStateQueryFields(\n documentModel.global,\n name,\n );\n const result = await requestGraphql<{\n document: DocumentGraphQLResult<TState>;\n }>(\n url,\n gql`\n query ($id: String!) {\n document(id: $id) {\n id\n name\n created\n documentType\n lastModified\n revision\n operations {\n id\n error\n hash\n index\n skip\n timestamp\n type\n inputText\n context {\n signer {\n user {\n address\n networkId\n chainId\n }\n app {\n name\n key\n }\n signatures\n }\n }\n }\n ... on ${name} {\n state {\n ${stateFields}\n }\n initialState {\n ${stateFields}\n }\n }\n }\n }\n `,\n { id: documentId },\n );\n\n if (!result.document) {\n return { ...result, document: null };\n }\n\n const document: DocumentGraphQLResult<TState> = {\n clipboard: result.document.clipboard,\n header: result.document.header,\n initialState: result.document.initialState,\n /** @ts-expect-error TODO: fix this */\n operations: {\n /** @ts-expect-error TODO: fix this */\n global: result.document.operations.map(({ inputText, ...o }) => ({\n ...o,\n error: o.error ?? undefined,\n scope: \"global\",\n input: JSON.parse(inputText) as PHDocument<TState>,\n })),\n local: [],\n },\n state: result.document.state,\n };\n\n return {\n ...result,\n document,\n } as GraphQLResult<{\n document: DocumentGraphQLResult<TState>;\n }>;\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n DefaultRemoteDriveInfo,\n DocumentDriveServerOptions,\n IBaseDocumentDriveServer,\n IDefaultDrivesManager,\n IReadModeDriveServer,\n IServerDelegateDrivesManager,\n RemoteDriveAccessLevel,\n RemoveDriveStrategy,\n RemoveOldRemoteDrivesOption,\n} from \"document-drive\";\nimport { logger } from \"document-model\";\nimport { requestPublicDriveWithTokenFromReactor } from \"../utils/graphql.js\";\n\nfunction isReadModeDriveServer(obj: unknown): obj is IReadModeDriveServer {\n return typeof (obj as IReadModeDriveServer).getReadDrives === \"function\";\n}\n\nexport class DefaultDrivesManager implements IDefaultDrivesManager {\n private defaultRemoteDrives = new Map<string, DefaultRemoteDriveInfo>();\n private removeOldRemoteDrivesConfig: RemoveOldRemoteDrivesOption;\n\n constructor(\n private server:\n | IBaseDocumentDriveServer\n | (IBaseDocumentDriveServer & IReadModeDriveServer),\n private delegate: IServerDelegateDrivesManager,\n options?: Pick<DocumentDriveServerOptions, \"defaultDrives\">,\n ) {\n if (options?.defaultDrives?.remoteDrives) {\n for (const defaultDrive of options.defaultDrives.remoteDrives) {\n this.defaultRemoteDrives.set(defaultDrive.url, {\n ...defaultDrive,\n status: \"PENDING\",\n });\n }\n }\n\n this.removeOldRemoteDrivesConfig = options?.defaultDrives\n ?.removeOldRemoteDrives || {\n strategy: \"preserve-all\",\n };\n }\n\n getDefaultRemoteDrives() {\n return new Map(\n JSON.parse(\n JSON.stringify(Array.from(this.defaultRemoteDrives)),\n ) as Iterable<[string, DefaultRemoteDriveInfo]>,\n );\n }\n\n private async deleteDriveById(driveId: string) {\n try {\n await this.server.deleteDrive(driveId);\n } catch (error) {\n logger.error(\"@error\", error);\n }\n }\n\n private async preserveDrivesById(\n driveIdsToPreserve: string[],\n drives: string[],\n removeStrategy: RemoveDriveStrategy = \"detach\",\n ) {\n const getAllDrives = drives.map((driveId) => this.server.getDrive(driveId));\n\n const drivesToRemove = (await Promise.all(getAllDrives))\n .filter(\n (drive: DocumentDriveDocument) =>\n drive.state.local.listeners.length > 0 ||\n drive.state.local.triggers.length > 0,\n )\n .filter(\n (drive: DocumentDriveDocument) =>\n !driveIdsToPreserve.includes(drive.header.id),\n );\n\n const driveIds = drivesToRemove.map(\n (drive: DocumentDriveDocument) => drive.header.id,\n );\n\n if (removeStrategy === \"detach\") {\n await this.detachDrivesById(driveIds);\n } else {\n await this.removeDrivesById(driveIds);\n }\n }\n\n private async removeDrivesById(driveIds: string[]) {\n for (const driveId of driveIds) {\n await this.deleteDriveById(driveId);\n }\n }\n\n private async detachDrivesById(driveIds: string[]) {\n const detachDrivesPromises = driveIds.map((driveId) =>\n this.delegate.detachDrive(driveId),\n );\n\n await Promise.all(detachDrivesPromises);\n }\n\n async removeOldremoteDrives() {\n const driveids = await this.server.getDrives();\n\n switch (this.removeOldRemoteDrivesConfig.strategy) {\n case \"preserve-by-id-and-detach\":\n case \"preserve-by-id\": {\n const detach: RemoveDriveStrategy =\n this.removeOldRemoteDrivesConfig.strategy ===\n \"preserve-by-id-and-detach\"\n ? \"detach\"\n : \"remove\";\n\n await this.preserveDrivesById(\n this.removeOldRemoteDrivesConfig.ids,\n driveids,\n detach,\n );\n break;\n }\n case \"preserve-by-url-and-detach\":\n case \"preserve-by-url\": {\n const detach: RemoveDriveStrategy =\n this.removeOldRemoteDrivesConfig.strategy ===\n \"preserve-by-url-and-detach\"\n ? \"detach\"\n : \"remove\";\n const getDrivesInfo = this.removeOldRemoteDrivesConfig.urls.map((url) =>\n requestPublicDriveWithTokenFromReactor(url, this.server),\n );\n\n const drivesIdsToPreserve = (await Promise.all(getDrivesInfo)).map(\n (driveInfo) => driveInfo.id,\n );\n\n await this.preserveDrivesById(drivesIdsToPreserve, driveids, detach);\n break;\n }\n case \"remove-by-id\": {\n const drivesIdsToRemove = this.removeOldRemoteDrivesConfig.ids.filter(\n (driveId) => driveids.includes(driveId),\n );\n\n await this.removeDrivesById(drivesIdsToRemove);\n break;\n }\n case \"remove-by-url\": {\n const getDrivesInfo = this.removeOldRemoteDrivesConfig.urls.map(\n (driveUrl) =>\n requestPublicDriveWithTokenFromReactor(driveUrl, this.server),\n );\n const drivesInfo = await Promise.all(getDrivesInfo);\n\n const drivesIdsToRemove = drivesInfo\n .map((driveInfo) => driveInfo.id)\n .filter((driveId) => driveids.includes(driveId));\n\n await this.removeDrivesById(drivesIdsToRemove);\n break;\n }\n case \"remove-all\": {\n const getDrives = driveids.map((driveId) =>\n this.server.getDrive(driveId),\n );\n const drives = await Promise.all(getDrives);\n const drivesToRemove = drives\n .filter(\n (drive: DocumentDriveDocument) =>\n drive.state.local.listeners.length > 0 ||\n drive.state.local.triggers.length > 0,\n )\n .map((drive: DocumentDriveDocument) => drive.header.id);\n\n await this.removeDrivesById(drivesToRemove);\n break;\n }\n case \"detach-by-id\": {\n const drivesIdsToRemove = this.removeOldRemoteDrivesConfig.ids.filter(\n (driveId) => driveids.includes(driveId),\n );\n const detachDrivesPromises = drivesIdsToRemove.map((driveId) =>\n this.delegate.detachDrive(driveId),\n );\n\n await Promise.all(detachDrivesPromises);\n break;\n }\n case \"detach-by-url\": {\n const getDrivesInfo = this.removeOldRemoteDrivesConfig.urls.map(\n (driveUrl) =>\n requestPublicDriveWithTokenFromReactor(driveUrl, this.server),\n );\n const drivesInfo = await Promise.all(getDrivesInfo);\n\n const drivesIdsToRemove = drivesInfo\n .map((driveInfo) => driveInfo.id)\n .filter((driveId) => driveids.includes(driveId));\n\n const detachDrivesPromises = drivesIdsToRemove.map((driveId) =>\n this.delegate.detachDrive(driveId),\n );\n\n await Promise.all(detachDrivesPromises);\n break;\n }\n }\n }\n\n async setAllDefaultDrivesAccessLevel(level: RemoteDriveAccessLevel) {\n const drives = this.defaultRemoteDrives.values();\n for (const drive of drives) {\n await this.setDefaultDriveAccessLevel(drive.url, level);\n }\n }\n\n async setDefaultDriveAccessLevel(url: string, level: RemoteDriveAccessLevel) {\n const drive = this.defaultRemoteDrives.get(url);\n if (drive && drive.options.accessLevel !== level) {\n const newDriveValue = {\n ...drive,\n options: { ...drive.options, accessLevel: level },\n };\n this.defaultRemoteDrives.set(url, newDriveValue);\n await this.initializeDefaultRemoteDrives([newDriveValue]);\n }\n }\n\n async initializeDefaultRemoteDrives(\n defaultDrives: DefaultRemoteDriveInfo[] = Array.from(\n this.defaultRemoteDrives.values(),\n ),\n ) {\n const drives = await this.server.getDrives();\n const readServer = isReadModeDriveServer(this.server)\n ? this.server\n : undefined;\n const readDrives = await readServer?.getReadDrives();\n\n for (const remoteDrive of defaultDrives) {\n let remoteDriveInfo = { ...remoteDrive };\n\n try {\n const driveInfo =\n remoteDrive.metadata ??\n (await requestPublicDriveWithTokenFromReactor(\n remoteDrive.url,\n this.server,\n ));\n\n remoteDriveInfo = { ...remoteDrive, metadata: driveInfo };\n\n this.defaultRemoteDrives.set(remoteDrive.url, remoteDriveInfo);\n\n const driveIsAdded = drives.includes(driveInfo.id);\n const readDriveIsAdded = readDrives?.includes(driveInfo.id);\n\n const hasAccessLevel = remoteDrive.options.accessLevel !== undefined;\n const readMode =\n readServer && remoteDrive.options.accessLevel === \"READ\";\n const isAdded = readMode ? readDriveIsAdded : driveIsAdded;\n\n // if the read mode has changed then existing drives\n // in the previous mode should be deleted\n const driveToDelete =\n hasAccessLevel && (readMode ? driveIsAdded : readDriveIsAdded);\n if (driveToDelete) {\n try {\n await (readMode\n ? this.server.deleteDrive(driveInfo.id)\n : readServer?.deleteReadDrive(driveInfo.id));\n } catch (e) {\n logger.error(\"@error\", e);\n }\n }\n\n if (isAdded) {\n remoteDriveInfo.status = \"ALREADY_ADDED\";\n\n this.defaultRemoteDrives.set(remoteDrive.url, remoteDriveInfo);\n this.delegate.emit(\n \"ALREADY_ADDED\",\n this.defaultRemoteDrives,\n remoteDriveInfo,\n driveInfo.id,\n driveInfo.name,\n );\n continue;\n }\n\n remoteDriveInfo.status = \"ADDING\";\n\n this.defaultRemoteDrives.set(remoteDrive.url, remoteDriveInfo);\n this.delegate.emit(\"ADDING\", this.defaultRemoteDrives, remoteDriveInfo);\n\n if (\n (remoteDrive.options.accessLevel === \"READ\" && readServer) ||\n readMode\n ) {\n await readServer.addReadDrive(remoteDrive.url, {\n ...remoteDrive.options,\n expectedDriveInfo: driveInfo,\n });\n } else {\n await this.server.addRemoteDrive(remoteDrive.url, {\n ...remoteDrive.options,\n expectedDriveInfo: driveInfo,\n });\n }\n\n remoteDriveInfo.status = \"SUCCESS\";\n\n this.defaultRemoteDrives.set(remoteDrive.url, remoteDriveInfo);\n this.delegate.emit(\n \"SUCCESS\",\n this.defaultRemoteDrives,\n remoteDriveInfo,\n driveInfo.id,\n driveInfo.name,\n );\n } catch (error) {\n remoteDriveInfo.status = \"ERROR\";\n\n this.defaultRemoteDrives.set(remoteDrive.url, remoteDriveInfo);\n this.delegate.emit(\n \"ERROR\",\n this.defaultRemoteDrives,\n remoteDriveInfo,\n undefined,\n undefined,\n error as Error,\n );\n }\n }\n }\n}\n","export class AbortError extends Error {\n constructor(message?: string) {\n super(message || \"Aborted\");\n\n this.name = \"AbortError\";\n }\n}\n\nexport const isAbortError = (error: unknown): boolean => {\n return error instanceof AbortError;\n};\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n Operation,\n PHDocument,\n PHDocumentHeader,\n} from \"@powerhousedao/shared/document-model\";\n\ntype ResponseForDrive = {\n id: string;\n slug: string;\n meta: Record<string, unknown> | undefined;\n name: string;\n icon: string | undefined;\n graphqlEndpoint?: string;\n};\nexport function responseForDrive(\n drive: DocumentDriveDocument,\n graphqlEndpoint?: string,\n) {\n const response: ResponseForDrive = {\n id: drive.header.id,\n slug: drive.header.slug,\n meta: drive.header.meta,\n name: drive.state.global.name,\n icon: drive.state.global.icon ?? undefined,\n ...(graphqlEndpoint && { graphqlEndpoint }),\n };\n return response;\n}\n\nexport type PHDocumentGQL = Omit<PHDocumentHeader, \"revision\"> & {\n id: string;\n revision: number;\n /**\n * @deprecated Use createdAtUtcIso instead\n */\n createdAt: string;\n /**\n * @deprecated Use lastModifiedAtUtcIso instead\n */\n lastModified: string;\n __typename: string;\n state: unknown;\n initialState: unknown;\n stateJSON: unknown;\n operations: Operation[];\n nodeName?: string;\n};\n\nexport function responseForDocument(\n document: PHDocument,\n typeName: string,\n nodeName?: string,\n): PHDocumentGQL {\n const name = nodeName ?? document.header.name ?? \"\";\n\n return {\n ...document.header,\n ...document,\n id: document.header.id,\n createdAt: document.header.createdAtUtcIso,\n lastModified: document.header.lastModifiedAtUtcIso,\n documentType: document.header.documentType,\n name: name,\n revision: document.header.revision.global || 0,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n state: (document.state as any).global,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n stateJSON: (document.state as any).global,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n operations: (document.operations as any).global.map((op: Operation) => ({\n ...op,\n inputText:\n typeof op.action.input === \"string\"\n ? op.action.input\n : JSON.stringify(op.action.input),\n })),\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n initialState: (document.initialState as any).global,\n __typename: typeName,\n };\n}\n","import type {\n DocumentOperations,\n Operation,\n PHDocument,\n Signature,\n} from \"@powerhousedao/shared/document-model\";\n\nexport function migrateDocumentOperationSignatures(\n document: PHDocument,\n): PHDocument | undefined {\n let legacy = false;\n const operations = Object.entries(\n document.operations,\n ).reduce<DocumentOperations>(\n (acc, [key, operations]) => {\n const scope = key;\n if (!operations) {\n return acc;\n }\n for (const op of operations) {\n const newOp = migrateLegacyOperationSignature(op);\n const scopeOps = acc[scope];\n if (scopeOps) {\n scopeOps.push(newOp);\n }\n if (newOp !== op) {\n legacy = true;\n }\n }\n return acc;\n },\n { global: [], local: [] },\n );\n return legacy ? { ...document, operations } : document;\n}\n\nexport function migrateLegacyOperationSignature<TGlobalState, TLocalState>(\n operation: Operation,\n): Operation {\n let needsMigration = false;\n let newOperation = { ...operation };\n\n // Check both top-level context and action.context for legacy signatures\n const topLevelSigner = (operation as any).context?.signer;\n const actionSigner = operation.action?.context?.signer;\n\n // Handle top-level context migration (legacy structure)\n if (topLevelSigner) {\n if (\"signature\" in topLevelSigner) {\n const signature = topLevelSigner.signature as string | undefined;\n (newOperation as any) = {\n ...newOperation,\n context: {\n ...(newOperation as any).context,\n signer: {\n user: topLevelSigner.user,\n app: topLevelSigner.app,\n signatures: (signature?.length\n ? [signature]\n : []) as unknown as Signature[],\n },\n },\n };\n needsMigration = true;\n } else if (topLevelSigner.signatures) {\n const cleanSignatures = topLevelSigner.signatures.filter(\n (sig: any) => sig && sig.length > 0,\n );\n if (cleanSignatures.length !== topLevelSigner.signatures.length) {\n (newOperation as any) = {\n ...newOperation,\n context: {\n ...(newOperation as any).context,\n signer: {\n ...topLevelSigner,\n signatures: cleanSignatures as unknown as Signature[],\n },\n },\n };\n needsMigration = true;\n }\n }\n }\n\n // Handle action.context migration\n if (actionSigner) {\n if (\"signature\" in actionSigner) {\n const signature = actionSigner.signature as string | undefined;\n const migratedContext = {\n ...newOperation.action!.context,\n signer: {\n user: actionSigner.user,\n app: actionSigner.app,\n signatures: (signature?.length\n ? [signature]\n : []) as unknown as Signature[],\n },\n };\n (newOperation as any) = {\n ...newOperation,\n action: {\n ...newOperation.action!,\n context: migratedContext,\n },\n context: migratedContext, // Also set top-level context\n };\n needsMigration = true;\n } else if (actionSigner.signatures) {\n const cleanSignatures = actionSigner.signatures.filter(\n (sig: any) => sig && sig.length > 0,\n );\n if (cleanSignatures.length !== actionSigner.signatures.length) {\n const migratedContext = {\n ...newOperation.action!.context,\n signer: {\n ...actionSigner,\n signatures: cleanSignatures as unknown as Signature[],\n },\n };\n (newOperation as any) = {\n ...newOperation,\n action: {\n ...newOperation.action!,\n context: migratedContext,\n },\n context: migratedContext, // Also set top-level context\n };\n needsMigration = true;\n }\n }\n }\n\n return needsMigration ? newOperation : operation;\n}\n","import {\n driveDocumentType,\n type DocumentDriveDocument,\n} from \"@powerhousedao/shared/document-drive\";\nimport { pascalCase } from \"change-case\";\nimport type { ListenerRevision } from \"document-drive\";\nimport type {\n DocumentOperations,\n Operation,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport { OperationError } from \"server\";\n\nexport function isDocumentDrive(\n document: PHDocument,\n): document is DocumentDriveDocument {\n return document.header.documentType === driveDocumentType;\n}\n\nexport function mergeOperations(\n currentOperations: DocumentOperations,\n newOperations: Operation[],\n): DocumentOperations {\n const minIndexByScope = Object.keys(currentOperations).reduce<\n Partial<Record<string, number>>\n >((acc, curr) => {\n const scope = curr;\n const scopeOps = currentOperations[scope];\n acc[scope] = scopeOps?.at(-1)?.index ?? 0;\n return acc;\n }, {});\n\n const conflictOp = newOperations.find(\n (op) => op.index < (minIndexByScope[op.action.scope] ?? 0),\n );\n if (conflictOp) {\n throw new OperationError(\n \"ERROR\",\n conflictOp,\n `Tried to add operation with index ${conflictOp.index} and document is at index ${minIndexByScope[conflictOp.action.scope]}`,\n );\n }\n\n return newOperations\n .sort((a, b) => a.index - b.index)\n .reduce<DocumentOperations>((acc, curr) => {\n const existingOperations = acc[curr.action.scope] || [];\n return { ...acc, [curr.action.scope]: [...existingOperations, curr] };\n }, currentOperations);\n}\n\nexport function isNoopUpdate(\n operation: Operation,\n latestOperation?: Operation,\n) {\n if (!latestOperation) {\n return false;\n }\n\n const isNoopOp = operation.action.type === \"NOOP\";\n const isNoopLatestOp = latestOperation.action.type === \"NOOP\";\n const isSameIndexOp = operation.index === latestOperation.index;\n const isSkipOpGreaterThanLatestOp = operation.skip > latestOperation.skip;\n\n return (\n isNoopOp && isNoopLatestOp && isSameIndexOp && isSkipOpGreaterThanLatestOp\n );\n}\n\n// return true if dateA is before dateB\nexport function isBefore(dateA: Date | string, dateB: Date | string) {\n return new Date(dateA) < new Date(dateB);\n}\n\nexport function operationsToRevision(\n operations: Pick<Operation, \"index\">[] | undefined,\n): ListenerRevision[\"revision\"] {\n const lastOperation = operations?.at(-1);\n return lastOperation ? lastOperation.index + 1 : 0;\n}\n\n/**\n * Converts a string to PascalCase\n * @param {string} str - The input string to convert\n * @returns {string} The string in PascalCase format\n *\n * Examples:\n * \"hello world\" -> \"HelloWorld\"\n * \"hello-world\" -> \"HelloWorld\"\n * \"hello_world\" -> \"HelloWorld\"\n * \"helloWorld\" -> \"HelloWorld\"\n */\nexport const toPascalCase = pascalCase;\n","import type { AbortTask, RunAsap, Task } from \"document-drive\";\n\nexport const useMessageChannel = (() => {\n if (typeof MessageChannel === \"undefined\") {\n return new Error(\"MessageChannel is not supported\");\n }\n\n return (task: Task) => {\n const controller = new AbortController();\n const signal = controller.signal;\n const mc = new MessageChannel();\n mc.port1.postMessage(null);\n mc.port2.addEventListener(\n \"message\",\n () => {\n task();\n mc.port1.close();\n mc.port2.close();\n },\n { once: true, signal: signal },\n );\n mc.port2.start();\n return () => controller.abort();\n };\n})();\n\nexport const usePostMessage = (() => {\n const _main: unknown =\n (typeof window === \"object\" && window) ||\n (typeof global === \"object\" && global) ||\n (typeof self === \"object\" && self);\n if (!_main) {\n return new Error(\"No global object found\");\n }\n\n const main = _main as Window;\n if (\n !main.postMessage ||\n !main.addEventListener ||\n (main as { importScripts?: unknown }).importScripts // web workers can't this method\n ) {\n return new Error(\"postMessage is not supported\");\n }\n\n let index = 0;\n const tasks = new Map<number, Task>();\n\n function getNewIndex() {\n if (index === 9007199254740991) {\n return 0;\n }\n return ++index;\n }\n\n const MESSAGE_PREFIX = \"com.usePostMessage\" + Math.random();\n\n main.addEventListener(\n \"message\",\n (e) => {\n const event = e as MessageEvent<string>;\n if (typeof event.data !== \"string\") {\n return;\n }\n if (event.source !== main || !event.data.startsWith(MESSAGE_PREFIX)) {\n return;\n }\n const index = event.data.split(\":\").at(1);\n if (index === undefined) {\n return;\n }\n const i = +index;\n const task = tasks.get(i);\n if (task) {\n task();\n tasks.delete(i);\n }\n },\n false,\n );\n\n return (task: Task) => {\n const i = getNewIndex();\n tasks.set(i, task);\n main.postMessage(MESSAGE_PREFIX + \":\" + i, { targetOrigin: \"*\" });\n return () => {\n tasks.delete(i);\n };\n };\n})();\n\nexport const useSetImmediate = (() => {\n if (typeof window !== \"undefined\") {\n return new Error(\"setImmediate is not supported on the browser\");\n }\n if (typeof setImmediate === \"undefined\") {\n return new Error(\"setImmediate is not supported\");\n }\n\n return (task: Task) => {\n const id = setImmediate(task);\n return () => clearImmediate(id);\n };\n})();\n\nexport const useSetTimeout = (() => {\n return (task: Task) => {\n const id = setTimeout(task, 0);\n return () => clearTimeout(id);\n };\n})();\n\n// queues the task in the macro tasks queue, so it doesn't\n// prevent the event loop from movin on the next tick\nexport function runAsap<T = void>(task: Task<T>): AbortTask {\n // if on node use setImmediate\n if (!(useSetImmediate instanceof Error)) {\n return useSetImmediate(task);\n }\n // on browser use MessageChannel if available\n else if (!(useMessageChannel instanceof Error)) {\n return useMessageChannel(task);\n }\n // otherwise use window.postMessage\n else if (!(usePostMessage instanceof Error)) {\n return usePostMessage(task);\n }\n // fallback to setTimeout with 0 delay\n else {\n return useSetTimeout(task);\n }\n}\n\nexport function runAsapAsync<T = void>(\n task: Task<Promise<T>>,\n queueMethod: RunAsap<void> = runAsap,\n): Promise<T> {\n if (queueMethod instanceof Error) {\n throw new Error(\"queueMethod is not supported\", {\n cause: queueMethod,\n });\n }\n return new Promise((resolve, reject) => {\n queueMethod(() => {\n task().then(resolve).catch(reject);\n });\n });\n}\n","import { driveDocumentModelModule } from \"@powerhousedao/shared/document-drive\";\nimport {\n generateId,\n type Action,\n type DocumentModelModule,\n type Operation,\n type PHBaseState,\n type PHDocument,\n type Reducer,\n} from \"@powerhousedao/shared/document-model\";\nimport type {\n BaseDocumentDriveServer,\n IDocumentDriveServer,\n} from \"document-drive\";\nimport { documentModelDocumentModelModule } from \"document-model\";\nimport type { ExpectStatic } from \"vitest\";\n\nexport const baseDocumentModels = [\n driveDocumentModelModule,\n documentModelDocumentModelModule,\n] as DocumentModelModule<any>[];\n\nexport function expectUUID(expect: ExpectStatic): unknown {\n return expect.stringMatching(\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n );\n}\n\nexport function expectOperationId(expect: ExpectStatic): unknown {\n return expect.stringMatching(/^[0-9a-f]{32}$/);\n}\n\nexport function expectUTCTimestamp(expect: ExpectStatic): unknown {\n return expect.stringMatching(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{3}Z$/i);\n}\n\nexport function buildOperation<TDocument extends PHDocument>(\n reducer: Reducer<any>,\n document: TDocument,\n action: Action,\n index?: number,\n): Operation {\n const newDocument = reducer(document, action);\n\n const operation = newDocument.operations[action.scope]!.slice().pop()!;\n\n return { ...operation, index: index ?? operation.index } as Operation;\n}\n\nexport function buildOperations<TDocument extends PHDocument>(\n reducer: Reducer<any>,\n document: TDocument,\n actions: Array<Action>,\n): Operation[] {\n const operations: Operation[] = [];\n for (const action of actions) {\n document = reducer(document, action) as TDocument;\n\n const operation = document.operations[action.scope]!.slice().pop()!;\n operations.push(operation);\n }\n return operations;\n}\n\nexport function buildOperationAndDocument<TDocument extends PHDocument>(\n reducer: Reducer<any>,\n document: TDocument,\n action: Action,\n index?: number,\n): {\n document: TDocument;\n operation: Operation;\n} {\n const newDocument = reducer(document, action);\n\n const operation = newDocument.operations[action.scope]!.slice().pop()!;\n\n return {\n document: newDocument as TDocument,\n operation: {\n ...operation,\n index: index ?? operation.index,\n } as Operation,\n };\n}\n\nexport class BasicClient<TDocument extends PHDocument = PHDocument> {\n private unsyncedOperations: Operation[] = [];\n\n constructor(\n private server: BaseDocumentDriveServer,\n private driveId: string,\n private documentId: string,\n private document: TDocument,\n private reducer: Reducer<any>,\n ) {}\n\n getDocument(): TDocument {\n return this.document;\n }\n\n clearUnsyncedOperations() {\n this.unsyncedOperations = [];\n }\n\n async pushOperationsToServer() {\n const result = await this.server.addOperations(\n this.documentId,\n this.unsyncedOperations,\n );\n\n if (result.status === \"SUCCESS\") {\n this.unsyncedOperations = [];\n }\n\n return result;\n }\n\n async syncDocument() {\n this.clearUnsyncedOperations();\n\n const remoteDocument = await this.server.getDocument(this.documentId);\n\n const remoteDocumentOperations = Object.values(remoteDocument.operations)\n .filter((ops): ops is Operation[] => ops !== undefined)\n .flat();\n\n const result = await this.server._processOperations(\n this.documentId,\n this.document,\n remoteDocumentOperations,\n );\n\n this.document = result.document as TDocument;\n return this.document;\n }\n\n dispatchDocumentAction(action: Action) {\n const result = buildOperationAndDocument(\n this.reducer,\n this.document,\n action,\n );\n\n this.document = { ...result.document };\n this.unsyncedOperations.push({ ...result.operation });\n\n return result;\n }\n}\n\nexport class DriveBasicClient<TDocument extends PHDocument = PHDocument> {\n private unsyncedOperations: Operation[] = [];\n\n constructor(\n private server: IDocumentDriveServer,\n private driveId: string,\n private document: TDocument,\n private reducer: Reducer<any>,\n ) {}\n\n getDocument(): TDocument {\n return this.document;\n }\n\n getUnsyncedOperations() {\n return this.unsyncedOperations;\n }\n\n setUnsyncedOperations(operations: Operation[]) {\n this.unsyncedOperations = operations;\n }\n\n clearUnsyncedOperations() {\n this.unsyncedOperations = [];\n }\n\n async pushOperationsToServer() {\n const result = await this.server.addOperations(\n this.driveId,\n this.unsyncedOperations,\n );\n\n if (result.status === \"SUCCESS\") {\n this.unsyncedOperations = [];\n }\n\n return result;\n }\n\n async syncDocument() {\n this.clearUnsyncedOperations();\n\n const remoteDocument = await this.server.getDrive(this.driveId);\n\n const remoteDocumentOperations = Object.values(remoteDocument.operations)\n .filter((ops): ops is Operation[] => ops !== undefined)\n .flat();\n\n const result = await (\n this.server as unknown as BaseDocumentDriveServer\n )._processOperations(this.driveId, this.document, remoteDocumentOperations);\n\n this.document = result.document as TDocument;\n return this.document;\n }\n\n dispatchDriveAction(action: Action) {\n const result = buildOperationAndDocument(\n this.reducer,\n this.document,\n action,\n );\n\n this.document = { ...result.document };\n this.unsyncedOperations.push({ ...result.operation });\n\n return result;\n }\n}\n\nexport const fakeAction = (\n // including some of the operation fields while we refactor\n params: Partial<Action> & { index?: number; hash?: string; skip?: number },\n): Action =>\n ({\n id: generateId(),\n timestampUtcMs: new Date().toISOString(),\n ...params,\n }) as Action;\n\n/**\n * Creates a default base state with the required auth and document properties\n * @param global - The global state\n * @param local - The local state\n */\nexport function createBaseState<TGlobal, TLocal>(\n global: TGlobal,\n local: TLocal,\n): PHBaseState & { global: TGlobal; local: TLocal } {\n return {\n auth: {},\n document: {\n version: 0,\n hash: {\n algorithm: \"sha1\",\n encoding: \"base64\",\n params: {},\n },\n },\n global,\n local,\n };\n}\n","import {\n driveDocumentModelModule,\n driveDocumentType,\n type DocumentDrivePHState,\n} from \"@powerhousedao/shared/document-drive\";\nimport type {\n GetDocumentModelModule,\n IReadModeDriveService,\n ReadDrive,\n ReadDriveContext,\n ReadDriveOptions,\n} from \"document-drive\";\nimport type {\n DocumentModelModule,\n PHBaseState,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport type { GraphQLError } from \"graphql\";\nimport { DocumentModelNotFoundError } from \"server\";\nimport { fetchDocument, requestPublicDrive } from \"utils\";\nimport {\n ReadDocumentNotFoundError,\n ReadDriveError,\n ReadDriveNotFoundError,\n ReadDriveSlugNotFoundError,\n} from \"./errors.js\";\n\nexport class ReadModeService implements IReadModeDriveService {\n #getDocumentModelModule: GetDocumentModelModule;\n #drives = new Map<\n string,\n { drive: Omit<ReadDrive, \"readContext\">; context: ReadDriveContext }\n >();\n\n constructor(getDocumentModelModule: GetDocumentModelModule) {\n this.#getDocumentModelModule = getDocumentModelModule;\n }\n\n #parseGraphQLErrors(\n errors: GraphQLError[],\n driveId: string,\n documentId?: string,\n ) {\n for (const error of errors) {\n if (error.message === `Drive with id ${driveId} not found`) {\n return new ReadDriveNotFoundError(driveId);\n } else if (\n documentId &&\n error.message === `Document with id ${documentId} not found`\n ) {\n return new ReadDocumentNotFoundError(driveId, documentId);\n }\n }\n const firstError = errors.at(0);\n if (firstError) {\n return firstError;\n }\n }\n\n async #fetchDrive(id: string, url: string) {\n const { errors, document } = await fetchDocument(\n url,\n id,\n driveDocumentModelModule,\n );\n const error = errors ? this.#parseGraphQLErrors(errors, id) : undefined;\n return error || document;\n }\n\n async fetchDrive(id: string): Promise<ReadDrive | ReadDriveNotFoundError> {\n const drive = this.#drives.get(id);\n if (!drive) {\n return new ReadDriveNotFoundError(id);\n }\n const document = await this.fetchDocument<DocumentDrivePHState>(\n id,\n id,\n driveDocumentType,\n );\n if (document instanceof Error) {\n return document;\n }\n const result = { ...document, readContext: drive.context };\n drive.drive = result;\n return result;\n }\n\n async fetchDocument<TState extends PHBaseState = PHBaseState>(\n driveId: string,\n documentId: string,\n documentType: string,\n ): Promise<\n | PHDocument<TState>\n | DocumentModelNotFoundError\n | ReadDriveNotFoundError\n | ReadDocumentNotFoundError\n > {\n const drive = this.#drives.get(driveId);\n if (!drive) {\n return new ReadDriveNotFoundError(driveId);\n }\n\n let documentModelModule: DocumentModelModule<TState> | undefined =\n undefined;\n try {\n documentModelModule = this.#getDocumentModelModule(documentType);\n } catch (error) {\n return new DocumentModelNotFoundError(documentType, error);\n }\n\n const { url } = drive.context;\n const { errors, document } = await fetchDocument<TState>(\n url,\n documentId,\n documentModelModule,\n );\n\n if (errors) {\n const error = this.#parseGraphQLErrors(errors, driveId, documentId);\n if (error instanceof ReadDriveError) {\n return error;\n } else if (error) {\n throw error;\n }\n }\n\n if (!document) {\n return new ReadDocumentNotFoundError(driveId, documentId);\n }\n\n return document as unknown as PHDocument<TState>;\n }\n\n async addReadDrive(url: string, options?: ReadDriveOptions): Promise<void> {\n let id: string;\n if (options?.expectedDriveInfo) {\n id = options.expectedDriveInfo.id;\n } else {\n const drive = await requestPublicDrive(url);\n id = drive.id;\n }\n\n const result = await this.#fetchDrive(id, url);\n if (result instanceof Error) {\n throw result;\n } else if (!result) {\n throw new ReadDriveNotFoundError(id);\n }\n this.#drives.set(id, {\n drive: result as unknown as ReadDrive,\n context: {\n ...options,\n url,\n },\n });\n }\n\n async getReadDrives() {\n return Promise.resolve([...this.#drives.keys()]);\n }\n\n async getReadDrive(id: string): Promise<ReadDrive | ReadDriveNotFoundError> {\n const result = this.#drives.get(id);\n return Promise.resolve(\n result\n ? { ...result.drive, readContext: result.context }\n : new ReadDriveNotFoundError(id),\n );\n }\n\n async getReadDriveBySlug(\n slug: string,\n ): Promise<ReadDrive | ReadDriveSlugNotFoundError> {\n const readDrive = [...this.#drives.values()].find(\n ({ drive }) => drive.header.slug === slug,\n );\n\n return Promise.resolve(\n readDrive\n ? { ...readDrive.drive, readContext: readDrive.context }\n : new ReadDriveSlugNotFoundError(slug),\n );\n }\n\n getReadDriveContext(id: string) {\n return Promise.resolve(\n this.#drives.get(id)?.context ?? new ReadDriveNotFoundError(id),\n );\n }\n\n deleteReadDrive(id: string): Promise<ReadDriveNotFoundError | undefined> {\n const deleted = this.#drives.delete(id);\n return Promise.resolve(\n deleted ? undefined : new ReadDriveNotFoundError(id),\n );\n }\n}\n","import type { PHBaseState } from \"@powerhousedao/shared/document-model\";\nimport type {\n DocumentDriveServerConstructor,\n IReadModeDriveServer,\n IReadModeDriveService,\n ReadDrive,\n ReadDriveOptions,\n ReadDrivesListener,\n ReadDriveSlugNotFoundError,\n RemoteDriveOptions,\n} from \"document-drive\";\nimport { logger } from \"document-model\";\nimport { ReadModeService } from \"./service.js\";\n\nexport function ReadModeServer(\n Base: DocumentDriveServerConstructor,\n): new (\n ...args: ConstructorParameters<typeof Base>\n) => InstanceType<typeof Base> & IReadModeDriveServer {\n return class ReadMode extends Base implements IReadModeDriveServer {\n #readModeStorage: IReadModeDriveService;\n #listeners = new Set<ReadDrivesListener>();\n\n constructor(...args: any[]) {\n super(...args);\n\n this.#readModeStorage = new ReadModeService(\n this.getDocumentModelModule.bind(this),\n );\n\n this.#buildDrives()\n .then((drives) => {\n if (drives.length) {\n this.#notifyListeners(drives, \"add\");\n }\n })\n .catch((e) => logger.error(\"@error\", e));\n }\n\n async #buildDrives() {\n const driveIds = await this.getReadDrives();\n const drives = (\n await Promise.all(driveIds.map((driveId) => this.getReadDrive(driveId)))\n ).filter((drive: any) => !(drive instanceof Error)) as ReadDrive[];\n return drives;\n }\n\n #notifyListeners(drives: ReadDrive[], operation: \"add\" | \"delete\") {\n this.#listeners.forEach((listener) => listener(drives, operation));\n }\n\n getReadDrives(): Promise<string[]> {\n return this.#readModeStorage.getReadDrives();\n }\n\n getReadDrive(id: string) {\n return this.#readModeStorage.getReadDrive(id);\n }\n\n getReadDriveBySlug(\n slug: string,\n ): Promise<ReadDrive | ReadDriveSlugNotFoundError> {\n return this.#readModeStorage.getReadDriveBySlug(slug);\n }\n\n getReadDriveContext(id: string) {\n return this.#readModeStorage.getReadDriveContext(id);\n }\n\n async addReadDrive(url: string, options?: ReadDriveOptions) {\n await this.#readModeStorage.addReadDrive(url, options);\n this.#notifyListeners(await this.#buildDrives(), \"add\");\n }\n\n fetchDrive(id: string) {\n return this.#readModeStorage.fetchDrive(id);\n }\n\n fetchDocument<TState extends PHBaseState = PHBaseState>(\n driveId: string,\n documentId: string,\n documentType: string,\n ) {\n return this.#readModeStorage.fetchDocument<TState>(\n driveId,\n documentId,\n documentType,\n );\n }\n\n async deleteReadDrive(id: string) {\n const error = await this.#readModeStorage.deleteReadDrive(id);\n if (error) {\n return error;\n }\n\n this.#notifyListeners(await this.#buildDrives(), \"delete\");\n }\n\n async migrateReadDrive(id: string, options: RemoteDriveOptions) {\n const result = await this.getReadDriveContext(id);\n if (result instanceof Error) {\n return result;\n }\n\n const { url, ...readOptions } = result;\n try {\n const newDrive = await this.addRemoteDrive(url, options);\n return newDrive;\n } catch (error) {\n // if an error is thrown, then add the read drive again\n logger.error(\"@error\", error);\n await this.addReadDrive(result.url, readOptions);\n throw error;\n }\n }\n\n onReadDrivesUpdate(listener: ReadDrivesListener) {\n this.#listeners.add(listener);\n return Promise.resolve(() => this.#listeners.delete(listener));\n }\n };\n}\n","import type { ErrorStatus, SynchronizationUnitId } from \"document-drive\";\nimport type { Operation } from \"@powerhousedao/shared/document-model\";\n\nexport class DocumentModelNotFoundError extends Error {\n constructor(\n public id: string,\n cause?: unknown,\n ) {\n super(`Document model \"${id}\" not found`, { cause });\n }\n}\nexport class OperationError extends Error {\n status: ErrorStatus;\n operation: Operation | undefined;\n\n constructor(\n status: ErrorStatus,\n operation?: Operation,\n message?: string,\n cause?: unknown,\n ) {\n super(message, { cause: cause ?? operation });\n this.status = status;\n this.operation = operation;\n if (cause instanceof Error) {\n this.stack = cause.stack;\n }\n }\n}\n\nexport class ConflictOperationError extends OperationError {\n constructor(existingOperation: Operation, newOperation: Operation) {\n super(\n \"CONFLICT\",\n newOperation,\n `Conflicting operation on index ${newOperation.index}`,\n { existingOperation, newOperation },\n );\n }\n}\n\nexport class MissingOperationError extends OperationError {\n constructor(index: number, operation: Operation) {\n super(\"MISSING\", operation, `Missing operation on index ${index}`);\n }\n}\n\nexport enum DocumentAlreadyExistsReason {\n ID = \"id\",\n SLUG = \"slug\",\n}\n\nexport class DocumentAlreadyExistsError extends Error {\n documentId: string;\n\n constructor(\n documentId: string,\n reason: DocumentAlreadyExistsReason = DocumentAlreadyExistsReason.ID,\n ) {\n super(`Document (${documentId}) uses ${reason} that already exists`);\n\n this.documentId = documentId;\n }\n}\n\nexport class DocumentNotFoundError extends Error {\n documentId: string;\n\n constructor(documentId: string) {\n super(`Document with id ${documentId} not found`);\n\n this.documentId = documentId;\n }\n}\n\nexport class SynchronizationUnitNotFoundError extends Error {\n syncUnitId: SynchronizationUnitId;\n\n constructor(syncUnitId: SynchronizationUnitId) {\n super(`Sync unit ${JSON.stringify(syncUnitId)} not found`);\n this.syncUnitId = syncUnitId;\n }\n}\n","export const DefaultListenerManagerOptions = {\n sequentialUpdates: true,\n};\n","export const PULL_DRIVE_INTERVAL = 1500;\n","import type {\n ListenerFilter,\n Trigger,\n} from \"@powerhousedao/shared/document-drive\";\nimport { generateId } from \"@powerhousedao/shared/document-model\";\nimport type {\n CancelPullLoop,\n GetStrandsOptions,\n GraphQLResult,\n IListenerManager,\n IOperationResult,\n IPullResponderTransmitter,\n ListenerRevision,\n ListenerRevisionWithError,\n PullResponderTrigger,\n PullStrandsGraphQL,\n RemoteDriveOptions,\n ServerListener,\n StrandUpdate,\n StrandUpdateSource,\n} from \"document-drive\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport { gql } from \"graphql-request\";\nimport { OperationError } from \"server\";\nimport { operationsToRevision, requestGraphql } from \"utils\";\nimport { PULL_DRIVE_INTERVAL } from \"./constants.js\";\n\nconst MAX_REVISIONS_PER_ACK = 100;\nconst MAX_PULLS = 50;\n\ninterface GraphQLError {\n message: string;\n response?: {\n errors?: Array<{\n message: string;\n }>;\n };\n}\n\n// lazily create the static logger so the logging system has time to read\n// configuration values for setting log level\nlet _staticLogger: ILogger | undefined;\nconst staticLogger = () => {\n if (!_staticLogger) {\n _staticLogger = childLogger([\"PullResponderTransmitter\", \"static\"]);\n }\n return _staticLogger;\n};\n\nexport class PullResponderTransmitter implements IPullResponderTransmitter {\n private logger = childLogger([\n \"PullResponderTransmitter\",\n Math.floor(Math.random() * 999).toString(),\n ]);\n\n private listener: ServerListener;\n private manager: IListenerManager;\n\n constructor(listener: ServerListener, manager: IListenerManager) {\n this.listener = listener;\n this.manager = manager;\n this.logger.verbose(\n \"constructor(listener: @listenerId)\",\n listener.listenerId,\n );\n }\n\n private static async getAuthHeaders(\n url: string,\n manager?: IListenerManager,\n ): Promise<Record<string, string>> {\n if (!manager?.generateJwtHandler) {\n staticLogger().verbose(\"No JWT handler available for @url\", url);\n return {};\n }\n try {\n const jwt = await manager.generateJwtHandler(url);\n if (!jwt) {\n staticLogger().verbose(\"No JWT generated for @url\", url);\n return {};\n }\n return { Authorization: `Bearer ${jwt}` };\n } catch (error) {\n staticLogger().error(\"Error generating JWT for @url: @error\", url, error);\n return {};\n }\n }\n\n private async requestWithAuth<T>(\n url: string,\n query: string,\n variables?: Record<string, unknown>,\n ): Promise<GraphQLResult<T>> {\n const headers = await PullResponderTransmitter.getAuthHeaders(\n url,\n this.manager,\n );\n const result = await requestGraphql<T>(url, query, variables, headers);\n\n // Check for unauthorized error\n const error = result.errors?.at(0);\n if (error?.message.includes(\"Unauthorized\")) {\n // Retry once with fresh JWT\n const freshHeaders = await PullResponderTransmitter.getAuthHeaders(\n url,\n this.manager,\n );\n return requestGraphql<T>(url, query, variables, freshHeaders);\n }\n\n return result;\n }\n\n getStrands(options?: GetStrandsOptions): Promise<StrandUpdate[]> {\n this.logger.verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.getStrands called for drive: @driveId, listener: @listenerId, options: @options\",\n this.listener.driveId,\n this.listener.listenerId,\n options || {},\n );\n\n return this.manager\n .getStrands(this.listener.driveId, this.listener.listenerId, options)\n .then((strands) => {\n this.logger.verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.getStrands returning @count strands for drive: @driveId, listener: @listenerId\",\n strands.length,\n this.listener.driveId,\n this.listener.listenerId,\n );\n if (strands.length === 0) {\n this.logger.verbose(\n \"[SYNC DEBUG] No strands returned for drive: @driveId, listener: @listenerId\",\n this.listener.driveId,\n this.listener.listenerId,\n );\n } else {\n for (const strand of strands) {\n this.logger.verbose(\n \"[SYNC DEBUG] Strand for drive: @driveId, document: @documentId, scope: @scope, operations: @count\",\n strand.driveId,\n strand.documentId,\n strand.scope,\n strand.operations.length,\n );\n }\n }\n return strands;\n });\n }\n\n disconnect(): Promise<void> {\n // TODO remove listener from switchboard\n return Promise.resolve();\n }\n\n async processAcknowledge(\n driveId: string,\n listenerId: string,\n revisions: ListenerRevision[],\n ): Promise<boolean> {\n this.logger.verbose(\n \"processAcknowledge(drive: @driveId, listener: @listenerId): @revisions\",\n driveId,\n listenerId,\n revisions,\n );\n let success = true;\n for (const revision of revisions) {\n try {\n await this.manager.updateListenerRevision(\n listenerId,\n driveId,\n {\n documentId: revision.documentId,\n scope: revision.scope,\n branch: revision.branch,\n },\n revision.revision,\n );\n } catch (error) {\n this.logger.warn(\n \"Error acknowledging sync unit: @error, @revision\",\n error,\n revision,\n );\n success = false;\n continue;\n }\n }\n return success;\n }\n\n static async registerPullResponder(\n driveId: string,\n url: string,\n filter: ListenerFilter,\n listenerId?: string,\n manager?: IListenerManager,\n ): Promise<ServerListener[\"listenerId\"]> {\n staticLogger().verbose(\n \"registerPullResponder(url: @url) @filter\",\n url,\n filter,\n );\n\n const headers = await this.getAuthHeaders(url, manager);\n const result = await requestGraphql<{\n registerPullResponderListener: {\n listenerId: ServerListener[\"listenerId\"];\n };\n }>(\n url,\n gql`\n mutation registerPullResponderListener(\n $filter: InputListenerFilter!\n $listenerId: String\n ) {\n registerPullResponderListener(\n filter: $filter\n listenerId: $listenerId\n ) {\n listenerId\n }\n }\n `,\n { filter, listenerId },\n headers,\n );\n\n const error = result.errors?.at(0);\n if (error) {\n if (error.message.includes(\"Unauthorized\")) {\n // Retry once with fresh JWT\n const freshHeaders = await this.getAuthHeaders(url, manager);\n const retryResult = await requestGraphql<{\n registerPullResponderListener: {\n listenerId: ServerListener[\"listenerId\"];\n };\n }>(\n url,\n gql`\n mutation registerPullResponderListener(\n $filter: InputListenerFilter!\n $listenerId: String\n ) {\n registerPullResponderListener(\n filter: $filter\n listenerId: $listenerId\n ) {\n listenerId\n }\n }\n `,\n { filter, listenerId },\n freshHeaders,\n );\n if (retryResult.errors?.at(0)) {\n throw retryResult.errors[0];\n }\n if (!retryResult.registerPullResponderListener) {\n throw new Error(\"Error registering listener\");\n }\n return retryResult.registerPullResponderListener.listenerId;\n }\n throw error;\n }\n\n if (!result.registerPullResponderListener) {\n throw new Error(\"Error registering listener\");\n }\n\n return result.registerPullResponderListener.listenerId;\n }\n\n static async pullStrands(\n driveId: string,\n url: string,\n listenerId: string,\n options?: GetStrandsOptions,\n manager?: IListenerManager,\n ): Promise<StrandUpdate[]> {\n staticLogger().verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.pullStrands called for drive: @driveId, url: @url, listener: @listenerId, options: @options\",\n driveId,\n url,\n listenerId,\n options || {},\n );\n\n const headers = await this.getAuthHeaders(url, manager);\n const result = await requestGraphql<PullStrandsGraphQL>(\n url,\n gql`\n query strands($listenerId: ID!) {\n system {\n sync {\n strands(listenerId: $listenerId) {\n driveId\n documentId\n documentType\n scope\n branch\n operations {\n id\n actionId\n timestampUtcMs\n skip\n type\n input\n hash\n index\n context {\n signer {\n user {\n address\n networkId\n chainId\n }\n app {\n name\n key\n }\n signatures\n }\n }\n }\n }\n }\n }\n }\n `,\n { listenerId },\n headers,\n );\n\n const error = result.errors?.at(0);\n if (error) {\n if (error.message.includes(\"Unauthorized\")) {\n // Retry once with fresh JWT\n const freshHeaders = await this.getAuthHeaders(url, manager);\n const retryResult = await requestGraphql<PullStrandsGraphQL>(\n url,\n gql`\n query strands($listenerId: ID!) {\n system {\n sync {\n strands(listenerId: $listenerId) {\n driveId\n documentId\n documentType\n scope\n branch\n operations {\n id\n actionId\n timestampUtcMs\n skip\n type\n input\n hash\n index\n context {\n signer {\n user {\n address\n networkId\n chainId\n }\n app {\n name\n key\n }\n signatures\n }\n }\n }\n }\n }\n }\n }\n `,\n { listenerId },\n freshHeaders,\n );\n if (retryResult.errors?.at(0)) {\n throw retryResult.errors[0];\n }\n if (!retryResult.system) {\n return [];\n }\n return retryResult.system.sync.strands.map((s) => ({\n ...s,\n operations: s.operations.map((o) => ({\n ...o,\n input: JSON.parse(o.input) as object,\n })),\n }));\n }\n throw error;\n }\n\n if (!result.system) {\n staticLogger().verbose(\n \"[SYNC DEBUG] No system data returned when pulling strands for drive: @driveId, listener: @listenerId\",\n driveId,\n listenerId,\n );\n return [];\n }\n\n const strands = result.system.sync.strands.map((s) => ({\n ...s,\n operations: s.operations.map((o) => ({\n ...o,\n input: JSON.parse(o.input) as object,\n })),\n }));\n\n staticLogger().verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.pullStrands returning @count strands for drive: @driveId, listener: @listenerId\",\n strands.length,\n driveId,\n listenerId,\n );\n\n if (strands.length > 0) {\n staticLogger().verbose(\n \"[SYNC DEBUG] Strands being returned: @strandIds\",\n strands.map((s) => `${s.documentId}:${s.scope}`).join(\", \"),\n );\n }\n\n return strands;\n }\n\n static async acknowledgeStrands(\n url: string,\n listenerId: string,\n revisions: ListenerRevision[],\n manager?: IListenerManager,\n ): Promise<void> {\n staticLogger().verbose(\n \"acknowledgeStrands(url: @url, listener: @listenerId) @revisions\",\n url,\n listenerId,\n revisions,\n );\n\n // split revisions into chunks\n const chunks = [];\n for (let i = 0; i < revisions.length; i += MAX_REVISIONS_PER_ACK) {\n chunks.push(revisions.slice(i, i + MAX_REVISIONS_PER_ACK));\n }\n\n if (chunks.length > 1) {\n staticLogger().verbose(\n \"Breaking strand acknowledgement into @count chunks...\",\n chunks.length,\n );\n }\n\n const headers = await this.getAuthHeaders(url, manager);\n // order does not matter, we can send out requests in parallel\n const results = await Promise.allSettled(\n chunks.map(async (chunk) => {\n const result = await requestGraphql<{ acknowledge: boolean }>(\n url,\n gql`\n mutation acknowledge(\n $listenerId: String!\n $revisions: [ListenerRevisionInput]\n ) {\n acknowledge(listenerId: $listenerId, revisions: $revisions)\n }\n `,\n { listenerId, revisions: chunk },\n headers,\n );\n\n const error = result.errors?.at(0);\n if (error) {\n if (error.message.includes(\"Unauthorized\")) {\n // Retry once with fresh JWT\n const freshHeaders = await this.getAuthHeaders(url, manager);\n const retryResult = await requestGraphql<{ acknowledge: boolean }>(\n url,\n gql`\n mutation acknowledge(\n $listenerId: String!\n $revisions: [ListenerRevisionInput]\n ) {\n acknowledge(listenerId: $listenerId, revisions: $revisions)\n }\n `,\n { listenerId, revisions: chunk },\n freshHeaders,\n );\n if (retryResult.errors?.at(0)) {\n throw retryResult.errors[0];\n }\n if (retryResult.acknowledge === null || !retryResult.acknowledge) {\n throw new Error(\"Error acknowledging strands\");\n }\n return;\n }\n throw error;\n }\n\n if (result.acknowledge === null || !result.acknowledge) {\n throw new Error(\"Error acknowledging strands\");\n }\n }),\n );\n\n // throw after we try all chunks\n const errors = results.filter((result) => result.status === \"rejected\");\n if (errors.length > 0) {\n throw new Error(\"Error acknowledging strands\");\n }\n }\n\n /**\n * This function will only throw if `onError` throws an error (or there is\n * an unintentionally unhandled error in the pull loop).\n *\n * All other errors are caught, logged, and passed to `onError`.\n *\n * Because of this, `onError` _may be called multiple times_.\n *\n * @returns boolean indicating whether there might be more data to pull\n */\n private static async executePull(\n driveId: string,\n trigger: PullResponderTrigger,\n onStrandUpdate: (\n strand: StrandUpdate,\n source: StrandUpdateSource,\n ) => Promise<IOperationResult>,\n onError: (error: Error) => void,\n onRevisions?: (revisions: ListenerRevisionWithError[]) => void,\n onAcknowledge?: (success: boolean) => void,\n manager?: IListenerManager,\n ): Promise<boolean> {\n staticLogger().verbose(\n \"executePull(driveId: @driveId), trigger: @trigger\",\n driveId,\n trigger,\n );\n\n staticLogger().verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.executePull starting for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n\n const { url } = trigger.data;\n\n let strands: StrandUpdate[] | undefined;\n let error: Error | undefined;\n const listenerId = trigger.data.listenerId;\n try {\n strands = await PullResponderTransmitter.pullStrands(\n driveId,\n url,\n listenerId,\n undefined,\n manager,\n );\n } catch (e) {\n error = e as Error;\n\n const graphqlError = error as GraphQLError;\n const errors = graphqlError.response?.errors ?? [];\n\n for (const err of errors) {\n if (err.message === \"Listener not found\") {\n staticLogger().verbose(\n \"[SYNC DEBUG] Auto-registering pull responder for drive: @driveId\",\n driveId,\n );\n\n // register a new pull responder with this id\n await PullResponderTransmitter.registerPullResponder(\n trigger.driveId,\n url,\n trigger.filter,\n listenerId,\n );\n\n // try again\n try {\n strands = await PullResponderTransmitter.pullStrands(\n driveId,\n url,\n listenerId,\n undefined,\n manager,\n );\n\n staticLogger().verbose(\n \"Successfully auto-registered and pulled strands for drive: @driveId, listenerId: @listenerId\",\n driveId,\n listenerId,\n );\n } catch (error) {\n staticLogger().error(\n \"Could not resolve 'Listener not found' error by registering a new pull responder for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n listenerId,\n error,\n );\n\n onError(error as Error);\n return false;\n }\n\n break;\n }\n }\n }\n\n if (!strands) {\n staticLogger().error(\n \"Error pulling strands for drive, and could not auto-register: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n\n onError(error!);\n return false;\n }\n\n // if there are no new strands then do nothing\n if (!strands.length) {\n staticLogger().verbose(\n \"[SYNC DEBUG] No strands returned in pull cycle for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n\n try {\n onRevisions?.([]);\n } catch (error) {\n staticLogger().error(\n \"Error calling onRevisions for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n\n // pass the error to the caller\n onError(error as Error);\n }\n\n return false;\n }\n\n staticLogger().verbose(\n \"[SYNC DEBUG] Processing @count strands in pull cycle for drive: @driveId, listenerId: @listenerId\",\n strands.length,\n driveId,\n trigger.data.listenerId,\n );\n\n const listenerRevisions: ListenerRevisionWithError[] = [];\n\n // todo: evaluate whether or not we can process strands in parallel\n for (const strand of strands) {\n const operations = strand.operations.map((op) => ({\n ...op,\n scope: strand.scope,\n branch: strand.branch,\n }));\n\n staticLogger().verbose(\n \"[SYNC DEBUG] Processing strand for drive: @driveId, document: @documentId, scope: @scope, with @count operations\",\n strand.driveId,\n strand.documentId,\n strand.scope,\n operations.length,\n );\n\n let error: Error | undefined = undefined;\n try {\n const result = await onStrandUpdate(strand, {\n type: \"trigger\",\n trigger,\n });\n\n if (result.error) {\n throw result.error;\n }\n } catch (e) {\n staticLogger().error(\n \"Error processing strand for drive: @driveId, document: @documentId, scope: @scope, with @count operations: @error\",\n strand.driveId,\n strand.documentId,\n strand.scope,\n operations.length,\n e,\n );\n\n error = e as Error;\n onError(error);\n\n // continue\n }\n\n listenerRevisions.push({\n branch: strand.branch,\n documentId: strand.documentId || \"\",\n documentType: strand.documentType,\n driveId: strand.driveId,\n revision: operationsToRevision(operations),\n scope: strand.scope,\n status: error\n ? error instanceof OperationError\n ? error.status\n : \"ERROR\"\n : \"SUCCESS\",\n error,\n });\n }\n\n staticLogger().verbose(\"Processed strands...\");\n\n // do not let a listener kill the pull loop\n try {\n onRevisions?.(listenerRevisions);\n } catch (error) {\n staticLogger().error(\n \"Error calling onRevisions for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n\n // pass the error to the caller\n onError(error as Error);\n }\n\n staticLogger().verbose(\n \"[SYNC DEBUG] Acknowledging @count strands for drive: @driveId, listenerId: @listenerId\",\n listenerRevisions.length,\n driveId,\n trigger.data.listenerId,\n );\n\n let success = false;\n try {\n await PullResponderTransmitter.acknowledgeStrands(\n url,\n trigger.data.listenerId,\n listenerRevisions.map((revision) => {\n const { error, ...rest } = revision;\n return rest;\n }),\n manager,\n );\n\n success = true;\n } catch (error) {\n staticLogger().error(\n \"Error acknowledging strands for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n\n // pass the error to the caller\n onError(error as Error);\n }\n\n if (success) {\n staticLogger().verbose(\n \"[SYNC DEBUG] Successfully acknowledged strands for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n } else {\n staticLogger().error(\"Failed to acknowledge strands\");\n }\n\n // let this throw separately\n try {\n onAcknowledge?.(success);\n } catch (error) {\n staticLogger().error(\n \"Error calling onAcknowledge for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n\n // pass the error to the caller\n onError(error as Error);\n }\n\n // Return true if we received strands, indicating there might be more to pull\n return strands.length > 0;\n }\n\n static setupPull(\n driveId: string,\n trigger: PullResponderTrigger,\n onStrandUpdate: (\n strand: StrandUpdate,\n source: StrandUpdateSource,\n ) => Promise<IOperationResult>,\n onError: (error: Error) => void,\n onRevisions?: (revisions: ListenerRevisionWithError[]) => void,\n onAcknowledge?: (success: boolean) => void,\n manager?: IListenerManager,\n ): CancelPullLoop {\n staticLogger().verbose(\n \"[SYNC DEBUG] PullResponderTransmitter.setupPull initiated for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n\n const { interval } = trigger.data;\n let loopInterval = PULL_DRIVE_INTERVAL;\n if (interval) {\n try {\n const intervalNumber = parseInt(interval);\n if (intervalNumber) {\n loopInterval = intervalNumber;\n }\n } catch {\n // ignore invalid interval\n }\n }\n\n staticLogger().verbose(\n \"[SYNC DEBUG] Pull interval set to @loopIntervalms for drive: @driveId, listenerId: @listenerId\",\n loopInterval,\n driveId,\n trigger.data.listenerId,\n );\n\n let isCancelled = false;\n let timeout: number | undefined;\n\n const executeLoop = async () => {\n while (!isCancelled) {\n staticLogger().verbose(\n \"[SYNC DEBUG] Starting pull cycle for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n\n // keep pulling until we get no more strands, encounter an error, or hit the limit\n let counter = 0;\n let hasMore = true;\n while (hasMore && !isCancelled && counter < MAX_PULLS) {\n counter++;\n\n hasMore = await this.executePull(\n driveId,\n trigger,\n onStrandUpdate,\n onError,\n onRevisions,\n onAcknowledge,\n manager,\n );\n\n if (hasMore) {\n staticLogger().verbose(\n \"[SYNC DEBUG] More strands available, continuing pull cycle for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n }\n }\n\n staticLogger().verbose(\n \"[SYNC DEBUG] Completed pull cycle for drive: @driveId, listenerId: @listenerId, waiting @loopIntervalms for next cycle\",\n driveId,\n trigger.data.listenerId,\n loopInterval,\n );\n\n await new Promise((resolve) => {\n staticLogger().verbose(\n \"Scheduling next pull in @loopInterval ms\",\n loopInterval,\n );\n timeout = setTimeout(resolve, loopInterval) as unknown as number;\n });\n }\n };\n\n executeLoop().catch((error) => {\n staticLogger().error(\n \"Error in executeLoop for drive: @driveId, listenerId: @listenerId: @error\",\n driveId,\n trigger.data.listenerId,\n error,\n );\n });\n\n return () => {\n staticLogger().verbose(\n \"[SYNC DEBUG] Cancelling pull loop for drive: @driveId, listenerId: @listenerId\",\n driveId,\n trigger.data.listenerId,\n );\n isCancelled = true;\n if (timeout !== undefined) {\n clearTimeout(timeout);\n }\n };\n }\n\n static async createPullResponderTrigger(\n driveId: string,\n url: string,\n options: Pick<RemoteDriveOptions, \"pullInterval\" | \"pullFilter\">,\n listenerManager: IListenerManager,\n ): Promise<PullResponderTrigger> {\n staticLogger().verbose(\n \"createPullResponderTrigger(drive: @driveId, url: @url)\",\n driveId,\n url,\n );\n\n const { pullFilter, pullInterval } = options;\n const filter = pullFilter ?? {\n documentId: [\"*\"],\n documentType: [\"*\"],\n branch: [\"*\"],\n scope: [\"*\"],\n };\n\n const listenerId = await PullResponderTransmitter.registerPullResponder(\n driveId,\n url,\n filter,\n undefined,\n listenerManager,\n );\n\n const pullTrigger: PullResponderTrigger = {\n id: generateId(),\n type: \"PullResponder\",\n driveId,\n filter,\n data: {\n url,\n listenerId,\n interval: pullInterval?.toString() ?? \"\",\n },\n };\n\n return pullTrigger;\n }\n\n static isPullResponderTrigger(\n trigger: Trigger,\n ): trigger is PullResponderTrigger {\n return trigger.type === \"PullResponder\";\n }\n}\n","import type {\n GraphQLResult,\n IListenerManager,\n ITransmitter,\n ListenerRevision,\n StrandUpdate,\n StrandUpdateSource,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport { gql } from \"graphql-request\";\nimport stringify from \"json-stringify-deterministic\";\nimport { operationsToRevision, requestGraphql } from \"utils\";\n\nconst SYNC_OPS_BATCH_LIMIT = 10;\n\nexport class SwitchboardPushTransmitter implements ITransmitter {\n private targetURL: string;\n private manager?: IListenerManager;\n private logger = childLogger([\n \"SwitchboardPushTransmitter\",\n Math.floor(Math.random() * 999).toString(),\n ]);\n\n constructor(targetURL: string, manager?: IListenerManager) {\n this.targetURL = targetURL;\n this.manager = manager;\n }\n\n private async getAuthHeaders(): Promise<Record<string, string>> {\n if (!this.manager?.generateJwtHandler) {\n this.logger.verbose(\n \"No JWT handler available for @targetURL\",\n this.targetURL,\n );\n return {};\n }\n try {\n const jwt = await this.manager.generateJwtHandler(this.targetURL);\n if (!jwt) {\n this.logger.verbose(\"No JWT generated for @targetURL\", this.targetURL);\n return {};\n }\n return { Authorization: `Bearer ${jwt}` };\n } catch (error) {\n this.logger.error(\n \"Error generating JWT for @targetURL: @error\",\n this.targetURL,\n error,\n );\n return {};\n }\n }\n\n private async requestWithAuth<T>(\n query: string,\n variables?: Record<string, unknown>,\n ): Promise<GraphQLResult<T>> {\n const headers = await this.getAuthHeaders();\n const result = await requestGraphql<T>(\n this.targetURL,\n query,\n variables,\n headers,\n );\n\n // Check for unauthorized error\n const error = result.errors?.at(0);\n if (error?.message.includes(\"Unauthorized\")) {\n // Retry once with fresh JWT\n const freshHeaders = await this.getAuthHeaders();\n return requestGraphql<T>(this.targetURL, query, variables, freshHeaders);\n }\n\n return result;\n }\n\n async transmit(\n strands: StrandUpdate[],\n source: StrandUpdateSource,\n ): Promise<ListenerRevision[]> {\n if (\n source.type === \"trigger\" &&\n source.trigger.data?.url === this.targetURL\n ) {\n this.logger.verbose(\n \"Cutting trigger loop from @targetURL.\",\n this.targetURL,\n );\n\n return strands.map((strand) => {\n return {\n driveId: strand.driveId,\n documentId: strand.documentId,\n documentType: strand.documentType,\n scope: strand.scope,\n branch: strand.branch,\n status: \"SUCCESS\",\n revision: operationsToRevision(strand.operations),\n };\n });\n }\n\n const culledStrands: StrandUpdate[] = [];\n let opsCounter = 0;\n\n for (\n let s = 0;\n opsCounter <= SYNC_OPS_BATCH_LIMIT && s < strands.length;\n s++\n ) {\n const currentStrand = strands.at(s);\n if (!currentStrand) {\n break;\n }\n const newOps = Math.min(\n SYNC_OPS_BATCH_LIMIT - opsCounter,\n currentStrand.operations.length,\n );\n\n culledStrands.push({\n ...currentStrand,\n operations: currentStrand.operations.slice(0, newOps),\n });\n\n opsCounter += newOps;\n }\n\n this.logger.verbose(\n \"Total update: [@opCounts] operations\",\n strands.map((s) => s.operations.length).join(\", \"),\n );\n\n this.logger.verbose(\n \"Culled update: [@opCounts] operations\",\n culledStrands.map((s) => s.operations.length).join(\", \"),\n );\n\n // Send Graphql mutation to switchboard\n try {\n const result = await this.requestWithAuth<{\n pushUpdates: ListenerRevision[];\n }>(\n gql`\n mutation pushUpdates($strands: [InputStrandUpdate!]) {\n pushUpdates(strands: $strands) {\n driveId\n documentId\n documentType\n scope\n branch\n status\n revision\n error\n }\n }\n `,\n {\n strands: culledStrands.map((strand) => ({\n driveId: strand.driveId,\n documentId: strand.documentId,\n documentType: strand.documentType,\n scope: strand.scope,\n branch: strand.branch,\n operations: strand.operations.map((op) => ({\n index: op.index,\n skip: op.skip,\n type: op.type,\n id: op.id ?? undefined,\n actionId: op.actionId,\n input: stringify(op.input),\n hash: op.hash,\n timestampUtcMs: op.timestampUtcMs,\n context: op.context\n ? {\n signer: op.context.signer,\n }\n : undefined,\n })),\n })),\n },\n );\n\n if (!result.pushUpdates) {\n throw new Error(\"Couldn't update listener revision\");\n }\n\n return result.pushUpdates;\n } catch (e) {\n this.logger.error(\"@error\", e);\n throw e;\n }\n }\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n CreateDocumentInput,\n RevisionsFilter,\n SharingType,\n StrandUpdate,\n SynchronizationUnitId,\n} from \"document-drive\";\nimport type {\n DocumentOperations,\n Operation,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\n\nexport function buildRevisionsFilter(\n strands: StrandUpdate[],\n driveId: string,\n documentId: string,\n): RevisionsFilter {\n return strands.reduce<RevisionsFilter>((acc, s) => {\n if (!(s.driveId === driveId && s.documentId === documentId)) {\n return acc;\n }\n acc[s.scope] = s.operations[s.operations.length - 1]?.index ?? -1;\n return acc;\n }, {});\n}\n\nexport function buildDocumentRevisionsFilter(\n document: PHDocument,\n): RevisionsFilter {\n return Object.entries(document.operations).reduce<RevisionsFilter>(\n (acc, [scope, operations]) => {\n acc[scope] = operations?.at(-1)?.index ?? -1;\n return acc;\n },\n {} as RevisionsFilter,\n );\n}\n\nexport function filterOperationsByRevision(\n operations: DocumentOperations,\n revisions?: RevisionsFilter,\n): DocumentOperations {\n if (!revisions) {\n return operations;\n }\n return Object.keys(operations).reduce(\n (acc, scope) => {\n const revision = revisions[scope];\n if (revision !== undefined) {\n const scopeOps = operations[scope];\n if (scopeOps) {\n acc[scope] = scopeOps.filter((op: Operation) => op.index <= revision);\n }\n }\n return acc;\n },\n { global: [], local: [] } as DocumentOperations,\n );\n}\n\nexport function isAtRevision(\n document: PHDocument,\n revisions?: RevisionsFilter,\n): boolean {\n return (\n !revisions ||\n Object.entries(revisions).find(([scope, revision]) => {\n const operation = document.operations[scope]?.at(-1);\n if (revision === -1) {\n return operation !== undefined;\n }\n return operation?.index !== revision;\n }) === undefined\n );\n}\n\nexport function isAfterRevision(\n document: PHDocument,\n revisions?: RevisionsFilter,\n): boolean {\n return (\n !revisions ||\n Object.entries(revisions).every(([scope, revision]) => {\n const operation = document.operations[scope]?.at(-1);\n\n if (revision === -1) {\n return operation !== undefined;\n }\n return (\n operation !== undefined &&\n revision !== undefined &&\n operation.index > revision\n );\n })\n );\n}\n\nexport function compareSyncUnits(\n a: SynchronizationUnitId,\n b: SynchronizationUnitId,\n) {\n return (\n a.documentId === b.documentId &&\n a.scope === b.scope &&\n a.branch === b.branch\n );\n}\n\nexport function resolveCreateDocumentInput<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n) {\n return {\n id: resolveCreateDocumentInputId(input),\n documentType: resolveCreateDocumentInputDocumentType(input),\n document: resolveCreateDocumentInputDocument(input),\n };\n}\n\nexport function resolveCreateDocumentInputId(\n input: CreateDocumentInput<PHDocument>,\n) {\n if (\"id\" in input) {\n return input.id;\n } else if (\"header\" in input) {\n return input.header.id;\n } else if (\"document\" in input) {\n return input.document.header.id;\n } else {\n return undefined;\n }\n}\n\nexport function resolveCreateDocumentInputDocumentType(\n input: CreateDocumentInput<PHDocument>,\n) {\n if (\"documentType\" in input) {\n return input.documentType;\n } else if (\"header\" in input) {\n return input.header.documentType;\n } else {\n return input.document.header.documentType;\n }\n}\n\nexport function resolveCreateDocumentInputDocument<\n TDocument extends PHDocument,\n>(input: CreateDocumentInput<TDocument>) {\n return \"document\" in input ? input.document : undefined;\n}\n\nexport function isSharingType(value: string): value is SharingType {\n return [\"LOCAL\", \"CLOUD\", \"PUBLIC\"].includes(value);\n}\n\nexport function getDriveSharingType(drive: DocumentDriveDocument): SharingType {\n if (typeof drive !== \"object\") return \"LOCAL\";\n const isReadDrive = \"readContext\" in drive;\n const { sharingType: _sharingType } = !isReadDrive\n ? drive.state.local\n : { sharingType: \"PUBLIC\" };\n const __sharingType = _sharingType?.toUpperCase();\n\n return !__sharingType ||\n __sharingType === \"PRIVATE\" ||\n !isSharingType(__sharingType)\n ? \"LOCAL\"\n : __sharingType;\n}\n","import type {\n DocumentDriveAction,\n DocumentDriveDocument,\n LegacyAddFileAction,\n} from \"@powerhousedao/shared/document-drive\";\nimport {\n type AddFileAction,\n type Trigger,\n driveCreateDocument,\n driveCreateState,\n removeListener,\n removeTrigger,\n setSharingType,\n} from \"@powerhousedao/shared/document-drive\";\nimport type {\n Action,\n CreateDocumentActionInput,\n DocumentModelModule,\n DocumentOperations,\n GetDocumentOptions,\n Operation,\n PHDocument,\n PHDocumentHeader,\n PHDocumentMeta,\n Signal,\n SignalResult,\n UpgradeDocumentActionInput,\n} from \"@powerhousedao/shared/document-model\";\nimport {\n attachBranch,\n createPresignedHeader,\n defaultBaseState,\n deriveOperationId,\n diffOperations,\n garbageCollect,\n garbageCollectDocumentOperations,\n generateId,\n groupOperationsByScope,\n hashDocumentStateForScope,\n merge,\n precedes,\n removeExistingOperations,\n replayDocument,\n reshuffleByTimestamp,\n skipHeaderOperations,\n sortOperations,\n validateHeader,\n} from \"@powerhousedao/shared/document-model\";\nimport type { ICache } from \"cache\";\nimport { childLogger } from \"document-model\";\nimport { ClientError } from \"graphql-request\";\nimport type { Unsubscribe } from \"nanoevents\";\nimport { isActionJob, isDocumentJob, isOperationJob } from \"queue\";\nimport { ReadModeServer } from \"read-mode\";\nimport type { IDocumentStorage, IDriveOperationStorage } from \"storage\";\nimport {\n DefaultDrivesManager,\n isDocumentDrive,\n requestPublicDriveWithTokenFromReactor,\n runAsap,\n runAsapAsync,\n} from \"utils\";\nimport type {\n ActionJob,\n DocumentJob,\n IQueueManager,\n Job,\n OperationJob,\n} from \"../queue/types.js\";\nimport type { IDefaultDrivesManager } from \"../utils/types.js\";\nimport type { SynchronizationUnitNotFoundError } from \"./error.js\";\nimport {\n ConflictOperationError,\n DocumentAlreadyExistsError,\n OperationError,\n} from \"./error.js\";\nimport { DefaultListenerManagerOptions } from \"./listener/constants.js\";\nimport { PullResponderTransmitter } from \"./transmitter/pull-responder.js\";\nimport { SwitchboardPushTransmitter } from \"./transmitter/switchboard-push.js\";\nimport type {\n CancelPullLoop,\n StrandUpdateSource,\n} from \"./transmitter/types.js\";\nimport type {\n AddOperationOptions,\n CreateDocumentInput,\n DocumentDriveServerOptions,\n DriveEvents,\n DriveInput,\n DriveOperationResult,\n IBaseDocumentDriveServer,\n IEventEmitter,\n IListenerManager,\n IOperationResult,\n ISynchronizationManager,\n ListenerState,\n OperationUpdate,\n RemoteDriveAccessLevel,\n RemoteDriveOptions,\n ServerListener,\n StrandUpdate,\n SynchronizationUnit,\n SyncStatus,\n SyncUnitStatusObject,\n} from \"./types.js\";\nimport {\n filterOperationsByRevision,\n isAtRevision,\n resolveCreateDocumentInput,\n} from \"./utils.js\";\n\nexport class BaseDocumentDriveServer\n implements IBaseDocumentDriveServer, IDefaultDrivesManager\n{\n protected logger = childLogger([\"BaseDocumentDriveServer\"]);\n\n // external dependencies\n private documentModelModules: DocumentModelModule[];\n private legacyStorage: IDriveOperationStorage;\n private documentStorage: IDocumentStorage;\n private cache: ICache;\n private queueManager: IQueueManager;\n public eventEmitter: IEventEmitter;\n protected options: Required<DocumentDriveServerOptions>;\n private listenerManager: IListenerManager;\n private synchronizationManager: ISynchronizationManager;\n public generateJwtHandler?: (driveUrl: string) => Promise<string>;\n\n // internal dependencies\n private defaultDrivesManager: DefaultDrivesManager;\n\n private defaultDrivesManagerDelegate = {\n detachDrive: this.detachDrive.bind(this),\n emit: (...args: Parameters<DriveEvents[\"defaultRemoteDrive\"]>) =>\n this.eventEmitter.emit(\"defaultRemoteDrive\", ...args),\n };\n\n private queueDelegate = {\n exists: (documentId: string): Promise<boolean> =>\n this.documentStorage.exists(documentId),\n processOperationJob: async ({\n documentId,\n operations,\n options,\n }: OperationJob) => {\n const document = await this.getDocument(documentId);\n return isDocumentDrive(document)\n ? this.processDriveOperations(documentId, operations, options)\n : this.processOperations(documentId, operations, options);\n },\n processActionJob: async ({ documentId, actions, options }: ActionJob) => {\n const document = await this.getDocument(documentId);\n return isDocumentDrive(document)\n ? this.processDriveActions(documentId, actions, options)\n : this.processActions(documentId, actions, options);\n },\n processDocumentJob: async ({\n documentId,\n documentType,\n header: inputHeader,\n initialState,\n options,\n }: DocumentJob): Promise<IOperationResult> => {\n const documentModelModule = this.getDocumentModelModule(documentType);\n\n const document = documentModelModule.utils.createDocument(initialState);\n // TODO: header must be included\n const header = createPresignedHeader(documentId, documentType);\n document.header.id = documentId;\n document.header.sig = header.sig;\n document.header.documentType = documentType;\n\n if (inputHeader) {\n document.header.meta = inputHeader.meta;\n }\n\n try {\n const createdDocument = await this.createDocument(\n { document },\n options?.source ?? { type: \"local\" },\n document.header.meta,\n );\n return {\n status: \"SUCCESS\",\n operations: [],\n document: createdDocument,\n signals: [],\n };\n } catch (error) {\n const cause =\n error instanceof Error ? error : new Error(JSON.stringify(error));\n return {\n status: \"ERROR\",\n error: new OperationError(\n \"ERROR\",\n undefined,\n `Error creating document: ${cause.message}`,\n cause,\n ),\n operations: [],\n document: undefined,\n signals: [],\n };\n }\n },\n processJob: async (job: Job) => {\n if (isOperationJob(job)) {\n return this.queueDelegate.processOperationJob(job);\n } else if (isActionJob(job)) {\n return this.queueDelegate.processActionJob(job);\n } else if (isDocumentJob(job)) {\n return this.queueDelegate.processDocumentJob(job);\n } else {\n throw new Error(\"Unknown job type\", job);\n }\n },\n };\n\n // internal state\n private triggerMap = new Map<\n PHDocumentHeader[\"id\"],\n Map<Trigger[\"id\"], CancelPullLoop>\n >();\n private initializePromise: Promise<Error[] | null>;\n protected enableDualActionCreate: boolean;\n\n constructor(\n documentModelModules: DocumentModelModule[],\n storage: IDriveOperationStorage,\n documentStorage: IDocumentStorage,\n cache: ICache,\n queueManager: IQueueManager,\n eventEmitter: IEventEmitter,\n synchronizationManager: ISynchronizationManager,\n listenerManager: IListenerManager,\n options?: DocumentDriveServerOptions,\n ) {\n this.documentModelModules = documentModelModules;\n this.legacyStorage = storage;\n this.documentStorage = documentStorage;\n this.cache = cache;\n this.queueManager = queueManager;\n this.eventEmitter = eventEmitter;\n this.synchronizationManager = synchronizationManager;\n this.listenerManager = listenerManager;\n\n this.options = {\n ...options,\n defaultDrives: {\n ...options?.defaultDrives,\n },\n listenerManager: {\n ...DefaultListenerManagerOptions,\n ...options?.listenerManager,\n },\n jwtHandler:\n options?.jwtHandler === undefined\n ? () => Promise.resolve(\"\")\n : options.jwtHandler,\n taskQueueMethod:\n options?.taskQueueMethod === undefined\n ? runAsap\n : options.taskQueueMethod,\n featureFlags: {\n ...options?.featureFlags,\n },\n };\n\n this.enableDualActionCreate =\n options?.featureFlags?.enableDualActionCreate ?? false;\n if (this.enableDualActionCreate) {\n this.logger.warn(\"Dual action create is enabled.\");\n }\n\n // todo: move to external dependencies\n this.defaultDrivesManager = new DefaultDrivesManager(\n this,\n this.defaultDrivesManagerDelegate,\n options,\n );\n\n this.initializePromise = this._initialize();\n }\n\n // workaround for testing the ephemeral listeners -- we don't have DI in place yet\n // todo: remove this once we have DI\n get listeners(): IListenerManager {\n return this.listenerManager;\n }\n\n initialize() {\n return this.initializePromise;\n }\n\n private async _initialize() {\n await this.listenerManager.initialize(this.handleListenerError.bind(this));\n\n await this.queueManager.init(this.queueDelegate, (error) => {\n this.logger.error(\"Error initializing queue manager: @error\", error);\n // errors.push(error);\n });\n\n try {\n await this.defaultDrivesManager.removeOldremoteDrives();\n } catch (error) {\n this.logger.error(\"@error\", error);\n }\n\n const errors: Error[] = [];\n const drives = await this.getDrives();\n for (const drive of drives) {\n await this._initializeDrive(drive).catch((error) => {\n this.logger.error(\n \"Error initializing drive @drive: @error\",\n drive,\n error,\n );\n errors.push(error as Error);\n });\n }\n\n if (this.options.defaultDrives.loadOnInit !== false) {\n await this.defaultDrivesManager.initializeDefaultRemoteDrives();\n }\n\n return errors.length === 0 ? null : errors;\n }\n\n setDocumentModelModules(modules: DocumentModelModule<any>[]): void {\n this.documentModelModules = [...modules];\n this.synchronizationManager.setDocumentModelModules([...modules]);\n this.eventEmitter.emit(\"documentModelModules\", [...modules]);\n }\n\n initializeDefaultRemoteDrives() {\n return this.defaultDrivesManager.initializeDefaultRemoteDrives();\n }\n\n getDefaultRemoteDrives() {\n return this.defaultDrivesManager.getDefaultRemoteDrives();\n }\n\n setDefaultDriveAccessLevel(url: string, level: RemoteDriveAccessLevel) {\n return this.defaultDrivesManager.setDefaultDriveAccessLevel(url, level);\n }\n\n setAllDefaultDrivesAccessLevel(level: RemoteDriveAccessLevel) {\n return this.defaultDrivesManager.setAllDefaultDrivesAccessLevel(level);\n }\n\n private getOperationSource(source: StrandUpdateSource) {\n return source.type === \"local\" ? \"push\" : \"pull\";\n }\n\n private handleListenerError(\n error: Error,\n driveId: string,\n listener: ListenerState,\n ) {\n this.logger.error(\n \"Listener @listenerId error: @error\",\n listener.listener.label ?? listener.listener.listenerId,\n error,\n );\n\n const status = error instanceof OperationError ? error.status : \"ERROR\";\n\n this.synchronizationManager.updateSyncStatus(\n driveId,\n { push: status },\n error,\n );\n }\n\n private shouldSyncRemoteDrive(drive: DocumentDriveDocument) {\n return (\n drive.state.local.availableOffline &&\n drive.state.local.triggers.length > 0\n );\n }\n\n private async startSyncRemoteDrive(driveId: string) {\n let driveTriggers = this.triggerMap.get(driveId);\n\n const syncUnits =\n await this.synchronizationManager.getSynchronizationUnitsIds(driveId);\n\n const drive = await this.getDrive(driveId);\n for (const trigger of drive.state.local.triggers) {\n if (driveTriggers?.get(trigger.id)) {\n continue;\n }\n\n if (!driveTriggers) {\n driveTriggers = new Map();\n }\n\n this.synchronizationManager.updateSyncStatus(driveId, {\n pull: \"SYNCING\",\n });\n\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(syncUnit, {\n pull: \"SYNCING\",\n });\n }\n\n if (PullResponderTransmitter.isPullResponderTrigger(trigger)) {\n let firstPull = true;\n const cancelPullLoop = PullResponderTransmitter.setupPull(\n driveId,\n trigger,\n this.saveStrand.bind(this),\n (error) => {\n const statusError =\n error instanceof OperationError ? error.status : \"ERROR\";\n\n this.synchronizationManager.updateSyncStatus(\n driveId,\n { pull: statusError },\n error,\n );\n\n if (error instanceof ClientError) {\n this.eventEmitter.emit(\n \"clientStrandsError\",\n driveId,\n trigger,\n error.response.status,\n error.message,\n );\n }\n },\n async (revisions) => {\n const errorRevisions = revisions.filter(\n (r) => r.status !== \"SUCCESS\",\n );\n\n if (errorRevisions.length < 1) {\n this.synchronizationManager.updateSyncStatus(driveId, {\n pull: \"SUCCESS\",\n });\n }\n\n for (const revision of revisions) {\n const { documentId, scope, branch, status, error } = revision;\n this.synchronizationManager.updateSyncStatus(\n { documentId, scope, branch },\n { pull: status },\n error,\n );\n }\n\n // if it is the first pull and returns empty\n // then updates drive documents to \"SUCCESS\" and\n // updates corresponding push transmitter\n if (firstPull) {\n firstPull = false;\n\n const syncUnitsIds =\n await this.synchronizationManager.getSynchronizationUnitsIds(\n driveId,\n );\n const unchangedSyncUnits = syncUnitsIds.filter((syncUnit) => {\n return !revisions.find((revision) => {\n return (\n revision.documentId === syncUnit.documentId &&\n revision.scope === syncUnit.scope &&\n revision.branch === syncUnit.branch\n );\n });\n });\n unchangedSyncUnits.forEach((syncUnit) => {\n this.synchronizationManager.updateSyncStatus(syncUnit, {\n pull: \"SUCCESS\",\n });\n });\n\n const pushListener = drive.state.local.listeners.find(\n (listener) => trigger.data.url === listener.callInfo?.data,\n );\n if (pushListener) {\n for (const revision of revisions) {\n const { documentId, scope, branch } = revision;\n this.listenerManager\n .updateListenerRevision(\n pushListener.listenerId,\n driveId,\n { documentId, scope, branch },\n revision.revision,\n )\n .catch((e) => this.logger.error(\"@error\", e));\n }\n }\n }\n },\n undefined,\n this.listeners,\n );\n driveTriggers.set(trigger.id, cancelPullLoop);\n this.triggerMap.set(driveId, driveTriggers);\n }\n }\n }\n\n private async stopSyncRemoteDrive(driveId: string) {\n const triggers = this.triggerMap.get(driveId);\n triggers?.forEach((cancel) => cancel());\n this.synchronizationManager.updateSyncStatus(driveId, null);\n\n const syncUnits =\n await this.synchronizationManager.getSynchronizationUnitsIds(driveId);\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(syncUnit, null);\n }\n return this.triggerMap.delete(driveId);\n }\n\n private async _initializeDrive(driveId: string) {\n const drive = await this.getDrive(driveId);\n\n this.logger.verbose(\n '[SYNC DEBUG] Initializing drive @driveId with slug \"@slug\"',\n driveId,\n drive.header.slug,\n );\n\n await this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);\n\n if (this.shouldSyncRemoteDrive(drive)) {\n this.logger.verbose(\n \"[SYNC DEBUG] Starting sync for remote drive @driveId\",\n driveId,\n );\n await this.startSyncRemoteDrive(driveId);\n }\n\n // add switchboard push listeners\n this.logger.verbose(\n \"[SYNC DEBUG] Processing @count listeners for drive @driveId\",\n drive.state.local.listeners.length,\n driveId,\n );\n\n for (const zodListener of drive.state.local.listeners) {\n if (zodListener.callInfo?.transmitterType === \"SwitchboardPush\") {\n this.logger.verbose(\n \"[SYNC DEBUG] Setting up SwitchboardPush listener @listenerId for drive @driveId\",\n zodListener.listenerId,\n driveId,\n );\n\n const transmitter = new SwitchboardPushTransmitter(\n zodListener.callInfo.data ?? \"\",\n this.listeners,\n );\n\n this.logger.verbose(\n \"[SYNC DEBUG] Created SwitchboardPush transmitter with URL: @url\",\n zodListener.callInfo.data || \"none\",\n );\n\n await this.listenerManager\n .setListener(driveId, {\n block: zodListener.block,\n driveId: drive.header.id,\n filter: {\n branch: zodListener.filter.branch ?? [],\n documentId: zodListener.filter.documentId ?? [],\n documentType: zodListener.filter.documentType ?? [],\n scope: zodListener.filter.scope ?? [],\n },\n listenerId: zodListener.listenerId,\n callInfo: zodListener.callInfo,\n system: zodListener.system,\n label: zodListener.label ?? \"\",\n transmitter,\n })\n .then(() => {\n this.logger.verbose(\n \"[SYNC DEBUG] Successfully set up listener @listenerId for drive @driveId\",\n zodListener.listenerId,\n driveId,\n );\n });\n } else if (zodListener.callInfo?.transmitterType === \"PullResponder\") {\n this.logger.verbose(\n \"[SYNC DEBUG] Setting up PullResponder listener @listenerId for drive @driveId\",\n zodListener.listenerId,\n driveId,\n );\n\n const pullResponderListener: ServerListener = {\n driveId,\n listenerId: zodListener.listenerId,\n block: false,\n filter: zodListener.filter,\n system: false,\n label: `PullResponder #${zodListener.listenerId}`,\n callInfo: {\n data: \"\",\n name: \"PullResponder\",\n transmitterType: \"PullResponder\",\n },\n };\n\n const pullResponder = new PullResponderTransmitter(\n pullResponderListener,\n this.listenerManager,\n );\n pullResponderListener.transmitter = pullResponder;\n\n await this.listenerManager.setListener(driveId, pullResponderListener);\n } else {\n this.logger.error(\n \"Skipping listener @listenerId with unsupported type @transmitterType\",\n zodListener.listenerId,\n zodListener.callInfo?.transmitterType || \"unknown\",\n );\n }\n }\n }\n\n protected getDocumentModelModule(documentType: string) {\n const documentModelModule = this.documentModelModules.find(\n (module) => module.documentModel.global.id === documentType,\n );\n\n if (!documentModelModule) {\n throw new Error(`Document type ${documentType} not supported`);\n }\n return documentModelModule;\n }\n\n getDocumentModelModules() {\n return [...this.documentModelModules];\n }\n\n addDocument<TDocument extends PHDocument>(\n document: TDocument,\n meta?: PHDocumentMeta,\n ): Promise<TDocument>;\n addDocument<TDocument extends PHDocument>(\n type: string,\n meta?: PHDocumentMeta,\n ): Promise<TDocument>;\n addDocument<TDocument extends PHDocument>(\n documentOrType: TDocument | string,\n meta?: PHDocumentMeta,\n ): Promise<TDocument> {\n const input =\n typeof documentOrType === \"string\"\n ? { documentType: documentOrType }\n : { document: documentOrType };\n return this.createDocument<TDocument>(input, { type: \"local\" }, meta);\n }\n\n async addDrive(\n input: DriveInput,\n preferredEditor?: string,\n ): Promise<DocumentDriveDocument> {\n // Create document with custom global and local state\n const { global } = driveCreateState();\n const document = driveCreateDocument({\n global: {\n ...global,\n name: input.global.name ?? global.name,\n icon: input.global.icon ?? global.icon,\n },\n local: {\n availableOffline: input.local?.availableOffline ?? false,\n sharingType: input.local?.sharingType ?? \"public\",\n listeners: input.local?.listeners ?? [],\n triggers: input.local?.triggers ?? [],\n },\n });\n\n if (input.id && input.id.length > 0) {\n document.header.id = input.id;\n }\n\n if (input.slug && input.slug.length > 0) {\n document.header.slug = input.slug;\n }\n\n if (input.global.name) {\n document.header.name = input.global.name;\n }\n\n const editorToUse = input.preferredEditor || preferredEditor;\n if (editorToUse) {\n document.header.meta = {\n preferredEditor: editorToUse,\n };\n }\n\n await this.documentStorage.create(document);\n\n if (input.slug && input.slug.length > 0) {\n await this.cache.deleteDriveBySlug(input.slug);\n }\n\n await this._initializeDrive(document.header.id);\n\n this.eventEmitter.emit(\"driveAdded\", document);\n\n return document;\n }\n\n async addRemoteDrive(\n url: string,\n options: RemoteDriveOptions,\n ): Promise<DocumentDriveDocument> {\n const token = await this.generateJwtHandler?.(url);\n const headers: Record<string, string> = token\n ? { Authorization: `Bearer ${token}` }\n : {};\n const { id, name, slug, icon, meta } =\n options.expectedDriveInfo ||\n (await requestPublicDriveWithTokenFromReactor(url, this));\n\n const {\n pullFilter,\n pullInterval,\n availableOffline,\n sharingType,\n listeners,\n triggers,\n } = options;\n\n const pullTrigger =\n await PullResponderTransmitter.createPullResponderTrigger(\n id,\n url,\n {\n pullFilter,\n pullInterval,\n },\n this.listeners,\n );\n\n return await this.addDrive(\n {\n id,\n slug,\n global: {\n name,\n icon,\n },\n local: {\n triggers: [...triggers, pullTrigger],\n listeners: listeners,\n availableOffline,\n sharingType,\n },\n },\n meta?.preferredEditor,\n );\n }\n\n async deleteDrive(driveId: string) {\n const result = await Promise.allSettled([\n this.stopSyncRemoteDrive(driveId),\n this.listenerManager.removeDrive(driveId),\n this.cache.deleteDrive(driveId),\n this.documentStorage.delete(driveId),\n ]);\n\n this.eventEmitter.emit(\"driveDeleted\", driveId);\n\n result.forEach((r) => {\n if (r.status === \"rejected\") {\n throw r.reason;\n }\n });\n }\n\n // TODO: paginate\n async getDrives() {\n const drives: string[] = [];\n let cursor: string | undefined;\n do {\n const { documents, nextCursor } = await this.documentStorage.findByType(\n \"powerhouse/document-drive\",\n 100,\n cursor,\n );\n\n drives.push(...documents);\n cursor = nextCursor;\n } while (cursor);\n\n return drives;\n }\n\n // TODO: paginate, move into IReactorClient eventually\n async getDrivesSlugs() {\n const drives = await this.getDrives();\n return this.documentStorage.resolveSlugs(drives);\n }\n\n async getDrive(driveId: string, options?: GetDocumentOptions) {\n let document: DocumentDriveDocument | undefined;\n try {\n const cachedDocument = await this.cache.getDrive(driveId); // TODO support GetDocumentOptions\n if (cachedDocument && isDocumentDrive(cachedDocument)) {\n document = cachedDocument;\n if (isAtRevision(document, options?.revisions)) {\n return document;\n }\n }\n } catch (e) {\n this.logger.error(\"Error getting drive from cache: @error\", e);\n }\n\n const driveStorage = document ?? (await this.documentStorage.get(driveId));\n const result = this._buildDocument(driveStorage, options);\n if (!isDocumentDrive(result)) {\n throw new Error(`Document with id ${driveId} is not a Document Drive`);\n } else {\n if (!options?.revisions) {\n this.cache\n .setDocument(driveId, result)\n .catch((e) => this.logger.error(\"@error\", e));\n this.cache\n .setDrive(driveId, result)\n .catch((e) => this.logger.error(\"@error\", e));\n }\n return result;\n }\n }\n\n async getDriveBySlug(slug: string, options?: GetDocumentOptions) {\n try {\n const drive = await this.cache.getDriveBySlug(slug);\n if (drive) {\n return drive;\n }\n } catch (e) {\n this.logger.error(\"Error getting drive from cache: @error\", e);\n }\n\n const driveStorage = await this.documentStorage.getBySlug(slug);\n const document = this._buildDocument(driveStorage, options);\n if (!isDocumentDrive(document)) {\n throw new Error(`Document with slug ${slug} is not a Document Drive`);\n } else {\n this.cache\n .setDriveBySlug(slug, document)\n .catch((e) => this.logger.error(\"@error\", e));\n return document;\n }\n }\n\n async getDriveIdBySlug(slug: string): Promise<string> {\n try {\n const drive = await this.cache.getDriveBySlug(slug);\n if (drive) {\n return drive.header.id;\n }\n } catch (e) {\n this.logger.error(\"Error getting drive from cache: @error\", e);\n }\n\n const driveStorage = await this.documentStorage.getBySlug(slug);\n return driveStorage.header.id;\n }\n\n getDocument<TDocument extends PHDocument>(\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<TDocument>;\n /**\n * @deprecated Use getDocument(documentId, options) instead. This method will be removed in the future.\n */\n getDocument<TDocument extends PHDocument>(\n driveId: string,\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<TDocument>;\n getDocument<TDocument extends PHDocument>(\n driveId: string,\n documentId?: string | GetDocumentOptions,\n options?: GetDocumentOptions,\n ): Promise<TDocument> {\n const id = typeof documentId === \"string\" ? documentId : driveId;\n const resolvedOptions =\n typeof documentId === \"object\" ? documentId : options;\n return this._getDocument<TDocument>(id, resolvedOptions);\n }\n\n private async _getDocument<TDocument extends PHDocument>(\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<TDocument> {\n let cachedDocument: TDocument | undefined;\n try {\n cachedDocument = await this.cache.getDocument<TDocument>(documentId); // TODO support GetDocumentOptions\n if (cachedDocument && isAtRevision(cachedDocument, options?.revisions)) {\n return cachedDocument;\n }\n } catch (e) {\n this.logger.error(\"Error getting document from cache: @error\", e);\n }\n\n const documentStorage =\n cachedDocument ?? (await this.documentStorage.get<TDocument>(documentId));\n const document = this._buildDocument<TDocument>(documentStorage, options);\n\n if (!options?.revisions) {\n this.cache\n .setDocument(documentId, document)\n .catch((e) => this.logger.error(\"@error\", e));\n }\n\n return document;\n }\n\n getDocuments(driveId: string) {\n return this.documentStorage.getChildren(driveId);\n }\n\n protected async addChild(\n parentId: string,\n documentId: string,\n ): Promise<void> {\n // TODO: check if document exists? Should that be a concern here?\n try {\n await this.documentStorage.addChild(parentId, documentId);\n // TODO: update listener manager?\n } catch (e) {\n this.logger.error(\"Error adding child document: @error\", e);\n throw e;\n }\n }\n\n protected async removeChild(\n parentId: string,\n documentId: string,\n ): Promise<void> {\n // TODO: check if document exists? Should that be a concern here?\n\n // cleanup child sync units state from the parent listeners\n try {\n const childSynUnits =\n await this.synchronizationManager.getSynchronizationUnitsIds(parentId, [\n documentId,\n ]);\n await this.listenerManager.removeSyncUnits(parentId, childSynUnits);\n } catch (e) {\n this.logger.warn(\"Error removing sync units of child: @error\", e);\n }\n\n // remove child relationship from storage\n try {\n await this.documentStorage.removeChild(parentId, documentId);\n } catch (e) {\n this.logger.error(\"Error adding child document: @error\", e);\n throw e;\n }\n }\n\n protected async createDocument<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n source: StrandUpdateSource,\n meta?: PHDocumentMeta,\n ): Promise<TDocument> {\n if (this.enableDualActionCreate) {\n return this.createDocumentDualAction(input, source, meta);\n } else {\n return this.createDocumentLegacy(input, source, meta);\n }\n }\n\n private async createDocumentLegacy<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n source: StrandUpdateSource,\n meta?: PHDocumentMeta,\n ): Promise<TDocument> {\n const { documentType, document: inputDocument } =\n resolveCreateDocumentInput(input);\n\n // if a document was provided then checks if it's valid\n let state = undefined;\n if (inputDocument) {\n if (\n \"documentType\" in input &&\n documentType !== inputDocument.header.documentType\n ) {\n throw new Error(`Provided document is not ${documentType}`);\n }\n\n const doc = this._buildDocument(inputDocument);\n state = doc.state;\n }\n\n // if no document was provided then create a new one\n const document =\n inputDocument ??\n this.getDocumentModelModule(documentType).utils.createDocument(state);\n\n // get the header\n let header: PHDocumentHeader;\n\n // handle the legacy case where an id is provided\n if (\"id\" in input && input.id) {\n if (inputDocument) {\n header = document.header;\n\n document.header.id = input.id;\n\n this.logger.warn(\n \"Assigning an id to a document is deprecated. Use the header field instead.\",\n );\n } else {\n this.logger.warn(\n \"Creating a document with an id is deprecated. Use the header field instead.\",\n );\n\n header = createPresignedHeader(input.id, documentType);\n }\n } else if (\"header\" in input) {\n // validate the header passed in\n await validateHeader(input.header);\n\n header = input.header;\n } else if (inputDocument?.header) {\n if (!inputDocument.header.id) {\n throw new Error(\"Document header id is required\");\n }\n if (!inputDocument.header.documentType) {\n throw new Error(\"Document header documentType is required\");\n }\n if (!inputDocument.header.createdAtUtcIso) {\n throw new Error(\"Document header createdAtUtcIso is required\");\n }\n\n if (!inputDocument.header.sig.nonce) {\n this.logger.warn(\n \"Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.\",\n );\n // throw new Error(\"Document header sig nonce is required\"); TODO: uncomment when ready to enforce signed documents\n } else {\n await validateHeader(inputDocument.header);\n }\n\n header = inputDocument.header;\n } else {\n // otherwise, generate a header\n header = createPresignedHeader(undefined, documentType);\n }\n\n if (meta) {\n header.meta = { ...header.meta, ...meta };\n }\n\n // stores document information\n const documentStorage: PHDocument = {\n header,\n operations: { global: [], local: [] },\n initialState: document.initialState,\n clipboard: [],\n state: state ?? document.state,\n };\n\n await this.documentStorage.create(documentStorage);\n\n // TODO set initial state for document sync units\n // if (source.type === \"trigger\") {\n // for (const scope of Object.keys(document.state)) {\n // this.synchronizationManager.updateSyncStatus(\n // {\n // documentId: document.id,\n // scope,\n // branch: \"main\" /* TODO handle branches */,\n // },\n // {\n // pull: \"INITIAL_SYNC\",\n // push: this.listenerManager.driveHasListeners(driveId)\n // ? \"SUCCESS\"\n // : undefined,\n // },\n // );\n // }\n // }\n\n // if the document contains operations then\n // stores the operations in the storage\n const operations = Object.values(document.operations).flat() as Operation[];\n if (operations.length) {\n if (isDocumentDrive(document)) {\n await this.legacyStorage.addDriveOperations(\n header.id,\n operations,\n document,\n );\n } else {\n await this.legacyStorage.addDocumentOperations(\n header.id,\n operations,\n document,\n );\n }\n }\n\n const addedDocument = await this.getDocument<TDocument>(\n documentStorage.header.id,\n );\n this.eventEmitter.emit(\"documentAdded\", addedDocument);\n return addedDocument;\n }\n\n private async createDocumentDualAction<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n source: StrandUpdateSource,\n meta?: PHDocumentMeta,\n ): Promise<TDocument> {\n const { documentType, document: inputDocument } =\n resolveCreateDocumentInput(input);\n\n // if a document was provided then checks if it's valid\n let state = undefined;\n if (inputDocument) {\n if (\n \"documentType\" in input &&\n documentType !== inputDocument.header.documentType\n ) {\n throw new Error(`Provided document is not ${documentType}`);\n }\n\n const doc = this._buildDocument(inputDocument);\n state = doc.state;\n }\n\n // if no document was provided then create a new one\n const document =\n inputDocument ??\n this.getDocumentModelModule(documentType).utils.createDocument(state);\n\n // get the header\n let header: PHDocumentHeader;\n\n // handle the legacy case where an id is provided\n let isSigned = false;\n if (\"id\" in input && input.id) {\n if (inputDocument) {\n header = document.header;\n\n document.header.id = input.id;\n\n this.logger.warn(\n \"Assigning an id to a document is deprecated. Use the header field instead.\",\n );\n } else {\n this.logger.warn(\n \"Creating a document with an id is deprecated. Use the header field instead.\",\n );\n\n header = createPresignedHeader(input.id, documentType);\n }\n } else if (\"header\" in input) {\n // validate the header passed in\n await validateHeader(input.header);\n isSigned = true;\n\n header = input.header;\n } else if (inputDocument?.header) {\n if (!inputDocument.header.id) {\n throw new Error(\"Document header id is required\");\n }\n if (!inputDocument.header.documentType) {\n throw new Error(\"Document header documentType is required\");\n }\n if (!inputDocument.header.createdAtUtcIso) {\n throw new Error(\"Document header createdAtUtcIso is required\");\n }\n\n if (!inputDocument.header.sig.nonce) {\n this.logger.warn(\n \"Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.\",\n );\n // throw new Error(\"Document header sig nonce is required\"); TODO: uncomment when ready to enforce signed documents\n } else {\n await validateHeader(inputDocument.header);\n isSigned = true;\n }\n\n header = inputDocument.header;\n } else {\n // otherwise, generate a header\n header = createPresignedHeader(undefined, documentType);\n isSigned = false;\n }\n\n if (meta) {\n header.meta = { ...header.meta, ...meta };\n }\n\n const currentVersion = 1;\n\n // Get initial state from input or model's defaultState\n const initialState = state ?? document.state;\n\n // Check if the input document already has operations\n const existingOperations = Object.values(\n document.operations,\n ).flat() as Operation[];\n const shouldCreateOperations = existingOperations.length === 0;\n\n let operations: Operation[] = [];\n\n if (shouldCreateOperations) {\n const timestampUtcMs = new Date().toISOString();\n\n // Determine if this is a signed document\n const signing = isSigned\n ? {\n signature: header.id, // The document ID is the signature\n publicKey: header.sig.publicKey,\n nonce: header.sig.nonce,\n createdAtUtcIso: header.createdAtUtcIso,\n documentType: header.documentType,\n }\n : undefined;\n\n // Create actions for CREATE_DOCUMENT and UPGRADE_DOCUMENT\n const createDocumentInput: CreateDocumentActionInput = {\n model: documentType,\n version: 0,\n documentId: header.id,\n signing,\n };\n\n const createDocumentAction: Action = {\n id: generateId(),\n type: \"CREATE_DOCUMENT\",\n timestampUtcMs,\n input: createDocumentInput,\n scope: \"document\",\n };\n\n const upgradeDocumentInput: UpgradeDocumentActionInput = {\n model: documentType,\n fromVersion: 0,\n toVersion: currentVersion,\n documentId: header.id,\n initialState,\n };\n\n const upgradeDocumentAction: Action = {\n id: generateId(),\n type: \"UPGRADE_DOCUMENT\",\n timestampUtcMs,\n input: upgradeDocumentInput,\n scope: \"document\",\n };\n\n // we need to create hashes for later verification\n const baseState = defaultBaseState();\n const createStateForHash = {\n state: baseState,\n };\n const createHash = hashDocumentStateForScope(\n createStateForHash,\n \"document\",\n );\n\n const upgradeStateForHash = {\n state: initialState,\n };\n const upgradeHash = hashDocumentStateForScope(\n upgradeStateForHash,\n \"document\",\n );\n\n // Create operations from actions with computed hashes\n operations = [\n {\n id: deriveOperationId(\n header.id,\n \"document\",\n \"main\",\n createDocumentAction.id,\n ),\n index: 0,\n skip: 0,\n hash: createHash,\n timestampUtcMs,\n action: createDocumentAction,\n },\n {\n id: deriveOperationId(\n header.id,\n \"document\",\n \"main\",\n upgradeDocumentAction.id,\n ),\n index: 1,\n skip: 0,\n hash: upgradeHash,\n timestampUtcMs,\n action: upgradeDocumentAction,\n },\n ];\n } else {\n // Use existing operations from the input document\n operations = existingOperations;\n }\n\n // Group operations by scope before storing\n const groupedOps = groupOperationsByScope(operations);\n\n // Ensure backward compatibility by initializing missing scopes\n if (!groupedOps.header) {\n groupedOps.header = [];\n }\n if (!groupedOps.document) {\n groupedOps.document = [];\n }\n if (!groupedOps.global) {\n groupedOps.global = [];\n }\n if (!groupedOps.local) {\n groupedOps.local = [];\n }\n\n // After initialization, it's safe to treat as DocumentOperations\n const operationsByScope = groupedOps as DocumentOperations;\n\n // stores document information with operations\n const documentToStore: PHDocument = {\n header,\n operations: operationsByScope,\n initialState,\n clipboard: [],\n state: initialState,\n };\n\n await this.documentStorage.create(documentToStore);\n\n // Force rebuild to ensure operations are properly merged\n const addedDocument = await this.getDocument<TDocument>(\n documentToStore.header.id,\n {\n checkHashes: true,\n },\n );\n this.eventEmitter.emit(\"documentAdded\", addedDocument);\n return addedDocument;\n }\n\n async deleteDocument(documentId: string) {\n try {\n const syncUnits =\n await this.synchronizationManager.getSynchronizationUnitsIds(\n undefined,\n [documentId],\n );\n\n // remove document sync units status when a document is deleted\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(syncUnit, null);\n }\n const parents = await this.documentStorage.getParents(documentId);\n for (const parent of parents) {\n this.listenerManager\n .removeSyncUnits(parent, syncUnits)\n .catch(this.logger.warn);\n }\n } catch (error) {\n this.logger.warn(\"Error deleting document: @error\", error);\n }\n await Promise.allSettled([\n this.cache.deleteDocument(documentId).catch(this.logger.warn),\n this.documentStorage.delete(documentId).catch(this.logger.warn),\n ]);\n this.eventEmitter.emit(\"documentDeleted\", documentId);\n }\n\n async _processOperations(\n documentId: string,\n documentStorage: PHDocument,\n operations: Operation[],\n ) {\n const operationsApplied: Operation[] = [];\n const signals: SignalResult[] = [];\n\n const documentStorageWithState = await this._addDocumentResultingStage(\n documentStorage,\n documentId,\n );\n\n let document = this._buildDocument(documentStorageWithState);\n let error: OperationError | undefined; // TODO: replace with an array of errors/consistency issues\n const operationsByScope = groupOperationsByScope(operations);\n\n for (const scope of Object.keys(operationsByScope)) {\n const storageDocumentOperations = documentStorage.operations[scope] || [];\n\n // TODO two equal operations done by two clients will be considered the same, ie: { type: \"INCREMENT\" }\n const branch = removeExistingOperations(\n operationsByScope[scope] || [],\n storageDocumentOperations,\n );\n\n // No operations to apply\n if (branch.length < 1) {\n continue;\n }\n\n const trunk = garbageCollect(sortOperations(storageDocumentOperations));\n\n const [invertedTrunk, tail] = attachBranch(trunk, branch);\n\n const newHistory =\n tail.length < 1\n ? invertedTrunk\n : merge(trunk, invertedTrunk, reshuffleByTimestamp);\n\n const newOperations = newHistory.filter(\n (op) => trunk.length < 1 || precedes(trunk[trunk.length - 1], op),\n );\n\n for (const nextOperation of newOperations) {\n let skipHashValidation = false;\n\n // when dealing with a merge (tail.length > 0) we have to skip hash validation\n // for the operations that were re-indexed (previous hash becomes invalid due the new position in the history)\n if (tail.length > 0) {\n const sourceOperation = operations.find(\n (op) => op.hash === nextOperation.hash,\n );\n\n skipHashValidation =\n !sourceOperation ||\n sourceOperation.index !== nextOperation.index ||\n sourceOperation.skip !== nextOperation.skip;\n }\n\n try {\n // runs operation on next available tick, to avoid blocking the main thread\n const taskQueueMethod = this.options.taskQueueMethod;\n const task = () =>\n this._performOperation(\n documentId,\n document,\n nextOperation,\n skipHashValidation,\n );\n const appliedResult = await (taskQueueMethod\n ? runAsapAsync(task, taskQueueMethod)\n : task());\n document = appliedResult.document;\n signals.push(...appliedResult.signals);\n operationsApplied.push(appliedResult.operation);\n\n // TODO what to do if one of the applied operations has an error?\n } catch (e) {\n error =\n e instanceof OperationError\n ? e\n : new OperationError(\n \"ERROR\",\n nextOperation,\n (e as Error).message,\n (e as Error).cause,\n );\n\n // TODO: don't break on errors...\n break;\n }\n }\n }\n\n return {\n document,\n operationsApplied,\n signals,\n error,\n } as const;\n }\n\n private async _addDocumentResultingStage(\n document: PHDocument,\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<PHDocument> {\n // apply skip header operations to all scopes\n const operations =\n options?.revisions !== undefined\n ? filterOperationsByRevision(document.operations, options.revisions)\n : document.operations;\n const documentOperations = garbageCollectDocumentOperations(operations);\n\n for (const scope of Object.keys(documentOperations)) {\n const scopeOps = documentOperations[scope];\n if (!scopeOps) {\n continue;\n }\n const lastRemainingOperation = scopeOps.at(-1);\n // if the latest operation doesn't have a resulting state then tries\n // to retrieve it from the db to avoid rerunning all the operations\n if (lastRemainingOperation && !lastRemainingOperation.resultingState) {\n lastRemainingOperation.resultingState = await (isDocumentDrive(document)\n ? this.legacyStorage.getOperationResultingState?.(\n documentId,\n lastRemainingOperation.index,\n lastRemainingOperation.action.scope,\n \"main\",\n )\n : this.legacyStorage.getDriveOperationResultingState?.(\n documentId,\n lastRemainingOperation.index,\n lastRemainingOperation.action.scope,\n \"main\",\n ));\n }\n }\n\n return {\n ...document,\n operations: documentOperations,\n };\n }\n\n private _buildDocument<TDocument extends PHDocument>(\n documentStorage: TDocument,\n options?: GetDocumentOptions,\n ): TDocument {\n if (\n documentStorage.state &&\n (!options || options.checkHashes === false) &&\n isAtRevision(documentStorage, options?.revisions)\n ) {\n return documentStorage;\n }\n\n const documentModelModule = this.getDocumentModelModule(\n documentStorage.header.documentType,\n );\n\n const revisionOperations =\n options?.revisions !== undefined\n ? filterOperationsByRevision(\n documentStorage.operations,\n options.revisions,\n )\n : documentStorage.operations;\n const operations = garbageCollectDocumentOperations(revisionOperations);\n\n // Get all scopes from operations\n const allScopes = Object.keys(operations);\n\n // Initialize with all scopes found in operations, plus global and local for backward compatibility\n const scopesToInitialize = new Set([...allScopes, \"global\", \"local\"]);\n const headerOperations: DocumentOperations = {};\n const operationsToReplay: DocumentOperations = {};\n\n for (const scope of scopesToInitialize) {\n headerOperations[scope] = [];\n operationsToReplay[scope] = [];\n }\n\n // Filter out CREATE_DOCUMENT and UPGRADE_DOCUMENT operations\n // (these don't currently have reducers and should not be replayed)\n for (const [scope, scopeOps] of Object.entries(operations)) {\n if (!scopeOps) {\n continue;\n }\n for (const op of scopeOps) {\n if (\n op.action.type === \"CREATE_DOCUMENT\" ||\n op.action.type === \"UPGRADE_DOCUMENT\"\n ) {\n const headerOps = headerOperations[scope];\n if (headerOps) {\n headerOps.push(op);\n }\n } else {\n const replayOps = operationsToReplay[scope];\n if (replayOps) {\n replayOps.push(op);\n }\n }\n }\n }\n\n // If revisions filter is specified, compute header revision from filtered operations\n // This ensures the returned document's header.revision reflects the requested revision,\n // not the current storage state\n let headerForReplay = documentStorage.header;\n if (options?.revisions) {\n const newRevision: Record<string, number | undefined> = {\n ...documentStorage.header.revision,\n };\n\n // For each scope in the revision filter, compute actual revision from filtered ops\n for (const scope of Object.keys(options.revisions)) {\n const scopeOps = operations[scope] ?? [];\n if (scopeOps.length === 0) {\n // No ops means revision should not exist for this scope\n delete newRevision[scope];\n } else {\n const lastOp = scopeOps.at(-1);\n newRevision[scope] = lastOp ? lastOp.index + 1 : 0;\n }\n }\n\n headerForReplay = {\n ...documentStorage.header,\n revision: newRevision as typeof documentStorage.header.revision,\n };\n }\n\n const replayed = replayDocument(\n documentStorage.initialState,\n operationsToReplay,\n documentModelModule.reducer,\n headerForReplay,\n undefined,\n {},\n {\n ...options,\n checkHashes: options?.checkHashes ?? true,\n reuseOperationResultingState: options?.checkHashes ?? true,\n },\n ) as TDocument;\n\n // merge header operations back into the result\n // Include ALL scopes from input operations, header operations, and replayed operations\n const allScopesForMerge = new Set([\n ...Object.keys(operations), // From input storage\n ...Object.keys(headerOperations),\n ...Object.keys(replayed.operations),\n ]);\n\n const finalOperations: DocumentOperations = {};\n for (const scope of allScopesForMerge) {\n finalOperations[scope] = [\n ...(headerOperations[scope] || []),\n ...(replayed.operations[scope] || []),\n ];\n }\n\n return {\n ...replayed,\n operations: finalOperations,\n clipboard: documentStorage.clipboard ?? [],\n };\n }\n\n private async _performOperation(\n documentId: string,\n document: PHDocument,\n operation: Operation,\n skipHashValidation = false,\n ) {\n const documentModelModule = this.getDocumentModelModule(\n document.header.documentType,\n );\n\n const signalResults: SignalResult[] = [];\n let newDocument = document;\n\n const scope = operation.action.scope;\n const currentScopeOperations = document.operations[scope] || [];\n const documentOperations = garbageCollectDocumentOperations({\n ...document.operations,\n [scope]: skipHeaderOperations(currentScopeOperations, operation),\n });\n\n const remainingScopeOps = documentOperations[scope];\n const lastRemainingOperation = remainingScopeOps?.at(-1);\n // if the latest operation doesn't have a resulting state then tries\n // to retrieve it from the db to avoid rerunning all the operations\n if (lastRemainingOperation && !lastRemainingOperation.resultingState) {\n lastRemainingOperation.resultingState = await (isDocumentDrive(document)\n ? this.legacyStorage.getOperationResultingState?.(\n documentId,\n lastRemainingOperation.index,\n lastRemainingOperation.action.scope,\n \"main\",\n )\n : this.legacyStorage.getDriveOperationResultingState?.(\n documentId,\n lastRemainingOperation.index,\n lastRemainingOperation.action.scope,\n \"main\",\n ));\n }\n\n const operationsBeforeReducer = newDocument.operations[scope] || [];\n\n const operationSignals: (() => Promise<SignalResult>)[] = [];\n newDocument = documentModelModule.reducer(\n newDocument,\n operation.action,\n (signal: Signal) => {\n let handler: (() => Promise<unknown>) | undefined = undefined;\n switch (signal.type) {\n case \"CREATE_CHILD_DOCUMENT\":\n handler = () => this.addChild(documentId, signal.input.id);\n break;\n case \"DELETE_CHILD_DOCUMENT\":\n handler = () => this.removeChild(documentId, signal.input.id);\n break;\n case \"COPY_CHILD_DOCUMENT\":\n handler = () => this.addChild(documentId, signal.input.newId);\n break;\n }\n\n if (handler) {\n operationSignals.push(() =>\n handler().then((result) => ({ signal, result }) as SignalResult),\n );\n }\n },\n {\n skip: operation.skip,\n reuseOperationResultingState: true,\n replayOptions: { operation },\n },\n );\n\n // when we have NOOP operations with skip > 0 we need to populate the\n // clipboard with the operations that were skipped to allow redo\n if (\n operation.action.type === \"NOOP\" &&\n operation.skip > 0 &&\n newDocument.clipboard.length === 0\n ) {\n const scopeOperationsAfter = newDocument.operations[scope] || [];\n\n // Get operations AFTER garbageCollect (with NOOP)\n const afterOperations = garbageCollect(\n sortOperations(scopeOperationsAfter),\n );\n\n // Get operations BEFORE the reducer ran (before NOOP was applied)\n const beforeOperations = garbageCollect(\n sortOperations(operationsBeforeReducer),\n );\n\n // Calculate what was removed by comparing before vs after\n // The diff shows operations that were in \"before\" but not in \"after\"\n const diff = diffOperations(beforeOperations, afterOperations);\n\n // Populate clipboard with skipped operations (excluding NOOPs)\n newDocument = {\n ...newDocument,\n clipboard: sortOperations(\n diff.filter((op: Operation) => op.action.type !== \"NOOP\"),\n ).reverse(),\n };\n }\n\n const newDocScopeOperations =\n newDocument.operations[operation.action.scope];\n if (!newDocScopeOperations) {\n throw new OperationError(\n \"ERROR\",\n operation,\n `No operations found for scope: ${operation.action.scope}`,\n );\n }\n const appliedOperations = newDocScopeOperations.filter(\n (op) => op.index == operation.index && op.skip == operation.skip,\n );\n const appliedOperation = appliedOperations.at(0);\n\n if (!appliedOperation) {\n throw new OperationError(\n \"ERROR\",\n operation,\n `Operation with index ${operation.index}:${operation.skip} was not applied.`,\n );\n }\n if (\n !appliedOperation.error &&\n appliedOperation.hash !== operation.hash &&\n !skipHashValidation\n ) {\n this.logger.warn(\"@appliedOperation\", appliedOperation);\n throw new ConflictOperationError(operation, appliedOperation);\n }\n\n for (const signalHandler of operationSignals) {\n const result = await signalHandler();\n signalResults.push(result);\n }\n\n return {\n document: newDocument,\n signals: signalResults,\n operation: appliedOperation,\n };\n }\n\n addOperation(\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addOperation(documentId, operation, options) instead. This method will be removed in the future.\n */\n addOperation(\n driveId: string,\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n addOperation(\n driveIdOrDocumentId: string,\n documentIdOrOperation: string | Operation,\n operationOrOptions?: Operation | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let operation: Operation;\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrOperation === \"string\") {\n // Deprecated overload: (driveId, documentId, operation, options)\n documentId = documentIdOrOperation;\n operation = operationOrOptions as Operation;\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, operation, options)\n documentId = driveIdOrDocumentId;\n operation = documentIdOrOperation;\n options = operationOrOptions as AddOperationOptions | undefined;\n }\n return this.addOperations(documentId, [operation], options);\n }\n\n private async _addOperations(\n documentId: string,\n callback: (document: PHDocument) => Promise<{\n operations: Operation[];\n document: PHDocument;\n }>,\n ) {\n if (!this.legacyStorage.addDocumentOperationsWithTransaction) {\n const documentStorage =\n await this.documentStorage.get<PHDocument>(documentId);\n const result = await callback(documentStorage);\n // saves the applied operations to storage\n if (result.operations.length > 0) {\n await this.legacyStorage.addDocumentOperations(\n documentId,\n result.operations,\n result.document,\n );\n }\n } else {\n await this.legacyStorage.addDocumentOperationsWithTransaction(\n documentId,\n callback,\n );\n }\n }\n\n async queueDocument<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n options?: AddOperationOptions,\n ): Promise<IOperationResult> {\n const { id, documentType, document } = resolveCreateDocumentInput(input);\n if (!id) {\n throw new Error(\"Document id is required\", { cause: input });\n }\n if (!documentType) {\n throw new Error(\"Document type is required\", { cause: input });\n }\n\n const exists = await this.documentStorage.exists(id);\n if (exists) {\n throw new DocumentAlreadyExistsError(id);\n }\n\n // add listeners first\n let jobId: string;\n const promise = new Promise<IOperationResult>((resolve, reject) => {\n const unsubscribe = this.queueManager.on(\n \"jobCompleted\",\n (job, result) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n resolve(result);\n }\n },\n );\n const unsubscribeError = this.queueManager.on(\n \"jobFailed\",\n (job, error) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n reject(error);\n }\n },\n );\n });\n\n // now queue the job\n try {\n jobId = await this.queueManager.addJob({\n documentId: id,\n documentType,\n initialState: document?.state,\n header: document?.header,\n options,\n });\n } catch (error) {\n this.logger.error(\"Error adding job: @error\", error);\n throw error;\n }\n\n return promise;\n }\n\n queueOperation(\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueOperation(documentId, operation, options) instead. This method will be removed in the future.\n */\n queueOperation(\n driveId: string,\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n queueOperation(\n driveIdOrDocumentId: string,\n documentIdOrOperation: string | Operation,\n operationOrOptions?: Operation | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let operation: Operation;\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrOperation === \"string\") {\n // Deprecated overload: (driveId, documentId, operation, options)\n documentId = documentIdOrOperation;\n operation = operationOrOptions as Operation;\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, operation, options)\n documentId = driveIdOrDocumentId;\n operation = documentIdOrOperation;\n options = operationOrOptions as AddOperationOptions | undefined;\n }\n return this._queueOperations(documentId, [operation], options);\n }\n\n private async resultIfExistingOperations(\n id: string,\n operations: Operation[],\n ): Promise<IOperationResult | undefined> {\n try {\n const document = await this.getDocument(id);\n const newOperation = operations.find((op) => {\n if (!op.id) {\n return true;\n }\n const scopeOps = document.operations[op.action.scope];\n if (!scopeOps) {\n return true;\n }\n return !scopeOps.find(\n (existingOp: Operation) =>\n existingOp.id === op.id &&\n existingOp.index === op.index &&\n existingOp.action.type === op.action.type &&\n existingOp.hash === op.hash,\n );\n });\n if (!newOperation) {\n return {\n status: \"SUCCESS\",\n document,\n operations,\n signals: [],\n };\n } else {\n return undefined;\n }\n } catch (error) {\n if (\n !(error as Error).message.includes(`Document with id ${id} not found`)\n ) {\n console.error(error);\n }\n return undefined;\n }\n }\n\n queueOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueOperations(documentId, operations, options) instead. This method will be removed in the future.\n */\n queueOperations(\n driveId: string,\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n queueOperations(\n driveIdOrDocumentId: string,\n documentIdOrOperations: string | Operation[],\n operationsOrOptions?: Operation[] | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let operations: Operation[];\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrOperations === \"string\") {\n // Deprecated overload: (driveId, documentId, operations, options)\n documentId = documentIdOrOperations;\n operations = operationsOrOptions as Operation[];\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, operations, options)\n documentId = driveIdOrDocumentId;\n operations = documentIdOrOperations;\n options = operationsOrOptions as AddOperationOptions | undefined;\n }\n return this._queueOperations(documentId, operations, options);\n }\n\n private async _queueOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ) {\n // if operations are already stored then returns cached document\n const result = await this.resultIfExistingOperations(\n documentId,\n operations,\n );\n if (result) {\n return result;\n }\n\n // add listeners first\n let jobId: string;\n const promise = new Promise<IOperationResult>((resolve, reject) => {\n const unsubscribe = this.queueManager.on(\n \"jobCompleted\",\n (job, result) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n resolve(result);\n }\n },\n );\n const unsubscribeError = this.queueManager.on(\n \"jobFailed\",\n (job, error) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n reject(error);\n }\n },\n );\n });\n\n // now queue the job\n try {\n jobId = await this.queueManager.addJob({\n documentId,\n operations,\n options,\n });\n } catch (error) {\n this.logger.error(\"Error adding job: @error\", error);\n throw error;\n }\n\n return promise;\n }\n\n queueAction(\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueAction(documentId, action, options) instead. This method will be removed in the future.\n */\n queueAction(\n driveId: string,\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n queueAction(\n driveIdOrDocumentId: string,\n documentIdOrAction: string | Action,\n actionOrOptions?: Action | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let action: Action;\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrAction === \"string\") {\n // Deprecated overload: (driveId, documentId, action, options)\n documentId = documentIdOrAction;\n action = actionOrOptions as Action;\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, action, options)\n documentId = driveIdOrDocumentId;\n action = documentIdOrAction;\n options = actionOrOptions as AddOperationOptions | undefined;\n }\n return this._queueActions(documentId, [action], options);\n }\n\n queueActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueActions(documentId, actions, options) instead. This method will be removed in the future.\n */\n queueActions(\n driveId: string,\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n queueActions(\n driveIdOrDocumentId: string,\n documentIdOrActions: string | Action[],\n actionsOrOptions?: Action[] | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let actions: Action[];\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrActions === \"string\") {\n // Deprecated overload: (driveId, documentId, actions, options)\n documentId = documentIdOrActions;\n actions = actionsOrOptions as Action[];\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, actions, options)\n documentId = driveIdOrDocumentId;\n actions = documentIdOrActions;\n options = actionsOrOptions as AddOperationOptions | undefined;\n }\n return this._queueActions(documentId, actions, options);\n }\n\n private async _queueActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult> {\n try {\n const jobId = await this.queueManager.addJob({\n documentId,\n actions,\n options,\n });\n\n return await new Promise<IOperationResult>((resolve, reject) => {\n const unsubscribe = this.queueManager.on(\n \"jobCompleted\",\n (job, result) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n resolve(result);\n }\n },\n );\n const unsubscribeError = this.queueManager.on(\n \"jobFailed\",\n (job, error) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n reject(error);\n }\n },\n );\n });\n } catch (error) {\n this.logger.error(\"Error adding job: @error\", error);\n throw error;\n }\n }\n\n /**\n * @deprecated Use the {@link queueAction} method instead.\n */\n async queueDriveAction(\n driveId: string,\n action: DocumentDriveAction | Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult<DocumentDriveDocument>> {\n return this.queueDriveActions(driveId, [action], options);\n }\n\n /**\n * @deprecated Use the {@link queueActions} method instead.\n */\n async queueDriveActions(\n driveId: string,\n actions: (DocumentDriveAction | Action)[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult<DocumentDriveDocument>> {\n try {\n const jobId = await this.queueManager.addJob({\n documentId: driveId,\n actions,\n options,\n });\n return await new Promise<IOperationResult<DocumentDriveDocument>>(\n (resolve, reject) => {\n const unsubscribe = this.queueManager.on(\n \"jobCompleted\",\n (job, result) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n resolve(result as IOperationResult<DocumentDriveDocument>);\n }\n },\n );\n const unsubscribeError = this.queueManager.on(\n \"jobFailed\",\n (job, error) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n reject(error);\n }\n },\n );\n },\n );\n } catch (error) {\n this.logger.error(\"Error adding drive job: @error\", error);\n throw error;\n }\n }\n\n addOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addOperations(documentId, operations, options) instead. This method will be removed in the future.\n */\n addOperations(\n driveId: string,\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n addOperations(\n driveIdOrDocumentId: string,\n documentIdOrOperations: string | Operation[],\n operationsOrOptions?: Operation[] | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let operations: Operation[];\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrOperations === \"string\") {\n // Deprecated overload: (driveId, documentId, operations, options)\n documentId = documentIdOrOperations;\n operations = operationsOrOptions as Operation[];\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, operations, options)\n documentId = driveIdOrDocumentId;\n operations = documentIdOrOperations;\n options = operationsOrOptions as AddOperationOptions | undefined;\n }\n return this._queueOperations(documentId, operations, options);\n }\n\n private async processOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult> {\n // if operations are already stored then returns the result\n const result = await this.resultIfExistingOperations(\n documentId,\n operations,\n );\n if (result) {\n return result;\n }\n let document: PHDocument | undefined;\n const operationsApplied: Operation[] = [];\n const signals: SignalResult[] = [];\n let error: Error | undefined;\n\n try {\n await this._addOperations(documentId, async (documentStorage) => {\n const result = await this._processOperations(\n documentId,\n documentStorage,\n operations,\n );\n\n if (!result.document) {\n this.logger.error(\"Invalid document\");\n throw result.error ?? new Error(\"Invalid document\");\n }\n\n document = result.document;\n error = result.error;\n signals.push(...result.signals);\n operationsApplied.push(...result.operationsApplied);\n\n return {\n operations: result.operationsApplied,\n document: result.document,\n };\n });\n\n const syncUnits = new Array<SynchronizationUnit>();\n\n if (document) {\n this.cache\n .setDocument(documentId, document)\n .catch((e) => this.logger.error(\"@error\", e));\n\n // creates array of unique sync units from the applied operations\n for (const operation of operationsApplied) {\n const syncUnit: SynchronizationUnit = {\n documentId,\n documentType: document.header.documentType,\n scope: operation.action.scope,\n branch: \"main\", // TODO: handle branches\n revision: operation.index + 1,\n lastUpdated: operation.timestampUtcMs,\n };\n\n // checks if this sync unit was already added\n const exists = syncUnits.some(\n (unit) =>\n unit.documentId === syncUnit.documentId &&\n unit.scope === syncUnit.scope &&\n unit.branch === syncUnit.branch,\n );\n\n if (!exists) {\n syncUnits.push(syncUnit);\n }\n }\n }\n // checks if any of the provided operations where reshufled\n const newOp = operationsApplied.find(\n (appliedOp) =>\n !operations.find(\n (o) =>\n o.id === appliedOp.id &&\n o.index === appliedOp.index &&\n o.skip === appliedOp.skip &&\n o.hash === appliedOp.hash,\n ),\n );\n\n // if there are no new operations then reuses the provided source\n // otherwise sets it to local so listeners know that there were\n // new changes originating from this document drive server\n const source: StrandUpdateSource = newOp\n ? { type: \"local\" }\n : (options?.source ?? { type: \"local\" });\n\n // update listener cache\n const operationSource = this.getOperationSource(source);\n\n // TODO Decouple the operation processing from syncing it to the listeners?\n // Listener manager should be the one keeping the sync status since it depends on the listeners\n if (syncUnits.length) {\n this.listenerManager\n .updateSynchronizationRevisions(\n syncUnits,\n source,\n () => {\n this.synchronizationManager.updateSyncStatus(documentId, {\n [operationSource]: \"SYNCING\",\n });\n\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(syncUnit, {\n [operationSource]: \"SYNCING\",\n });\n }\n },\n this.handleListenerError.bind(this),\n options?.forceSync ?? source.type === \"local\",\n )\n .then((updates) => {\n if (updates.length) {\n this.synchronizationManager.updateSyncStatus(documentId, {\n [operationSource]: \"SUCCESS\",\n });\n }\n\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(syncUnit, {\n [operationSource]: \"SUCCESS\",\n });\n }\n })\n .catch((error) => {\n this.logger.error(\n \"Non handled error updating sync revision: @error\",\n error,\n );\n this.synchronizationManager.updateSyncStatus(\n documentId,\n {\n [operationSource]: \"ERROR\",\n },\n error as Error,\n );\n\n for (const syncUnit of syncUnits) {\n this.synchronizationManager.updateSyncStatus(\n syncUnit,\n {\n [operationSource]: \"ERROR\",\n },\n error as Error,\n );\n }\n });\n }\n\n // after applying all the valid operations,throws\n // an error if there was an invalid operation\n if (error) {\n throw error;\n }\n\n this.eventEmitter.emit(\"documentOperationsAdded\", documentId, operations);\n\n this.eventEmitter.emit(\"operationsAdded\", documentId, operations);\n\n return {\n status: \"SUCCESS\",\n document,\n operations: operationsApplied,\n signals,\n } satisfies IOperationResult;\n } catch (error) {\n const operationError =\n error instanceof OperationError\n ? error\n : new OperationError(\n \"ERROR\",\n undefined,\n (error as Error).message,\n (error as Error).cause,\n );\n\n return {\n status: operationError.status,\n error: operationError,\n document,\n operations: operationsApplied,\n signals,\n } satisfies IOperationResult;\n }\n }\n\n /**\n * @deprecated Use the {@link addOperation} method instead.\n */\n addDriveOperation(\n driveId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n return this.addDriveOperations(driveId, [operation], options);\n }\n\n private async _addDriveOperations(\n driveId: string,\n callback: (document: DocumentDriveDocument) => Promise<{\n operations: Operation[];\n document: PHDocument;\n }>,\n ) {\n if (!this.legacyStorage.addDriveOperationsWithTransaction) {\n const documentStorage =\n await this.documentStorage.get<DocumentDriveDocument>(driveId);\n const result = await callback(documentStorage);\n // saves the applied operations to storage\n if (result.operations.length > 0) {\n await this.legacyStorage.addDriveOperations(\n driveId,\n result.operations,\n result.document,\n );\n }\n return result;\n } else {\n return this.legacyStorage.addDriveOperationsWithTransaction(\n driveId,\n callback,\n );\n }\n }\n\n /**\n * @deprecated Use the {@link queueOperation} method instead.\n */\n queueDriveOperation(\n driveId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n return this.queueDriveOperations(driveId, [operation], options);\n }\n\n private async resultIfExistingDriveOperations(\n driveId: string,\n operations: Operation[],\n ): Promise<DriveOperationResult | undefined> {\n try {\n const drive = await this.getDrive(driveId);\n const newOperation = operations.find((op) => {\n if (!op.id) {\n return true;\n }\n const scopeOps = drive.operations[op.action.scope];\n if (!scopeOps) {\n return true;\n }\n return !scopeOps.find(\n (existingOp: Operation) =>\n existingOp.id === op.id &&\n existingOp.index === op.index &&\n existingOp.action.type === op.action.type &&\n existingOp.hash === op.hash,\n );\n });\n if (!newOperation) {\n return {\n status: \"SUCCESS\",\n document: drive,\n operations: operations,\n signals: [],\n } as DriveOperationResult;\n } else {\n return undefined;\n }\n } catch (error) {\n console.error(error); // TODO error\n return undefined;\n }\n }\n\n /**\n * @deprecated Use the {@link queueOperations} method instead.\n */\n async queueDriveOperations(\n driveId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n // if operations are already stored then returns cached document\n const result = await this.resultIfExistingDriveOperations(\n driveId,\n operations,\n );\n if (result) {\n return result;\n }\n try {\n const jobId = await this.queueManager.addJob({\n documentId: driveId,\n operations,\n options,\n });\n return await new Promise<DriveOperationResult>((resolve, reject) => {\n const unsubscribe = this.queueManager.on(\n \"jobCompleted\",\n (job, result) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n resolve(result as DriveOperationResult);\n }\n },\n );\n const unsubscribeError = this.queueManager.on(\n \"jobFailed\",\n (job, error) => {\n if (job.jobId === jobId) {\n unsubscribe();\n unsubscribeError();\n reject(error);\n }\n },\n );\n });\n } catch (error) {\n this.logger.error(\"Error adding drive job: @error\", error);\n throw error;\n }\n }\n\n /**\n * @deprecated Use the {@link addOperations} method instead.\n */\n async addDriveOperations(\n driveId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n return this.queueDriveOperations(driveId, operations, options);\n }\n\n private async processDriveOperations(\n driveId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n let document: DocumentDriveDocument | undefined;\n const operationsApplied: Operation[] = [];\n const signals: SignalResult[] = [];\n let error: Error | undefined;\n\n // if operations are already stored then returns cached drive\n const result = await this.resultIfExistingDriveOperations(\n driveId,\n operations,\n );\n if (result) {\n return result;\n }\n\n try {\n await this._addDriveOperations(driveId, async (documentStorage) => {\n const result = await this._processOperations(\n driveId,\n documentStorage,\n operations.slice(),\n );\n document = result.document as DocumentDriveDocument;\n operationsApplied.push(...result.operationsApplied);\n signals.push(...result.signals);\n error = result.error;\n\n return {\n operations: result.operationsApplied,\n document: result.document,\n };\n });\n\n if (!document || !isDocumentDrive(document)) {\n throw error ?? new Error(\"Invalid Document Drive document\");\n }\n\n this.cache\n .setDocument(driveId, document)\n .catch((e) => this.logger.error(\"@error\", e));\n this.cache\n .setDrive(driveId, document)\n .catch((e) => this.logger.error(\"@error\", e));\n\n // update listener cache\n const lastOperation = operationsApplied\n .filter((op) => op.action.scope === \"global\")\n .slice()\n .pop();\n\n if (lastOperation) {\n // checks if any of the provided operations where reshufled\n const newOp = operationsApplied.find(\n (appliedOp) =>\n !operations.find(\n (o) =>\n o.id === appliedOp.id &&\n o.index === appliedOp.index &&\n o.skip === appliedOp.skip &&\n o.hash === appliedOp.hash,\n ),\n );\n\n // if there are no new operations then reuses the provided source\n // otherwise sets it to local so listeners know that there were\n // new changes originating from this document drive server\n const source: StrandUpdateSource = newOp\n ? { type: \"local\" }\n : (options?.source ?? { type: \"local\" });\n\n const operationSource = this.getOperationSource(source);\n\n this.listenerManager\n .updateSynchronizationRevisions(\n [\n {\n documentId: driveId,\n documentType: document.header.documentType,\n scope: \"global\",\n branch: \"main\",\n lastUpdated: lastOperation.timestampUtcMs,\n revision: lastOperation.index,\n },\n ],\n source,\n () => {\n this.synchronizationManager.updateSyncStatus(driveId, {\n [operationSource]: \"SYNCING\",\n });\n },\n this.handleListenerError.bind(this),\n options?.forceSync ?? source.type === \"local\",\n )\n .then((updates) => {\n if (updates.length) {\n this.synchronizationManager.updateSyncStatus(driveId, {\n [operationSource]: \"SUCCESS\",\n });\n }\n })\n .catch((error) => {\n this.logger.error(\n \"Non handled error updating sync revision: @error\",\n error,\n );\n this.synchronizationManager.updateSyncStatus(\n driveId,\n {\n [operationSource]: \"ERROR\",\n },\n error as Error,\n );\n });\n }\n\n if (this.shouldSyncRemoteDrive(document)) {\n this.startSyncRemoteDrive(driveId).catch((e) =>\n this.logger.error(\"@error\", e),\n );\n } else {\n this.stopSyncRemoteDrive(driveId).catch((e) =>\n this.logger.error(\"@error\", e),\n );\n }\n\n // after applying all the valid operations,throws\n // an error if there was an invalid operation\n if (error) {\n throw error;\n }\n\n this.eventEmitter.emit(\"driveOperationsAdded\", driveId, operations);\n this.eventEmitter.emit(\"operationsAdded\", driveId, operations);\n\n return {\n status: \"SUCCESS\",\n document,\n operations: operationsApplied,\n signals,\n } satisfies DriveOperationResult;\n } catch (error) {\n const operationError =\n error instanceof OperationError\n ? error\n : new OperationError(\n \"ERROR\",\n undefined,\n (error as Error).message,\n error,\n );\n\n return {\n status: operationError.status,\n error: operationError,\n document,\n operations: operationsApplied,\n signals,\n } satisfies IOperationResult;\n }\n }\n\n private _buildOperations<TAction extends Action = Action>(\n documentId: PHDocument,\n actions: TAction[],\n ): Operation[] {\n const operations: Operation[] = [];\n const { reducer } = this.getDocumentModelModule(\n documentId.header.documentType,\n );\n for (const action of actions) {\n documentId = reducer(documentId, action);\n const scopeOps = documentId.operations[action.scope];\n if (!scopeOps) {\n throw new Error(`No operations found for scope: ${action.scope}`);\n }\n const operation = scopeOps.slice().pop();\n if (!operation) {\n throw new Error(\"Error creating operations\");\n }\n operations.push(operation);\n }\n return operations;\n }\n\n addAction(\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addAction(documentId, action, options) instead. This method will be removed in the future.\n */\n addAction(\n driveId: string,\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n addAction(\n driveIdOrDocumentId: string,\n documentIdOrAction: string | Action,\n actionOrOptions?: Action | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let action: Action;\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrAction === \"string\") {\n // Deprecated overload: (driveId, documentId, action, options)\n documentId = documentIdOrAction;\n action = actionOrOptions as Action;\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, action, options)\n documentId = driveIdOrDocumentId;\n action = documentIdOrAction;\n options = actionOrOptions as AddOperationOptions | undefined;\n }\n return this._addAction(documentId, action, options);\n }\n\n private async _addAction(\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult> {\n return this.addActions(documentId, [action], options);\n }\n\n addActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addActions(documentId, actions, options) instead. This method will be removed in the future.\n */\n addActions(\n driveId: string,\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n addActions(\n driveIdOrDocumentId: string,\n documentIdOrActions: string | Action[],\n actionsOrOptions?: Action[] | AddOperationOptions,\n maybeOptions?: AddOperationOptions,\n ): Promise<IOperationResult> {\n let documentId: string;\n let actions: Action[];\n let options: AddOperationOptions | undefined;\n\n if (typeof documentIdOrActions === \"string\") {\n // Deprecated overload: (driveId, documentId, actions, options)\n documentId = documentIdOrActions;\n actions = actionsOrOptions as Action[];\n options = maybeOptions;\n } else {\n // Standard overload: (documentId, actions, options)\n documentId = driveIdOrDocumentId;\n actions = documentIdOrActions;\n options = actionsOrOptions as AddOperationOptions | undefined;\n }\n return this._queueActions(documentId, actions, options);\n }\n\n private async processActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult> {\n const document = await this.getDocument(documentId);\n const operations = this._buildOperations(document, actions);\n return this.processOperations(documentId, operations, options);\n }\n\n /**\n * @deprecated Use the {@link addAction} method instead with a {@link AddFileAction} and call {@link addDocument} if the document needs to be created.\n */\n /**\n * @deprecated Use the {@link addAction} method instead with a {@link AddFileAction} and call {@link addDocument} if the document needs to be created.\n */\n async addDriveAction(\n driveId: string,\n action: LegacyAddFileAction,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n /**\n * @deprecated Use the {@link addAction} method instead.\n */\n async addDriveAction(\n driveId: string,\n\n action: DocumentDriveAction | Action,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n /**\n * @deprecated Use the {@link addAction} method instead.\n */\n async addDriveAction(\n driveId: string,\n\n action: LegacyAddFileAction | DocumentDriveAction | Action,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n if (\"synchronizationUnits\" in (action as LegacyAddFileAction).input) {\n return this._legacyAddFileAction(\n driveId,\n action as LegacyAddFileAction,\n options,\n );\n }\n\n return this.addDriveActions(driveId, [action], options);\n }\n\n private async _legacyAddFileAction(\n driveId: string,\n action: LegacyAddFileAction,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n // create document before adding it to the drive\n const document = this.getDocumentModelModule(\n action.input.documentType,\n ).utils.createDocument(action.input.document?.state || undefined);\n document.header.id = action.input.id;\n document.header.name = action.input.name;\n document.header.documentType = action.input.documentType;\n await this.queueDocument(\n { document },\n { source: options?.source || { type: \"local\" } },\n );\n\n // create updated version of the ADD_FILE action\n const newAction: AddFileAction = {\n ...action,\n input: {\n id: action.input.id,\n documentType: document.header.documentType,\n name: action.input.name,\n parentFolder: action.input.parentFolder,\n },\n };\n return (await this.addAction(\n driveId,\n newAction,\n options,\n )) as IOperationResult<DocumentDriveDocument>;\n }\n\n /**\n * @deprecated Use the {@link addActions} method instead.\n */\n async addDriveActions(\n driveId: string,\n actions: (DocumentDriveAction | Action)[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n return this.queueDriveActions(driveId, actions, options);\n }\n\n private async processDriveActions(\n driveId: string,\n actions: (DocumentDriveAction | Action)[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult> {\n const document = await this.getDrive(driveId);\n const operations = this._buildOperations(document, actions);\n return this.processDriveOperations(driveId, operations, options);\n }\n\n async detachDrive(driveId: string) {\n const documentDrive = await this.getDrive(driveId);\n const listeners = documentDrive.state.local.listeners || [];\n const triggers = documentDrive.state.local.triggers || [];\n\n for (const listener of listeners) {\n await this.addDriveAction(\n driveId,\n removeListener({ listenerId: listener.listenerId }),\n );\n }\n\n for (const trigger of triggers) {\n await this.addDriveAction(\n driveId,\n removeTrigger({ triggerId: trigger.id }),\n );\n }\n\n await this.addDriveAction(driveId, setSharingType({ type: \"LOCAL\" }));\n }\n\n getSyncStatus(\n documentId: string,\n scope?: string,\n branch?: string,\n ): SyncStatus | SynchronizationUnitNotFoundError {\n return this.synchronizationManager.getSyncStatus(documentId, scope, branch);\n }\n\n on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe {\n return this.eventEmitter.on(event, cb);\n }\n\n private emit<K extends keyof DriveEvents>(\n event: K,\n ...args: Parameters<DriveEvents[K]>\n ): void {\n return this.eventEmitter.emit(event, ...args);\n }\n\n // Add delegated methods to properly implement ISynchronizationManager\n updateSyncStatus(\n syncUnitId: string,\n status: Partial<SyncUnitStatusObject> | null,\n error?: Error,\n ): void {\n this.synchronizationManager.updateSyncStatus(syncUnitId, status, error);\n }\n\n initializeDriveSyncStatus(\n driveId: string,\n drive: DocumentDriveDocument,\n ): Promise<void> {\n return this.synchronizationManager.initializeDriveSyncStatus(\n driveId,\n drive,\n );\n }\n\n getCombinedSyncUnitStatus(syncUnitStatus: SyncUnitStatusObject): SyncStatus {\n return this.synchronizationManager.getCombinedSyncUnitStatus(\n syncUnitStatus,\n );\n }\n\n // Add back the saveStrand method that was accidentally removed\n private async saveStrand(\n strand: StrandUpdate,\n source: StrandUpdateSource,\n ): Promise<IOperationResult> {\n const isNewDocument = !(await this.documentStorage.exists(\n strand.documentId,\n ));\n\n let result: IOperationResult | undefined = undefined;\n\n if (isNewDocument) {\n result = await this.queueDocument({\n id: strand.documentId,\n documentType: strand.documentType,\n });\n }\n\n const operations: Operation[] = strand.operations.map(\n (op: OperationUpdate) => ({\n ...op,\n id:\n op.id ??\n deriveOperationId(\n strand.documentId,\n strand.scope,\n strand.branch,\n op.actionId,\n ),\n action: {\n id: op.actionId,\n timestampUtcMs: op.timestampUtcMs,\n type: op.type,\n input: op.input,\n context: op.context,\n scope: strand.scope,\n },\n scope: strand.scope,\n branch: strand.branch,\n }),\n );\n\n // if document already existed or queueDocument\n // was successful, queues the operations\n if ((!isNewDocument || result?.status === \"SUCCESS\") && operations.length) {\n try {\n result = await this.queueOperations(strand.documentId, operations, {\n source,\n });\n } catch (error) {\n this.logger.error(\"Error queueing operations: @error\", error);\n throw error;\n }\n }\n\n if (!result) {\n this.logger.debug(\n \"Document @documentId already exists\",\n strand.documentId,\n );\n return {\n status: \"SUCCESS\",\n document: await this.getDocument(strand.documentId),\n operations: [],\n signals: [],\n } satisfies IOperationResult;\n }\n\n if (result.status === \"ERROR\") {\n const operationSource = this.getOperationSource(source);\n this.synchronizationManager.updateSyncStatus(\n {\n documentId: strand.documentId || strand.driveId,\n scope: strand.scope,\n branch: strand.branch,\n },\n { [operationSource]: result.status },\n result.error,\n );\n }\n this.eventEmitter.emit(\"strandUpdate\", strand);\n return result;\n }\n\n setGenerateJwtHandler(handler: (driveUrl: string) => Promise<string>) {\n this.generateJwtHandler = handler;\n this.listenerManager.setGenerateJwtHandler(handler);\n }\n\n removeJwtHandler() {\n this.generateJwtHandler = undefined;\n this.listenerManager.removeJwtHandler();\n }\n}\n\nexport const DocumentDriveServer = ReadModeServer(BaseDocumentDriveServer);\n","import type {\n IStorageUnitFilter,\n ResolvedStorageUnitFilter,\n} from \"document-drive\";\n\nexport const resolveStorageUnitsFilterComponent = (\n component: string[] | undefined,\n) => {\n return component && component.length > 0 && !component.includes(\"*\")\n ? new Set(component)\n : null;\n};\n\nexport const resolveStorageUnitsFilter = (\n filter: IStorageUnitFilter,\n): ResolvedStorageUnitFilter => {\n return {\n parentId: resolveStorageUnitsFilterComponent(filter.parentId),\n documentId: resolveStorageUnitsFilterComponent(filter.documentId),\n documentModelType: resolveStorageUnitsFilterComponent(\n filter.documentModelType,\n ),\n scope: resolveStorageUnitsFilterComponent(filter.scope),\n branch: resolveStorageUnitsFilterComponent(filter.branch),\n };\n};\n\nexport const setUnion = <T>(\n base: Set<T>,\n ...iterables: Iterable<T>[]\n): Set<T> => {\n const result = new Set(base);\n for (const iterable of iterables) {\n for (const value of iterable) {\n result.add(value);\n }\n }\n return result;\n};\n\nexport const setIntersection = <T>(left: Set<T>, right: Set<T>): Set<T> => {\n const result = new Set<T>();\n for (const value of left) {\n if (right.has(value)) {\n result.add(value);\n }\n }\n return result;\n};\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n Operation,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport type {\n IDocumentAdminStorage,\n IDocumentStorage,\n IDriveOperationStorage,\n IStorageUnit,\n IStorageUnitFilter,\n SynchronizationUnitQuery,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport LocalForage from \"localforage\";\nimport {\n DocumentAlreadyExistsError,\n DocumentAlreadyExistsReason,\n DocumentNotFoundError,\n} from \"server\";\nimport {\n AbortError,\n mergeOperations,\n migrateDocumentOperationSignatures,\n operationsToRevision,\n} from \"utils\";\nimport {\n resolveStorageUnitsFilter,\n setIntersection,\n setUnion,\n} from \"./utils.js\";\n\n// Interface for drive manifest that tracks document IDs in a drive\ninterface DriveManifest {\n documentIds: string[];\n}\n\n// Interface for slug manifest that maps slugs to document IDs\ninterface SlugManifest {\n slugToId: Record<string, string>;\n}\n\nexport class BrowserStorage\n implements IDriveOperationStorage, IDocumentStorage, IDocumentAdminStorage\n{\n private logger = childLogger([\"BrowserStorage\"]);\n private db: Promise<LocalForage>;\n\n static DBName = \"DOCUMENT_DRIVES\";\n static SEP = \":\";\n static DOCUMENT_KEY = \"DOCUMENT\";\n static MANIFEST_KEY = \"MANIFEST\";\n static SLUG_MANIFEST_KEY = \"SLUG_MANIFEST\";\n\n constructor(namespace?: string) {\n this.db = LocalForage.ready().then(() =>\n LocalForage.createInstance({\n name: namespace\n ? `${namespace}:${BrowserStorage.DBName}`\n : BrowserStorage.DBName,\n }),\n );\n }\n\n ////////////////////////////////\n // IStorageUnitStorage\n ////////////////////////////////\n\n async findStorageUnitsBy(\n filter: IStorageUnitFilter,\n limit: number,\n cursor?: string,\n ): Promise<{ units: IStorageUnit[]; nextCursor?: string }> {\n const storageUnits: IStorageUnit[] = [];\n\n const {\n parentId: parentIds,\n documentId: documentIds,\n documentModelType: documentTypes,\n scope: scopes,\n branch: branches,\n } = resolveStorageUnitsFilter(filter);\n\n const db = await this.db;\n const keys = await db.keys();\n const documentKeys = keys\n .filter((key) =>\n key.startsWith(`${BrowserStorage.DOCUMENT_KEY}${BrowserStorage.SEP}`),\n )\n .map((key) =>\n key.slice(\n BrowserStorage.DOCUMENT_KEY.length + BrowserStorage.SEP.length,\n ),\n );\n\n let documents: Set<string>;\n\n // apply parent id filter\n if (parentIds) {\n // join children from all parents\n const childrenIds = new Set<string>();\n for (const parentId of parentIds) {\n const ids = await this.getChildren(parentId);\n ids.forEach((id) => childrenIds.add(id));\n }\n documents = setUnion(parentIds, childrenIds);\n } else {\n documents = new Set(documentKeys);\n }\n\n // apply document id filter\n documents = documentIds\n ? setIntersection(documentIds, documents)\n : documents;\n\n for (const documentId of documents) {\n const document = await this.get(documentId).catch(() => null);\n // might be a child that has not been synced yet\n if (!document) continue;\n\n // apply document type filter\n if (documentTypes && !documentTypes.has(document.header.documentType))\n continue;\n\n // For each operation scope in the document\n for (const [scope] of Object.entries(document.state)) {\n // apply scope filter\n if (scopes && !scopes.has(scope)) continue;\n\n // Create storage unit for this document+scope combination\n storageUnits.push({\n documentId,\n documentModelType: document.header.documentType,\n scope,\n branch: \"main\", // Default branch\n });\n }\n }\n\n // Handle pagination\n let startIndex = 0;\n if (cursor) {\n const index = storageUnits.findIndex(\n (unit) => unit.documentId === cursor,\n );\n if (index !== -1) {\n startIndex = index;\n }\n }\n\n // Calculate the range to return\n const endIndex = Math.min(startIndex + limit, storageUnits.length);\n const nextCursor =\n endIndex < storageUnits.length\n ? storageUnits[endIndex].documentId\n : undefined;\n\n return {\n units: storageUnits.slice(startIndex, endIndex),\n nextCursor,\n };\n }\n\n ////////////////////////////////\n // IDocumentView\n ////////////////////////////////\n async resolveIds(slugs: string[], signal?: AbortSignal): Promise<string[]> {\n const slugManifest = await this.getSlugManifest();\n\n if (signal?.aborted) {\n throw new AbortError(\"Aborted\");\n }\n\n const ids: string[] = [];\n for (const slug of slugs) {\n const documentId = slugManifest.slugToId[slug];\n if (!documentId) {\n throw new DocumentNotFoundError(slug);\n }\n\n ids.push(documentId);\n }\n\n return Promise.resolve(ids);\n }\n\n async resolveSlugs(ids: string[], signal?: AbortSignal): Promise<string[]> {\n const slugManifest = await this.getSlugManifest();\n\n if (signal?.aborted) {\n throw new AbortError(\"Aborted\");\n }\n\n const slugs: string[] = [];\n for (const id of ids) {\n let found = false;\n for (const [slug, documentId] of Object.entries(slugManifest.slugToId)) {\n if (documentId === id) {\n slugs.push(slug);\n found = true;\n break;\n }\n }\n\n if (!found) {\n throw new DocumentNotFoundError(id);\n }\n }\n\n return Promise.resolve(slugs);\n }\n\n ////////////////////////////////\n // IDocumentAdminStorage\n ////////////////////////////////\n\n async clear() {\n const db = await this.db;\n await db.clear();\n }\n\n ////////////////////////////////\n // IDocumentStorage\n ////////////////////////////////\n\n async exists(documentId: string): Promise<boolean> {\n const db = await this.db;\n const document = await db.getItem<Document>(\n this.buildDocumentKey(documentId),\n );\n\n return !!document;\n }\n\n async create(document: PHDocument): Promise<void> {\n const documentId = document.header.id;\n\n const db = await this.db;\n\n if (await this.exists(documentId)) {\n throw new DocumentAlreadyExistsError(documentId);\n }\n\n const slug =\n document.header.slug && document.header.slug.length > 0\n ? document.header.slug\n : documentId;\n\n // check if the slug is already taken\n const slugManifest = await this.getSlugManifest();\n if (slugManifest.slugToId[slug]) {\n throw new DocumentAlreadyExistsError(\n documentId,\n DocumentAlreadyExistsReason.SLUG,\n );\n }\n\n document.header.slug = slug;\n await db.setItem(this.buildDocumentKey(documentId), document);\n\n // Update the slug manifest if the document has a slug\n if (slug) {\n const slugManifest = await this.getSlugManifest();\n\n // check if the slug is already taken\n if (slugManifest.slugToId[slug]) {\n throw new Error(`Document with slug ${slug} already exists`);\n }\n\n slugManifest.slugToId[slug] = documentId;\n await this.updateSlugManifest(slugManifest);\n }\n\n // temporary: initialize an empty manifest for new drives\n if (document.header.documentType === \"powerhouse/document-drive\") {\n this.updateDriveManifest(documentId, { documentIds: [] });\n }\n }\n\n async get<TDocument extends PHDocument>(\n documentId: string,\n ): Promise<TDocument> {\n const db = await this.db;\n const document = await db.getItem<TDocument>(\n this.buildDocumentKey(documentId),\n );\n\n if (!document) {\n return Promise.reject(new DocumentNotFoundError(documentId));\n }\n\n return document;\n }\n\n async getBySlug<TDocument extends PHDocument>(\n slug: string,\n ): Promise<TDocument> {\n const slugManifest = await this.getSlugManifest();\n const documentId = slugManifest.slugToId[slug];\n\n if (!documentId) {\n return Promise.reject(new DocumentNotFoundError(slug));\n }\n\n return this.get<TDocument>(documentId);\n }\n\n async findByType(\n documentModelType: string,\n limit = 100,\n cursor?: string,\n ): Promise<{\n documents: string[];\n nextCursor: string | undefined;\n }> {\n const db = await this.db;\n const keys = await db.keys();\n\n const documentKeys = keys.filter((key) =>\n key.startsWith(`${BrowserStorage.DOCUMENT_KEY}${BrowserStorage.SEP}`),\n );\n\n // Load documents with matching type and collect their metadata\n const documentsAndIds: Array<{ id: string; document: PHDocument }> = [];\n for (const key of documentKeys) {\n const documentId = key.slice(\n BrowserStorage.DOCUMENT_KEY.length + BrowserStorage.SEP.length,\n );\n\n try {\n const document = await db.getItem<PHDocument>(key);\n if (!document || document.header.documentType !== documentModelType) {\n continue;\n }\n\n documentsAndIds.push({ id: documentId, document });\n } catch (error) {\n continue;\n }\n }\n\n // Sort by creation date, then by ID\n documentsAndIds.sort((a, b) => {\n const aDate = new Date(a.document.header.createdAtUtcIso);\n const bDate = new Date(b.document.header.createdAtUtcIso);\n\n if (aDate.getTime() === bDate.getTime()) {\n return a.id.localeCompare(b.id);\n }\n\n return aDate.getTime() - bDate.getTime();\n });\n\n // cursor\n let startIndex = 0;\n if (cursor) {\n const index = documentsAndIds.findIndex(({ id }) => id === cursor);\n if (index !== -1) {\n startIndex = index;\n }\n }\n\n // count to limit\n const endIndex = Math.min(startIndex + limit, documentsAndIds.length);\n let nextCursor: string | undefined;\n if (endIndex < documentsAndIds.length) {\n nextCursor = documentsAndIds[endIndex].id;\n }\n\n return {\n documents: documentsAndIds\n .slice(startIndex, endIndex)\n .map(({ id }) => id),\n nextCursor,\n };\n }\n\n async delete(documentId: string): Promise<boolean> {\n const db = await this.db;\n\n const document = await db.getItem<PHDocument>(\n this.buildDocumentKey(documentId),\n );\n\n if (!document) {\n return false;\n }\n\n // Remove from slug manifest if it has a slug\n const slug =\n document.header.slug?.length > 0 ? document.header.slug : documentId;\n try {\n if (slug) {\n const slugManifest = await this.getSlugManifest();\n if (slugManifest.slugToId[slug] === documentId) {\n delete slugManifest.slugToId[slug];\n await this.updateSlugManifest(slugManifest);\n }\n }\n } catch (error) {\n // If we can't get the slug, we can't remove it from the manifest\n }\n\n // remove from parent manifests\n const parents = await this.getParents(documentId);\n for (const parent of parents) {\n await this.removeChild(parent, documentId);\n }\n\n // delete any manifest for this document\n await db.removeItem(this.buildManifestKey(documentId));\n\n // finally, delete the specified document\n await db.removeItem(this.buildDocumentKey(documentId));\n\n return true;\n }\n\n async removeChild(parentId: string, childId: string): Promise<boolean> {\n const manifest = await this.getManifest(parentId);\n const docIndex = manifest.documentIds.indexOf(childId);\n if (docIndex !== -1) {\n manifest.documentIds.splice(docIndex, 1);\n await this.updateDriveManifest(parentId, manifest);\n return true;\n }\n\n return false;\n }\n\n async addChild(parentId: string, childId: string): Promise<void> {\n if (parentId === childId) {\n throw new Error(\"Cannot associate a document with itself\");\n }\n\n // check if the child is a parent of the parent\n const children = await this.getChildren(childId);\n if (children.includes(parentId)) {\n throw new Error(\"Cannot associate a document with its child\");\n }\n\n const manifest = await this.getManifest(parentId);\n if (!manifest.documentIds.includes(childId)) {\n manifest.documentIds.push(childId);\n await this.updateDriveManifest(parentId, manifest);\n }\n }\n\n async getChildren(parentId: string): Promise<string[]> {\n const manifest = await this.getManifest(parentId);\n return manifest.documentIds;\n }\n\n async getParents(childId: string): Promise<string[]> {\n const db = await this.db;\n const keys = await db.keys();\n const parents: string[] = [];\n\n // Find all manifest keys\n const manifestKeys = keys.filter((key) =>\n key.startsWith(`${BrowserStorage.MANIFEST_KEY}${BrowserStorage.SEP}`),\n );\n\n // Check each manifest to see if it contains the childId\n for (const key of manifestKeys) {\n // Extract the driveId from the manifest key\n const driveId = key.slice(\n BrowserStorage.MANIFEST_KEY.length + BrowserStorage.SEP.length,\n );\n\n const manifest = await this.getManifest(driveId);\n if (manifest.documentIds.includes(childId)) {\n parents.push(driveId);\n }\n }\n\n return parents;\n }\n\n ////////////////////////////////\n // IDriveStorage\n ////////////////////////////////\n\n private async getManifest(driveId: string): Promise<DriveManifest> {\n const db = await this.db;\n const manifest = await db.getItem<DriveManifest>(\n this.buildManifestKey(driveId),\n );\n return manifest || { documentIds: [] };\n }\n\n private async updateDriveManifest(\n driveId: string,\n manifest: DriveManifest,\n ): Promise<void> {\n const db = await this.db;\n await db.setItem(this.buildManifestKey(driveId), manifest);\n }\n\n private async getSlugManifest(): Promise<SlugManifest> {\n const db = await this.db;\n const manifest = await db.getItem<SlugManifest>(\n BrowserStorage.SLUG_MANIFEST_KEY,\n );\n return manifest || { slugToId: {} };\n }\n\n private async updateSlugManifest(manifest: SlugManifest): Promise<void> {\n const db = await this.db;\n await db.setItem(BrowserStorage.SLUG_MANIFEST_KEY, manifest);\n }\n\n async addDocumentOperations(\n id: string,\n operations: Operation[],\n document: PHDocument,\n ): Promise<void> {\n const existingDocument = await this.get(id);\n if (!existingDocument) {\n throw new Error(`Document with id ${id} not found`);\n }\n\n const mergedOperations = mergeOperations(\n existingDocument.operations,\n operations,\n );\n\n const db = await this.db;\n await db.setItem(this.buildDocumentKey(id), {\n ...existingDocument,\n ...document,\n operations: mergedOperations,\n });\n }\n\n async addDriveOperations(\n id: string,\n operations: Operation[],\n document: PHDocument,\n ): Promise<void> {\n const existingDocument = await this.get<DocumentDriveDocument>(id);\n const mergedOperations = mergeOperations(\n existingDocument.operations,\n operations,\n );\n const db = await this.db;\n\n await db.setItem(this.buildDocumentKey(id), {\n ...existingDocument,\n ...document,\n operations: mergedOperations,\n });\n }\n\n async getSynchronizationUnitsRevision(\n units: SynchronizationUnitQuery[],\n ): Promise<\n {\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n lastUpdated: string;\n revision: number;\n }[]\n > {\n const results = await Promise.allSettled(\n units.map(async (unit) => {\n try {\n const document = await this.get<PHDocument>(unit.documentId);\n if (!document?.operations[unit.scope]) {\n return undefined;\n }\n const operations = document.operations[unit.scope]!;\n\n return {\n documentId: unit.documentId,\n documentType: unit.documentType,\n scope: unit.scope,\n branch: unit.branch,\n lastUpdated:\n operations.at(-1)?.timestampUtcMs ??\n document.header.createdAtUtcIso,\n revision:\n operations.length > 0 ? operationsToRevision(operations) : 0,\n };\n } catch (error) {\n this.logger.error(\n \"Error getting synchronization units revision: @error\",\n error,\n );\n return undefined;\n }\n }),\n );\n return results.reduce<\n {\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n lastUpdated: string;\n revision: number;\n }[]\n >((acc, curr) => {\n if (curr.status === \"fulfilled\" && curr.value !== undefined) {\n acc.push(curr.value);\n }\n return acc;\n }, []);\n }\n\n // migrates all stored operations from legacy signature to signatures array\n async migrateOperationSignatures() {\n let cursor: string | undefined;\n do {\n const { documents: drives, nextCursor } = await this.findByType(\n \"powerhouse/document-drive\",\n 100,\n cursor,\n );\n for (const drive of drives) {\n await this.migrateDrive(drive);\n\n const documents = await this.getChildren(drive);\n await Promise.all(\n documents.map(async (docId) => this.migrateDocument(drive, docId)),\n );\n }\n\n cursor = nextCursor;\n } while (cursor);\n }\n\n private async migrateDrive(driveId: string) {\n const drive = await this.get<DocumentDriveDocument>(driveId);\n const migratedDrive = migrateDocumentOperationSignatures(drive);\n if (migratedDrive !== drive) {\n return (await this.db).setItem(\n this.buildDocumentKey(driveId),\n migratedDrive,\n );\n }\n }\n\n private async migrateDocument(drive: string, id: string) {\n const document = await this.get(id);\n const migratedDocument = migrateDocumentOperationSignatures(document);\n if (migratedDocument !== document) {\n return (await this.db).setItem(\n this.buildDocumentKey(id),\n migratedDocument,\n );\n }\n }\n\n ////////////////////////////////\n // Private methods\n ////////////////////////////////\n\n buildDocumentKey(documentId: string) {\n return `${BrowserStorage.DOCUMENT_KEY}${BrowserStorage.SEP}${documentId}`;\n }\n\n buildManifestKey(driveId: string) {\n return `${BrowserStorage.MANIFEST_KEY}${BrowserStorage.SEP}${driveId}`;\n }\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type {\n Operation,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport type {\n IDocumentAdminStorage,\n IDocumentStorage,\n IDriveOperationStorage,\n IStorageUnit,\n IStorageUnitFilter,\n SynchronizationUnitQuery,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport {\n DocumentAlreadyExistsError,\n DocumentAlreadyExistsReason,\n DocumentNotFoundError,\n} from \"server\";\nimport { AbortError, mergeOperations, operationsToRevision } from \"utils\";\nimport {\n resolveStorageUnitsFilter,\n setIntersection,\n setUnion,\n} from \"./utils.js\";\n\ntype DriveManifest = {\n documentIds: Set<string>;\n};\n\nexport class MemoryStorage\n implements IDriveOperationStorage, IDocumentStorage, IDocumentAdminStorage\n{\n private logger = childLogger([\"MemoryStorage\"]);\n private documents: Record<string, PHDocument>;\n private driveManifests: Record<string, DriveManifest>;\n private slugToDocumentId: Record<string, string>;\n\n constructor() {\n this.documents = {};\n this.driveManifests = {};\n this.slugToDocumentId = {};\n }\n\n ////////////////////////////////\n // IDocumentView\n ////////////////////////////////\n resolveIds(slugs: string[], signal?: AbortSignal): Promise<string[]> {\n const ids = [];\n for (const slug of slugs) {\n const documentId = this.slugToDocumentId[slug];\n if (!documentId) {\n throw new DocumentNotFoundError(slug);\n }\n\n ids.push(documentId);\n }\n\n if (signal?.aborted) {\n throw new AbortError(\"Aborted\");\n }\n\n return Promise.resolve(ids);\n }\n\n resolveSlugs(ids: string[], signal?: AbortSignal): Promise<string[]> {\n const slugs = [];\n for (const id of ids) {\n const document = this.documents[id];\n if (!document) {\n throw new DocumentNotFoundError(id);\n }\n\n slugs.push(document.header.slug);\n }\n\n if (signal?.aborted) {\n throw new AbortError(\"Aborted\");\n }\n\n return Promise.resolve(slugs);\n }\n\n ////////////////////////////////\n // IDocumentStorage\n ////////////////////////////////\n\n exists(documentId: string): Promise<boolean> {\n return Promise.resolve(!!this.documents[documentId]);\n }\n\n create(document: PHDocument) {\n const documentId = document.header.id;\n\n // check if the document already exists by id\n if (this.documents[documentId]) {\n throw new DocumentAlreadyExistsError(documentId);\n }\n\n const slug =\n document.header.slug?.length > 0 ? document.header.slug : documentId;\n\n // check if the document already exists by slug\n if (slug && this.slugToDocumentId[slug]) {\n throw new DocumentAlreadyExistsError(\n documentId,\n DocumentAlreadyExistsReason.SLUG,\n );\n }\n\n // store the document and update the slug\n document.header.slug = slug;\n this.documents[documentId] = document;\n\n // add slug to lookup if it exists\n if (slug) {\n this.slugToDocumentId[slug] = documentId;\n }\n\n // temporary: initialize an empty manifest for new drives\n if (document.header.documentType === \"powerhouse/document-drive\") {\n this.updateDriveManifest(documentId, { documentIds: new Set() });\n }\n\n return Promise.resolve();\n }\n\n get<TDocument extends PHDocument>(documentId: string): Promise<TDocument> {\n const document = this.documents[documentId];\n if (!document) {\n return Promise.reject(new DocumentNotFoundError(documentId));\n }\n\n return Promise.resolve(document as TDocument);\n }\n\n getBySlug<TDocument extends PHDocument>(slug: string): Promise<TDocument> {\n const documentId = this.slugToDocumentId[slug];\n\n if (!documentId) {\n return Promise.reject(new DocumentNotFoundError(slug));\n }\n\n return this.get<TDocument>(documentId);\n }\n\n async findByType(\n documentModelType: string,\n limit = 100,\n cursor?: string,\n ): Promise<{\n documents: string[];\n nextCursor: string | undefined;\n }> {\n const documentsAndIds = Object.entries(this.documents)\n .filter(([_, doc]) => doc.header.documentType === documentModelType)\n .map(([id, doc]) => ({\n id,\n document: doc,\n }));\n\n // sort: created first, then id -- similar to prisma's ordinal but not guaranteed\n documentsAndIds.sort((a, b) => {\n // get date objects\n const aDate = new Date(a.document.header.createdAtUtcIso);\n const bDate = new Date(b.document.header.createdAtUtcIso);\n\n // if the dates are the same, sort by id\n if (aDate.getTime() === bDate.getTime()) {\n const aId = a.id;\n const bId = b.id;\n\n return aId.localeCompare(bId);\n }\n\n return aDate.getTime() - bDate.getTime();\n });\n\n // if cursor is provided, start there\n let startIndex = 0;\n if (cursor) {\n const index = documentsAndIds.findIndex(({ id }) => id === cursor);\n if (index !== -1) {\n startIndex = index;\n }\n }\n\n // count to limit\n const endIndex = Math.min(startIndex + limit, documentsAndIds.length);\n\n let nextCursor: string | undefined;\n if (endIndex < documentsAndIds.length) {\n nextCursor = documentsAndIds[endIndex].id;\n }\n\n // return the documents\n return {\n documents: documentsAndIds\n .slice(startIndex, endIndex)\n .map(({ id }) => id),\n nextCursor,\n };\n }\n\n async delete(documentId: string): Promise<boolean> {\n // Remove from slug lookup if it has a slug\n const document = this.documents[documentId];\n if (document) {\n const slug =\n document.header.slug?.length > 0 ? document.header.slug : documentId;\n if (slug && this.slugToDocumentId[slug] === documentId) {\n delete this.slugToDocumentId[slug];\n }\n }\n\n // remove from parent manifests\n const parents = await this.getParents(documentId);\n for (const parent of parents) {\n await this.removeChild(parent, documentId);\n }\n\n // delete any manifest for this document\n delete this.driveManifests[documentId];\n\n if (this.documents[documentId]) {\n delete this.documents[documentId];\n\n return Promise.resolve(true);\n }\n\n return Promise.resolve(false);\n }\n\n async addChild(parentId: string, childId: string) {\n if (parentId === childId) {\n return Promise.reject(\n new Error(\"Cannot associate a document with itself\"),\n );\n }\n\n // check if the child is a parent of the parent\n const children = await this.getChildren(childId);\n if (children.includes(parentId)) {\n return Promise.reject(\n new Error(\"Cannot associate a document with its child\"),\n );\n }\n\n const manifest = this.getManifest(parentId);\n manifest.documentIds.add(childId);\n this.updateDriveManifest(parentId, manifest);\n\n return Promise.resolve();\n }\n\n async removeChild(parentId: string, childId: string) {\n const manifest = this.getManifest(parentId);\n if (manifest.documentIds.delete(childId)) {\n this.updateDriveManifest(parentId, manifest);\n return Promise.resolve(true);\n }\n\n return Promise.resolve(false);\n }\n\n async getChildren(parentId: string): Promise<string[]> {\n const manifest = this.getManifest(parentId);\n return [...manifest.documentIds];\n }\n\n async getParents(childId: string): Promise<string[]> {\n const parents: string[] = [];\n\n // Scan through all drive manifests to find ones that contain the childId\n for (const [driveId, manifest] of Object.entries(this.driveManifests)) {\n if (manifest.documentIds.has(childId)) {\n parents.push(driveId);\n }\n }\n\n return parents;\n }\n\n ////////////////////////////////\n // IDocumentAdminStorage\n ////////////////////////////////\n\n async clear(): Promise<void> {\n this.documents = {};\n this.driveManifests = {};\n this.slugToDocumentId = {};\n }\n\n ////////////////////////////////\n // IDriveStorage\n ////////////////////////////////\n\n async addDocumentOperations(\n id: string,\n operations: Operation[],\n document: PHDocument,\n ): Promise<void> {\n const existingDocument = await this.get(id);\n if (!document) {\n return Promise.reject(new DocumentNotFoundError(id));\n }\n\n const mergedOperations = mergeOperations(\n existingDocument.operations,\n operations,\n );\n\n const revision: Record<string, number> = {};\n for (const [scope, scopeOps] of Object.entries(mergedOperations)) {\n revision[scope] = operationsToRevision(scopeOps);\n }\n\n this.documents[id] = {\n ...existingDocument,\n state: document.state,\n initialState: document.initialState,\n header: {\n ...existingDocument.header,\n ...document.header,\n revision,\n },\n operations: mergedOperations,\n clipboard: document.clipboard,\n };\n }\n\n async addDriveOperations(\n id: string,\n operations: Operation[],\n document: PHDocument,\n ): Promise<void> {\n const drive = await this.get<DocumentDriveDocument>(id);\n const mergedOperations = mergeOperations(drive.operations, operations);\n\n const revision: Record<string, number> = {};\n for (const [scope, scopeOps] of Object.entries(mergedOperations)) {\n revision[scope] = operationsToRevision(scopeOps);\n }\n\n this.documents[id] = {\n ...drive,\n state: document.state,\n initialState: document.initialState,\n header: {\n ...drive.header,\n ...document.header,\n revision,\n },\n operations: mergedOperations,\n clipboard: document.clipboard,\n };\n }\n\n async getSynchronizationUnitsRevision(\n units: SynchronizationUnitQuery[],\n ): Promise<\n {\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n lastUpdated: string;\n revision: number;\n }[]\n > {\n const results = await Promise.allSettled(\n units.map(async (unit) => {\n try {\n const document = await this.get<PHDocument>(unit.documentId);\n if (!document || !Object.keys(document.state).includes(unit.scope)) {\n return undefined;\n }\n const operations = document.operations[unit.scope];\n if (!operations) {\n return undefined;\n }\n\n return {\n documentId: unit.documentId,\n documentType: unit.documentType,\n scope: unit.scope,\n branch: unit.branch,\n lastUpdated:\n operations.at(-1)?.timestampUtcMs ??\n document.header.createdAtUtcIso,\n revision:\n operations.length > 0 ? operationsToRevision(operations) : 0,\n };\n } catch (error) {\n this.logger.error(\n \"Error getting synchronization units revision: @error\",\n error,\n );\n return undefined;\n }\n }),\n );\n return results.reduce<\n {\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n lastUpdated: string;\n revision: number;\n }[]\n >((acc, curr) => {\n if (curr.status === \"fulfilled\" && curr.value !== undefined) {\n acc.push(curr.value);\n }\n return acc;\n }, []);\n }\n\n ////////////////////////////////\n // IStorageUnitStorage\n ////////////////////////////////\n\n async findStorageUnitsBy(\n filter: IStorageUnitFilter,\n limit: number,\n cursor?: string,\n ): Promise<{ units: IStorageUnit[]; nextCursor?: string }> {\n const storageUnits: IStorageUnit[] = [];\n\n const {\n parentId: parentIds,\n documentId: documentIds,\n documentModelType: documentTypes,\n scope: scopes,\n branch: branches,\n } = resolveStorageUnitsFilter(filter);\n\n let documents: Set<string>;\n\n // apply parent id filter\n if (parentIds) {\n // join children from all parents\n const childrenIds = new Set<string>();\n for (const parentId of parentIds) {\n const ids = await this.getChildren(parentId);\n ids.forEach((id) => childrenIds.add(id));\n }\n documents = setUnion(parentIds, childrenIds);\n } else {\n documents = new Set(Object.keys(this.documents));\n }\n\n // apply document id filter\n documents = documentIds\n ? setIntersection(documentIds, documents)\n : documents;\n\n for (const documentId of documents) {\n const document = this.documents[documentId];\n // might be a child that has not been synced yet\n\n if (!document) continue;\n\n // apply document type filter\n if (documentTypes && !documentTypes.has(document.header.documentType))\n continue;\n\n // For each operation scope in the document\n for (const [scope] of Object.entries(document.state)) {\n // apply scope filter\n if (scopes && !scopes.has(scope)) continue;\n\n // Create storage unit for this document+scope combination\n storageUnits.push({\n documentId,\n documentModelType: document.header.documentType,\n scope,\n branch: \"main\", // Default branch\n });\n }\n }\n\n // Handle pagination\n let startIndex = 0;\n if (cursor) {\n const index = storageUnits.findIndex(\n (unit) => unit.documentId === cursor,\n );\n if (index !== -1) {\n startIndex = index;\n }\n }\n\n // Calculate the range to return\n const endIndex = Math.min(startIndex + limit, storageUnits.length);\n const nextCursor =\n endIndex < storageUnits.length\n ? storageUnits[endIndex].documentId\n : undefined;\n\n return {\n units: storageUnits.slice(startIndex, endIndex),\n nextCursor,\n };\n }\n\n ////////////////////////////////\n // Private\n ////////////////////////////////\n\n private getManifest(driveId: string): DriveManifest {\n if (!this.driveManifests[driveId]) {\n this.driveManifests[driveId] = { documentIds: new Set() };\n }\n\n return this.driveManifests[driveId];\n }\n\n private updateDriveManifest(driveId: string, manifest: DriveManifest): void {\n this.driveManifests[driveId] = manifest;\n }\n}\n","// UUID v4 regex pattern\nconst UUID_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n// Base64 signature characters that need encoding\nconst BASE64_SPECIAL_CHARS = /[+/=]/;\n\n/**\n * Checks if a string is a UUID v4.\n */\nexport function isUUID(id: string): boolean {\n return UUID_REGEX.test(id);\n}\n\n/**\n * Checks if a string contains Base64 special characters that need encoding.\n */\nexport function hasBase64SpecialChars(id: string): boolean {\n return BASE64_SPECIAL_CHARS.test(id);\n}\n\n/**\n * Encodes a document ID to a filesystem-safe string.\n * - UUIDs pass through unchanged\n * - Base64 signatures are encoded to Base64url\n */\nexport function encodeDocumentIdForPath(documentId: string): string {\n // UUIDs are already filesystem-safe\n if (isUUID(documentId)) {\n return documentId;\n }\n\n // Only encode if it has Base64 special characters\n if (hasBase64SpecialChars(documentId)) {\n return documentId\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n }\n\n return documentId;\n}\n\n/**\n * Decodes a filesystem-safe string back to original document ID.\n * - UUIDs pass through unchanged\n * - Base64url is decoded back to Base64 (for signatures)\n */\nexport function decodeDocumentIdFromPath(encodedId: string): string {\n // UUIDs pass through unchanged\n if (isUUID(encodedId)) {\n return encodedId;\n }\n\n // Non-UUIDs are assumed to be Base64url-encoded signatures\n // Decode: replace - with +, _ with /, and restore padding\n let base64 = encodedId.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padLength = (4 - (base64.length % 4)) % 4;\n base64 += \"=\".repeat(padLength);\n return base64;\n}\n","import type { DriveEvents, IEventEmitter } from \"document-drive\";\nimport type { Unsubscribe } from \"nanoevents\";\nimport { createNanoEvents } from \"nanoevents\";\n\nexport class DefaultEventEmitter implements IEventEmitter {\n private emitter = createNanoEvents<DriveEvents>();\n\n emit<K extends keyof DriveEvents>(\n event: K,\n ...args: Parameters<DriveEvents[K]>\n ): void {\n return this.emitter.emit(event, ...args);\n }\n\n on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe {\n return this.emitter.on(event, cb);\n }\n}\n","import type { ISyncUnitMap, SynchronizationUnitId } from \"document-drive\";\n\n/** Separator character used to join synchronization unit key parts */\ntype SyncUnitKeySeparator = \"|\";\n\n/**\n * Internal key format used to store synchronization units.\n * Composed of documentId, scope, and branch joined by the separator.\n */\ntype SyncUnitKey =\n `${SynchronizationUnitId[\"documentId\"]}${SyncUnitKeySeparator}${SynchronizationUnitId[\"scope\"]}${SyncUnitKeySeparator}${SynchronizationUnitId[\"branch\"]}`;\n\n/**\n * A specialized Map implementation for managing synchronization units that uses a \"documentId - scope - branch\" tuple as key.\n * It provides methods to store, retrieve, and delete synchronization units of a certain documentId, optionally a scope and a branch.\n * The implementation uses an internal Map with string keys created by combining documentId, scope, and branch with a separator character.\n */\nexport class SyncUnitMap<Value> implements ISyncUnitMap<Value> {\n /** Internal storage using concatenated string keys */\n private internalMap = new Map<SyncUnitKey, Value>();\n\n /** Character used to separate key components */\n static keySeparator: SyncUnitKeySeparator = \"|\";\n\n /**\n * Escapes the separator character in a string by prefixing it with a backslash\n * @param str String to escape\n */\n private static escape(str: string): string {\n return str.replace(/\\|/g, \"\\\\|\");\n }\n\n /**\n * Unescapes the separator character in a string by removing the prefix backslash\n * @param str String to unescape\n */\n private static unescape(str: string): string {\n return str.replace(/\\\\\\|/g, \"|\");\n }\n\n /**\n * Creates a composite key from a SynchronizationUnitId\n * Escapes any separator characters in the components\n * @param id The synchronization unit identifier\n * @returns A string key combining documentId, scope, and branch\n */\n static buildKey(id: SynchronizationUnitId): SyncUnitKey {\n return `${SyncUnitMap.escape(id.documentId)}${SyncUnitMap.keySeparator}${SyncUnitMap.escape(id.scope)}${SyncUnitMap.keySeparator}${SyncUnitMap.escape(id.branch)}`;\n }\n\n /**\n * Parses a composite key back into a SynchronizationUnitId\n * Unescapes any separator characters in the components\n * @param key The composite key string\n * @returns The parsed synchronization unit identifier\n */\n static parseKey(key: SyncUnitKey): SynchronizationUnitId {\n const parts = key\n .split(/(?<!\\\\)\\|/)\n .map((part: string) => SyncUnitMap.unescape(part));\n\n const [documentId, scope, branch] = parts;\n return { documentId, scope, branch };\n }\n\n // Map API implementation\n\n /**\n * Stores a value with the given synchronization unit identifier\n * @throws Error if any part of the id contains the separator character\n */\n set(id: SynchronizationUnitId, state: Value): this {\n this.internalMap.set(SyncUnitMap.buildKey(id), state);\n return this;\n }\n\n /** Retrieves a value by its synchronization unit identifier */\n get(id: SynchronizationUnitId): Value | undefined {\n return this.internalMap.get(SyncUnitMap.buildKey(id));\n }\n\n /** Checks if a value exists for the given synchronization unit identifier */\n has(id: SynchronizationUnitId): boolean {\n return this.internalMap.has(SyncUnitMap.buildKey(id));\n }\n\n /** Removes a value by its synchronization unit identifier */\n delete(id: SynchronizationUnitId): boolean {\n return this.internalMap.delete(SyncUnitMap.buildKey(id));\n }\n\n /** Removes all entries from the map */\n clear(): void {\n this.internalMap.clear();\n }\n\n /** Returns the number of entries in the map */\n get size(): number {\n return this.internalMap.size;\n }\n\n /**\n * Returns an iterator of synchronization unit identifiers\n * @param filter Optional filter by documentId and scope\n */\n keys(filter?: {\n documentId: string;\n scope?: string;\n }): IterableIterator<SynchronizationUnitId> {\n const iter = this.internalMap.keys();\n return {\n [Symbol.iterator]() {\n return this;\n },\n next(): IteratorResult<SynchronizationUnitId> {\n while (true) {\n const result = iter.next();\n if (result.done) return { done: true, value: undefined };\n const key = result.value;\n const id = SyncUnitMap.parseKey(key);\n if (filter) {\n if (id.documentId !== filter.documentId) continue;\n if (filter.scope !== undefined && id.scope !== filter.scope)\n continue;\n }\n return { done: false, value: id };\n }\n },\n };\n }\n\n /**\n * Returns an iterator of stored values\n * @param filter Optional filter by documentId and scope\n */\n values(filter?: {\n documentId: string;\n scope?: string;\n }): IterableIterator<Value> {\n const iter = this.internalMap.entries();\n return {\n [Symbol.iterator]() {\n return this;\n },\n next(): IteratorResult<Value> {\n while (true) {\n const result = iter.next();\n if (result.done) return { done: true, value: undefined };\n const [key, value] = result.value;\n const id = SyncUnitMap.parseKey(key);\n if (filter) {\n if (id.documentId !== filter.documentId) continue;\n if (filter.scope !== undefined && id.scope !== filter.scope)\n continue;\n }\n return { done: false, value };\n }\n },\n };\n }\n\n /**\n * Returns an iterator of [id, value] pairs\n * @param filter Optional filter by documentId and scope\n */\n entries(filter?: {\n documentId: string;\n scope?: string;\n }): IterableIterator<[SynchronizationUnitId, Value]> {\n const iter = this.internalMap.entries();\n return {\n [Symbol.iterator]() {\n return this;\n },\n next(): IteratorResult<[SynchronizationUnitId, Value]> {\n while (true) {\n const result = iter.next();\n if (result.done) return { done: true, value: undefined };\n const [key, value] = result.value;\n const id = SyncUnitMap.parseKey(key);\n if (filter) {\n if (id.documentId !== filter.documentId) continue;\n if (filter.scope !== undefined && id.scope !== filter.scope)\n continue;\n }\n return {\n done: false,\n value: [id, value],\n };\n }\n },\n };\n }\n\n /** Makes the map iterable */\n [Symbol.iterator]() {\n return this.entries();\n }\n\n /**\n * Executes a callback for each entry in the map\n * @param callbackfn Function to execute for each entry\n * @param thisArg Value to use as 'this' in the callback\n */\n forEach(\n callbackfn: (\n value: Value,\n key: SynchronizationUnitId,\n map: ISyncUnitMap<Value>,\n ) => void,\n thisArg?: any,\n ): void {\n for (const [k, v] of this.entries()) {\n callbackfn.call(thisArg, v, k, this);\n }\n }\n\n // Custom API methods\n\n /**\n * Removes all entries associated with a specific document\n * @param documentId The document identifier\n */\n deleteByDocumentId(documentId: string): void {\n for (const key of this.internalMap.keys()) {\n if (key.startsWith(documentId + SyncUnitMap.keySeparator)) {\n this.internalMap.delete(key);\n }\n }\n }\n\n /**\n * Removes all entries for a specific document and scope combination\n * @param documentId The document identifier\n * @param scope The scope identifier\n */\n deleteByDocumentIdAndScope(documentId: string, scope: string): void {\n const prefix = `${documentId}${SyncUnitMap.keySeparator}${scope}${SyncUnitMap.keySeparator}`;\n for (const key of this.internalMap.keys()) {\n if (key.startsWith(prefix)) {\n this.internalMap.delete(key);\n }\n }\n }\n\n /**\n * Retrieves all entries associated with a specific document\n * @param documentId The document identifier\n * @returns Array of [id, value] pairs\n */\n getAllByDocumentId(documentId: string): [SynchronizationUnitId, Value][] {\n const results: [SynchronizationUnitId, Value][] = [];\n for (const [key, value] of this.internalMap.entries()) {\n if (key.startsWith(documentId + SyncUnitMap.keySeparator)) {\n results.push([SyncUnitMap.parseKey(key), value]);\n }\n }\n return results;\n }\n\n /**\n * Retrieves all entries for a specific document and scope combination\n * @param documentId The document identifier\n * @param scope The scope identifier\n * @returns Array of [id, value] pairs\n */\n getAllByDocumentIdAndScope(\n documentId: string,\n scope: string,\n ): [SynchronizationUnitId, Value][] {\n const prefix = `${documentId}${SyncUnitMap.keySeparator}${scope}${SyncUnitMap.keySeparator}`;\n const results: [SynchronizationUnitId, Value][] = [];\n for (const [key, value] of this.internalMap.entries()) {\n if (key.startsWith(prefix)) {\n results.push([SyncUnitMap.parseKey(key), value]);\n }\n }\n return results;\n }\n}\n","export function debounce<T extends unknown[], R>(\n func: (...args: T) => Promise<R>,\n delay = 250,\n) {\n let timer: number;\n return (immediate = false, ...args: T) => {\n if (timer) {\n clearTimeout(timer);\n }\n return new Promise<R>((resolve, reject) => {\n if (immediate) {\n func(...args)\n .then(resolve)\n .catch(reject);\n } else {\n timer = setTimeout(() => {\n func(...args)\n .then(resolve)\n .catch(reject);\n }, delay) as unknown as number;\n }\n });\n };\n}\n","import type { ListenerFilter } from \"@powerhousedao/shared/document-drive\";\nimport type {\n DriveUpdateErrorHandler,\n ErrorStatus,\n GetStrandsOptions,\n IListenerManager,\n ISynchronizationManager,\n ListenerManagerOptions,\n ListenerState,\n ListenerUpdate,\n OperationUpdate,\n ServerListener,\n StrandUpdate,\n StrandUpdateSource,\n SynchronizationUnit,\n SynchronizationUnitId,\n SyncronizationUnitState,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport { OperationError } from \"../error.js\";\nimport { SyncUnitMap } from \"../sync-unit-map.js\";\nimport { DefaultListenerManagerOptions } from \"./constants.js\";\nimport { debounce } from \"./util.js\";\n\nexport class ListenerManager implements IListenerManager {\n static LISTENER_UPDATE_DELAY = 250;\n\n protected logger = childLogger([\n \"ListenerManager\",\n Math.floor(Math.random() * 999).toString(),\n ]);\n\n protected syncManager: ISynchronizationManager;\n protected options: ListenerManagerOptions;\n public generateJwtHandler?: (driveUrl: string) => Promise<string>;\n\n // driveId -> listenerId -> listenerState\n protected listenerStateByDriveId = new Map<\n string,\n Map<string, ListenerState>\n >();\n\n constructor(\n syncManager: ISynchronizationManager,\n options: ListenerManagerOptions = DefaultListenerManagerOptions,\n ) {\n this.syncManager = syncManager;\n this.options = { ...DefaultListenerManagerOptions, ...options };\n\n this.logger.verbose(`constructor(...)`);\n }\n\n setGenerateJwtHandler(handler: (driveUrl: string) => Promise<string>) {\n this.generateJwtHandler = handler;\n }\n\n removeJwtHandler() {\n this.generateJwtHandler = undefined;\n }\n\n async initialize(handler: DriveUpdateErrorHandler) {\n this.logger.verbose(\"initialize(...)\");\n\n // if network connect comes back online\n // then triggers the listeners update\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"online\", () => {\n this.triggerUpdate(false, { type: \"local\" }, undefined, handler).catch(\n (error) => {\n this.logger.error(\n \"Non handled error updating listeners: @error\",\n error,\n );\n },\n );\n });\n }\n }\n\n driveHasListeners(driveId: string) {\n return this.listenerStateByDriveId.has(driveId);\n }\n\n async setListener(driveId: string, listener: ServerListener) {\n this.logger.verbose(\n \"setListener(drive: @driveId, listener: @listenerId)\",\n driveId,\n listener.listenerId,\n );\n\n // slight code smell -- drive id may not need to be on listener or not passed in\n if (driveId !== listener.driveId) {\n throw new Error(\"Drive ID mismatch\");\n }\n\n let existingState;\n try {\n existingState = this.getListenerState(driveId, listener.listenerId);\n } catch {\n existingState = {};\n }\n\n // keep existing state if it exists\n this.setListenerState(driveId, listener.listenerId, {\n ...existingState,\n block: listener.block,\n driveId: listener.driveId,\n pendingTimeout: \"0\",\n listener,\n listenerStatus: \"CREATED\",\n syncUnits: new SyncUnitMap<SyncronizationUnitState>(),\n });\n\n await this.triggerUpdate(true, { type: \"local\" });\n }\n\n async removeListener(driveId: string, listenerId: string) {\n this.logger.verbose(\"setListener()\");\n\n const driveMap = this.listenerStateByDriveId.get(driveId);\n if (!driveMap) {\n return false;\n }\n\n return Promise.resolve(driveMap.delete(listenerId));\n }\n\n async removeSyncUnits(\n parentId: string,\n syncUnits: SynchronizationUnitId[],\n ): Promise<void> {\n const driveMap = this.listenerStateByDriveId.get(parentId);\n if (!driveMap) {\n return;\n }\n\n // delete sync unit state from listeners\n for (const [, listener] of driveMap) {\n for (const syncUnit of syncUnits) {\n listener.syncUnits.delete(syncUnit);\n }\n }\n return Promise.resolve();\n }\n\n async updateSynchronizationRevisions(\n syncUnits: SynchronizationUnit[],\n source: StrandUpdateSource,\n willUpdate?: (listeners: ServerListener[]) => void,\n onError?: (error: Error, driveId: string, listener: ListenerState) => void,\n forceSync = false,\n ) {\n // TODO Do we need to check if listeners are outdated?\n // This method is called when processing an operation.\n // Should we decouple the operation processing from the sync?\n const driveListeners = this.listenerStateByDriveId.values();\n const outdatedListeners: ServerListener[] = [];\n for (const [[_drive, listenerState]] of driveListeners) {\n if (\n outdatedListeners.find(\n (l) => l.listenerId === listenerState.listener.listenerId,\n )\n ) {\n continue;\n }\n\n const transmitter = listenerState.listener.transmitter;\n if (!transmitter?.transmit) {\n continue;\n }\n\n for (const syncUnit of syncUnits) {\n if (!this._checkFilter(listenerState.listener.filter, syncUnit)) {\n continue;\n }\n\n const listenerRev = listenerState.syncUnits.get(syncUnit);\n\n if (!listenerRev || listenerRev.listenerRev < syncUnit.revision) {\n outdatedListeners.push(listenerState.listener);\n break;\n }\n }\n }\n\n return this.triggerUpdate(forceSync, source, willUpdate, onError);\n }\n\n async updateListenerRevision(\n listenerId: string,\n driveId: string,\n syncId: SynchronizationUnitId,\n listenerRev: number,\n ): Promise<void> {\n const drive = this.listenerStateByDriveId.get(driveId);\n if (!drive) {\n return;\n }\n\n const listener = drive.get(listenerId);\n if (!listener) {\n return;\n }\n\n const lastUpdated = new Date().toISOString();\n listener.syncUnits.set(syncId, { listenerRev, lastUpdated });\n\n return Promise.resolve();\n }\n\n triggerUpdate = debounce(\n this._triggerUpdate.bind(this),\n ListenerManager.LISTENER_UPDATE_DELAY,\n );\n\n private async _triggerUpdate(\n source: StrandUpdateSource,\n willUpdate?: (listeners: ServerListener[]) => void,\n onError?: (error: Error, driveId: string, listener: ListenerState) => void,\n maxContinues = 500,\n ) {\n this.logger.verbose(\n \"_triggerUpdate(source: @sourceType, maxContinues: @maxContinues) @listenerStateByDriveId\",\n source.type,\n maxContinues,\n this.listenerStateByDriveId,\n );\n\n if (maxContinues < 0) {\n throw new Error(\"Maximum retries exhausted.\");\n }\n\n const listenerUpdates: ListenerUpdate[] = [];\n\n for (const [driveId, listenerStateById] of this.listenerStateByDriveId) {\n for (const [listenerId, listenerState] of listenerStateById) {\n const transmitter = listenerState.listener.transmitter;\n\n if (!transmitter?.transmit) {\n // transmit is optional, so we can skip listeners that don't have a transmitter\n continue;\n }\n\n const syncUnits = await this.getListenerSyncUnits(driveId, listenerId);\n const strandUpdates: StrandUpdate[] = [];\n\n this.logger.verbose(\"syncUnits: @syncUnits\", syncUnits);\n\n // TODO change to push one after the other, reusing operation data\n const tasks = syncUnits.map((syncUnit) => async () => {\n const unitState = listenerState.syncUnits.get(syncUnit);\n\n if (unitState && unitState.listenerRev >= syncUnit.revision) {\n this.logger.verbose(\n \"Abandoning push for sync unit @syncUnit: already up-to-date (@listenerRev >= @revision)\",\n syncUnit,\n unitState.listenerRev,\n syncUnit.revision,\n );\n return;\n } else {\n this.logger.verbose(\n \"Listener out-of-date for sync unit (@scope, @documentId): @listenerRev < @revision\",\n syncUnit.scope,\n syncUnit.documentId,\n unitState?.listenerRev,\n syncUnit.revision,\n );\n }\n\n const opData: OperationUpdate[] = [];\n if (syncUnit.revision > 0) {\n try {\n const data = await this.syncManager.getOperationData(\n // TODO - join queries, DEAL WITH INVALID SYNC ID ERROR\n syncUnit,\n {\n fromRevision: unitState?.listenerRev,\n },\n );\n opData.push(...data);\n } catch (e) {\n this.logger.error(\"@error\", e);\n }\n\n if (!opData.length) {\n this.logger.verbose(\n \"Abandoning push for @syncUnit: no operations found\",\n syncUnit,\n );\n return;\n }\n }\n\n strandUpdates.push({\n driveId,\n documentType: syncUnit.documentType,\n documentId: syncUnit.documentId,\n branch: syncUnit.branch,\n operations: opData,\n scope: syncUnit.scope,\n });\n });\n\n if (this.options.sequentialUpdates) {\n this.logger.verbose(\n \"Collecting @count syncUnit strandUpdates in sequence\",\n tasks.length,\n );\n for (const task of tasks) {\n await task();\n }\n } else {\n this.logger.verbose(\n \"Collecting @count syncUnit strandUpdates in parallel\",\n tasks.length,\n );\n await Promise.all(tasks.map((task) => task()));\n }\n\n if (strandUpdates.length == 0) {\n this.logger.verbose(\n \"No strandUpdates needed for listener @listenerId\",\n listenerId,\n );\n continue;\n }\n\n listenerState.pendingTimeout = new Date(\n new Date().getTime() / 1000 + 300,\n ).toISOString();\n\n listenerState.listenerStatus = \"PENDING\";\n\n // TODO update listeners in parallel, blocking for listeners with block=true\n try {\n this.logger.verbose(\n \"_triggerUpdate(source: @sourceType) > transmitter.transmit\",\n source.type,\n );\n\n const listenerRevisions = await transmitter.transmit(\n strandUpdates,\n source,\n );\n\n this.logger.verbose(\n \"_triggerUpdate(source: @sourceType) > transmission succeeded: @listenerRevisions\",\n source.type,\n listenerRevisions,\n );\n\n listenerState.pendingTimeout = \"0\";\n listenerState.listenerStatus = \"PENDING\";\n\n const lastUpdated = new Date().toISOString();\n let continuationNeeded = false;\n\n for (const revision of listenerRevisions) {\n const syncUnit = syncUnits.find(\n (unit) =>\n revision.documentId === unit.documentId &&\n revision.scope === unit.scope &&\n revision.branch === unit.branch,\n );\n\n if (syncUnit) {\n listenerState.syncUnits.set(syncUnit, {\n lastUpdated,\n listenerRev: revision.revision,\n });\n\n // Check for revision status vv\n const su = strandUpdates.find(\n (su) =>\n su.driveId === revision.driveId &&\n su.documentId === revision.documentId &&\n su.scope === revision.scope &&\n su.branch === revision.branch,\n );\n\n if (su && su.operations.length > 0) {\n const suIndex = su.operations.at(-1)?.index;\n if (suIndex !== revision.revision) {\n this.logger.verbose(\n \"Revision still out-of-date for @documentId:@scope:@branch @suIndex <> @revision\",\n su.documentId,\n su.scope,\n su.branch,\n suIndex,\n revision.revision,\n );\n continuationNeeded = true;\n } else {\n this.logger.verbose(\n \"Revision match for @documentId:@scope:@branch @suIndex\",\n su.documentId,\n su.scope,\n su.branch,\n suIndex,\n );\n }\n }\n // Check for revision status ^^\n } else {\n this.logger.warn(\n \"Received revision for untracked unit for listener @listenerId: @revision\",\n listenerState.listener.listenerId,\n revision,\n );\n }\n }\n\n for (const revision of listenerRevisions) {\n const error = revision.status === \"ERROR\";\n if (revision.error?.includes(\"Missing operations\")) {\n continuationNeeded = true;\n } else if (error) {\n throw new OperationError(\n revision.status as ErrorStatus,\n undefined,\n revision.error,\n revision.error,\n );\n }\n }\n\n if (!continuationNeeded) {\n listenerUpdates.push({\n listenerId: listenerState.listener.listenerId,\n listenerRevisions,\n });\n } else {\n const updates = await this._triggerUpdate(\n source,\n willUpdate,\n onError,\n maxContinues - 1,\n );\n listenerUpdates.push(...updates);\n }\n\n listenerState.listenerStatus = \"SUCCESS\";\n } catch (e) {\n // TODO: Handle error based on listener params (blocking, retry, etc)\n onError?.(e as Error, driveId, listenerState);\n listenerState.listenerStatus =\n e instanceof OperationError ? e.status : \"ERROR\";\n }\n }\n }\n\n this.logger.verbose(\n \"Returning listener updates (maxContinues: @maxContinues): @listenerUpdates\",\n maxContinues,\n listenerUpdates,\n );\n\n return listenerUpdates;\n }\n\n private _checkFilter(filter: ListenerFilter, syncUnit: SynchronizationUnit) {\n const { branch, documentId, scope, documentType } = syncUnit;\n // TODO: Needs to be optimized\n if (\n (!filter.branch ||\n filter.branch.includes(branch) ||\n filter.branch.includes(\"*\")) &&\n (!filter.documentId ||\n filter.documentId.includes(documentId) ||\n filter.documentId.includes(\"*\")) &&\n (!filter.scope ||\n filter.scope.includes(scope) ||\n filter.scope.includes(\"*\")) &&\n (!filter.documentType ||\n filter.documentType.includes(documentType) ||\n filter.documentType.includes(\"*\"))\n ) {\n return true;\n }\n return false;\n }\n\n getListenerSyncUnits(driveId: string, listenerId: string) {\n const listener = this.listenerStateByDriveId.get(driveId)?.get(listenerId);\n if (!listener) {\n return [];\n }\n const filter = listener.listener.filter;\n return this.syncManager.getSynchronizationUnits(\n driveId,\n filter.documentId ?? [\"*\"],\n filter.scope ?? [\"*\"],\n filter.branch ?? [\"*\"],\n filter.documentType ?? [\"*\"],\n );\n }\n\n async removeDrive(driveId: string): Promise<void> {\n const listenerIdToListenerState = this.listenerStateByDriveId.get(driveId);\n if (!listenerIdToListenerState) {\n return;\n }\n\n // delete first\n this.listenerStateByDriveId.delete(driveId);\n\n for (const [_, listenerState] of listenerIdToListenerState) {\n // guarantee that all disconnects are called\n try {\n await listenerState.listener.transmitter?.disconnect?.();\n } catch (error) {\n this.logger.error(\"@error\", error);\n }\n }\n }\n\n async getStrands(\n driveId: string,\n listenerId: string,\n options?: GetStrandsOptions,\n ): Promise<StrandUpdate[]> {\n // this will throw if listenerState is not found\n this.logger.verbose(\n \"[SYNC DEBUG] ListenerManager.getStrands called for drive: @driveId, listener: @listenerId, options: @options\",\n driveId,\n listenerId,\n options || {},\n );\n\n let listenerState;\n try {\n listenerState = this.getListenerState(driveId, listenerId);\n this.logger.verbose(\n \"[SYNC DEBUG] Found listener state for drive: @driveId, listener: @listenerId, status: @status\",\n driveId,\n listenerId,\n listenerState.listenerStatus,\n );\n } catch (error) {\n this.logger.error(\n \"[SYNC DEBUG] Failed to find listener state for drive: @driveId, listener: @listenerId. Error: @error\",\n driveId,\n listenerId,\n error,\n );\n throw error;\n }\n\n // fetch operations from drive and prepare strands\n const strands: StrandUpdate[] = [];\n\n try {\n const syncUnits = await this.getListenerSyncUnits(driveId, listenerId);\n this.logger.verbose(\n \"[SYNC DEBUG] Retrieved @count sync units for drive: @driveId, listener: @listenerId\",\n syncUnits.length,\n driveId,\n listenerId,\n );\n\n const limit = options?.limit; // maximum number of operations to send across all sync units\n let operationsCount = 0; // total amount of operations that have been retrieved\n\n const tasks = syncUnits.map((syncUnit) => async () => {\n if (limit && operationsCount >= limit) {\n // break;\n return;\n }\n if (syncUnit.revision < 0) {\n this.logger.verbose(\n \"[SYNC DEBUG] Skipping sync unit with negative revision: @syncUnit, revision: @revision\",\n syncUnit,\n syncUnit.revision,\n );\n return;\n }\n const entry = listenerState.syncUnits.get(syncUnit);\n if (entry && entry.listenerRev >= syncUnit.revision) {\n this.logger.verbose(\n \"[SYNC DEBUG] Skipping sync unit - listener already up to date: @syncUnit, listenerRev: @listenerRev, revision: @revision\",\n syncUnit,\n entry.listenerRev,\n syncUnit.revision,\n );\n return;\n }\n\n const { documentId, scope, branch } = syncUnit;\n let operations: OperationUpdate[] = [];\n try {\n if (syncUnit.revision > 0) {\n this.logger.verbose(\n \"[SYNC DEBUG] Getting operations for syncUnit: @syncUnit\",\n syncUnit,\n );\n\n operations = await this.syncManager.getOperationData(\n // DEAL WITH INVALID SYNC ID ERROR\n syncUnit,\n {\n since: options?.since,\n fromRevision: options?.fromRevision ?? entry?.listenerRev,\n limit: limit ? limit - operationsCount : undefined,\n },\n );\n }\n this.logger.verbose(\n \"[SYNC DEBUG] Retrieved @count operations for syncUnit: @syncUnit\",\n operations.length,\n syncUnit,\n );\n\n operationsCount += operations.length;\n\n strands.push({\n driveId,\n documentId,\n documentType: syncUnit.documentType,\n scope: scope,\n branch,\n operations,\n });\n\n this.logger.verbose(\n \"[SYNC DEBUG] Added strand with @count operations for syncUnit: @syncUnit\",\n operations.length,\n syncUnit,\n );\n } catch (error) {\n this.logger.error(\n \"Error getting operations for syncUnit: @syncUnit, error: @error\",\n syncUnit,\n error,\n );\n return;\n }\n });\n\n if (this.options.sequentialUpdates) {\n this.logger.verbose(\n \"[SYNC DEBUG] Processing @count sync units sequentially\",\n tasks.length,\n );\n for (const task of tasks) {\n await task();\n }\n } else {\n this.logger.verbose(\n \"[SYNC DEBUG] Processing @count sync units in parallel\",\n tasks.length,\n );\n await Promise.all(tasks.map((task) => task()));\n }\n } catch (error) {\n this.logger.error(\"Error in getStrands: @error\", error);\n }\n\n this.logger.verbose(\n \"ListenerManager.getStrands returning @count strands for drive: @driveId, listener: @listenerId\",\n strands.length,\n driveId,\n listenerId,\n );\n return strands;\n }\n\n getListenerState(driveId: string, listenerId: string) {\n let listenerStateByListenerId = this.listenerStateByDriveId.get(driveId);\n if (!listenerStateByListenerId) {\n listenerStateByListenerId = new Map();\n this.listenerStateByDriveId.set(driveId, listenerStateByListenerId);\n }\n\n const listenerState = listenerStateByListenerId.get(listenerId);\n if (!listenerState) {\n throw new Error(\"Listener not found\");\n }\n\n return listenerState;\n }\n\n setListenerState(\n driveId: string,\n listenerId: string,\n listenerState: ListenerState,\n ) {\n let listenerStateByListenerId = this.listenerStateByDriveId.get(driveId);\n if (!listenerStateByListenerId) {\n listenerStateByListenerId = new Map();\n this.listenerStateByDriveId.set(driveId, listenerStateByListenerId);\n }\n\n listenerStateByListenerId.set(listenerId, listenerState);\n }\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport {\n garbageCollectDocumentOperations,\n replayDocument,\n type DocumentModelModule,\n type PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport type {\n GetStrandsOptions,\n ICache,\n IDocumentStorage,\n IDriveOperationStorage,\n IEventEmitter,\n IStorageUnit,\n ISynchronizationManager,\n OperationUpdate,\n SynchronizationUnit,\n SynchronizationUnitId,\n SynchronizationUnitQuery,\n SyncStatus,\n SyncUnitStatusObject,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport { isBefore, operationsToRevision } from \"utils\";\nimport { SynchronizationUnitNotFoundError } from \"./error.js\";\nimport { SyncUnitMap } from \"./sync-unit-map.js\";\n\nexport class SynchronizationManager implements ISynchronizationManager {\n private syncStatus = new SyncUnitMap<SyncUnitStatusObject>();\n\n private logger = childLogger([\"SynchronizationManager\"]);\n\n constructor(\n private readonly storage: IDriveOperationStorage,\n private readonly documentStorage: IDocumentStorage,\n private readonly cache: ICache,\n private documentModelModules: DocumentModelModule[],\n private readonly eventEmitter?: IEventEmitter,\n ) {}\n\n async getSynchronizationUnits(\n parentId: string,\n documentId?: string[],\n scope?: string[],\n branch?: string[],\n documentType?: string[],\n ): Promise<SynchronizationUnit[]> {\n const synchronizationUnitsQuery = await this.getSynchronizationUnitsIds(\n parentId,\n documentId,\n scope,\n branch,\n documentType,\n );\n\n this.logger.verbose(\n \"getSynchronizationUnits query: @query\",\n synchronizationUnitsQuery,\n );\n\n const result = await this.getSynchronizationUnitsRevision(\n synchronizationUnitsQuery,\n );\n return result.filter((s) => typeof s !== \"undefined\");\n }\n\n private async getSynchronizationUnitsRevision(\n syncUnitsQuery: SynchronizationUnitQuery[],\n ): Promise<(SynchronizationUnit | undefined)[]> {\n const revisions =\n await this.storage.getSynchronizationUnitsRevision(syncUnitsQuery);\n\n this.logger.verbose(\n \"getSynchronizationUnitsRevision: @revisions\",\n revisions,\n );\n\n return syncUnitsQuery.map((query) =>\n revisions.find(\n (revision) =>\n revision.documentId === query.documentId &&\n revision.scope === query.scope &&\n revision.branch === query.branch,\n ),\n );\n }\n\n async getSynchronizationUnitsIds(\n parentId?: string,\n documentId?: string[],\n scope?: string[],\n branch?: string[],\n documentType?: string[],\n ): Promise<SynchronizationUnitQuery[]> {\n const filter = {\n parentId: parentId ? [parentId] : undefined,\n documentId: documentId,\n documentModelType: documentType,\n scope,\n branch,\n };\n\n let cursor: string | undefined;\n const units: IStorageUnit[] = [];\n do {\n const { units: newUnits, nextCursor } =\n await this.documentStorage.findStorageUnitsBy(filter, 100, cursor);\n units.push(...newUnits);\n cursor = nextCursor;\n } while (cursor);\n\n return units.reduce(\n (acc, { documentModelType, ...u }) =>\n u.scope === \"local\"\n ? acc\n : acc.concat([{ ...u, documentType: documentModelType }]),\n new Array<SynchronizationUnitQuery>(),\n );\n }\n\n async getSynchronizationUnit(\n syncId: SynchronizationUnitId,\n ): Promise<SynchronizationUnit | undefined> {\n const { scope, branch, documentId } = syncId;\n\n // TODO: REPLACE WITH GET DOCUMENT OPERATIONS\n const document = await this.getDocument(documentId);\n if (!Object.keys(document.state).includes(scope)) {\n return undefined;\n }\n\n const operations = document.operations[scope] ?? [];\n const lastOperation = operations.at(-1);\n\n return {\n scope,\n branch,\n documentId,\n documentType: document.header.documentType,\n lastUpdated:\n lastOperation?.timestampUtcMs ?? document.header.lastModifiedAtUtcIso,\n revision: operationsToRevision(operations),\n };\n }\n\n async getOperationData(\n syncId: SynchronizationUnitId,\n filter: GetStrandsOptions,\n ): Promise<OperationUpdate[]> {\n this.logger.verbose(\n \"[SYNC DEBUG] SynchronizationManager.getOperationData called for syncId: @syncId, filter: @filter\",\n syncId,\n filter,\n );\n\n const document = await this.getDocument(syncId.documentId);\n\n this.logger.verbose(\n \"[SYNC DEBUG] Retrieved document @documentId with type: @documentType\",\n document.header.id,\n document.header.documentType,\n );\n\n const operations = document.operations[syncId.scope] ?? []; // TODO filter by branch also\n\n this.logger.verbose(\n \"[SYNC DEBUG] Found @count total operations in scope @scope\",\n operations.length,\n syncId.scope,\n );\n\n const filteredOperations = operations.filter(\n (operation) =>\n Object.keys(filter).length === 0 ||\n ((filter.since === undefined ||\n isBefore(filter.since, operation.timestampUtcMs)) &&\n (filter.fromRevision === undefined ||\n operation.index >= filter.fromRevision)),\n );\n\n this.logger.verbose(\n \"[SYNC DEBUG] Filtered to @count operations based on filter criteria (fromRevision: @fromRevision)\",\n filteredOperations.length,\n filter.fromRevision,\n );\n\n const limitedOperations = filter.limit\n ? filteredOperations.slice(0, filter.limit)\n : filteredOperations;\n\n this.logger.verbose(\n \"[SYNC DEBUG] Returning @count operations after applying limit\",\n limitedOperations.length,\n );\n\n if (limitedOperations.length > 0) {\n const firstOp = limitedOperations[0];\n const lastOp = limitedOperations[limitedOperations.length - 1];\n this.logger.verbose(\n \"[SYNC DEBUG] First operation: index=@index, type=@type\",\n firstOp.index,\n firstOp.action.type,\n );\n this.logger.verbose(\n \"[SYNC DEBUG] Last operation: index=@index, type=@type\",\n lastOp.index,\n lastOp.action.type,\n );\n }\n\n return limitedOperations.map((operation) => ({\n actionId: operation.action.id,\n hash: operation.hash,\n index: operation.index,\n timestampUtcMs: operation.timestampUtcMs,\n type: operation.action.type,\n input: operation.action.input as object,\n skip: operation.skip,\n context: operation.action.context,\n id: operation.id ?? \"\",\n }));\n }\n\n private async getDocument(documentId: string): Promise<PHDocument> {\n try {\n const cachedDocument = await this.cache.getDocument(documentId);\n if (cachedDocument) {\n return cachedDocument;\n }\n } catch (e) {\n this.logger.error(\"Error getting document from cache: @error\", e);\n }\n const documentStorage = await this.documentStorage.get(documentId);\n return this._buildDocument(documentStorage);\n }\n\n private _buildDocument(documentStorage: PHDocument): PHDocument {\n const documentModelModule = this.getDocumentModelModule<PHDocument>(\n documentStorage.header.documentType,\n );\n\n const operations = garbageCollectDocumentOperations(\n documentStorage.operations,\n );\n\n return replayDocument(\n documentStorage.initialState,\n operations,\n documentModelModule.reducer,\n documentStorage.header,\n undefined,\n {},\n {\n checkHashes: true,\n reuseOperationResultingState: true,\n },\n );\n }\n\n setDocumentModelModules(modules: DocumentModelModule[]) {\n this.documentModelModules = modules;\n }\n\n private getDocumentModelModule<TDocument>(documentType: string) {\n const documentModelModule = this.documentModelModules.find(\n (m) => m.documentModel.global.id === documentType,\n );\n if (!documentModelModule) {\n throw new Error(`Document type ${documentType} not supported`);\n }\n return documentModelModule;\n }\n\n getCombinedSyncUnitStatus(syncUnitStatus: SyncUnitStatusObject): SyncStatus {\n if (!syncUnitStatus.pull && !syncUnitStatus.push) return \"INITIAL_SYNC\";\n if (syncUnitStatus.pull === \"INITIAL_SYNC\") return \"INITIAL_SYNC\";\n if (syncUnitStatus.push === \"INITIAL_SYNC\")\n return syncUnitStatus.pull || \"INITIAL_SYNC\";\n\n const order: Array<SyncStatus> = [\n \"ERROR\",\n \"MISSING\",\n \"CONFLICT\",\n \"SYNCING\",\n \"SUCCESS\",\n ];\n const sortedStatus = Object.values(syncUnitStatus).sort(\n (a, b) => order.indexOf(a) - order.indexOf(b),\n );\n\n return sortedStatus[0];\n }\n\n getSyncStatus(\n input: string | SynchronizationUnitId,\n scope = \"global\",\n branch = \"main\",\n ): SyncStatus | SynchronizationUnitNotFoundError {\n const syncUnitId =\n typeof input === \"string\" ? { documentId: input, scope, branch } : input;\n\n const status = this.syncStatus.get(syncUnitId);\n if (!status) {\n return new SynchronizationUnitNotFoundError(syncUnitId);\n }\n return this.getCombinedSyncUnitStatus(status);\n }\n\n updateSyncStatus(\n input: string | SynchronizationUnitId,\n status: Partial<SyncUnitStatusObject> | null,\n error?: Error,\n scope = \"global\",\n branch = \"main\",\n ): void {\n const syncUnitId =\n typeof input === \"string\" ? { documentId: input, scope, branch } : input;\n\n if (status === null) {\n this.syncStatus.delete(syncUnitId);\n return;\n }\n\n const syncUnitStatus = this.syncStatus.get(syncUnitId);\n\n if (!syncUnitStatus) {\n this.initSyncStatus(syncUnitId, status);\n return;\n }\n\n const shouldUpdateStatus = Object.entries(status).some(\n ([key, _status]) =>\n syncUnitStatus[key as keyof SyncUnitStatusObject] !== _status,\n );\n\n if (shouldUpdateStatus) {\n const newStatus = Object.entries(status).reduce((acc, [key, _status]) => {\n return {\n ...acc,\n // do not replace initial_syncing if it has not finished yet\n [key]:\n acc[key as keyof SyncUnitStatusObject] === \"INITIAL_SYNC\" &&\n _status === \"SYNCING\"\n ? \"INITIAL_SYNC\"\n : _status,\n };\n }, syncUnitStatus);\n\n const previousCombinedStatus =\n this.getCombinedSyncUnitStatus(syncUnitStatus);\n const newCombinedStatus = this.getCombinedSyncUnitStatus(newStatus);\n\n this.syncStatus.set(syncUnitId, newStatus);\n\n if (previousCombinedStatus !== newCombinedStatus && this.eventEmitter) {\n this.eventEmitter.emit(\n \"syncStatus\",\n syncUnitId.documentId,\n this.getCombinedSyncUnitStatus(newStatus),\n error,\n newStatus,\n syncUnitId.scope,\n syncUnitId.branch,\n );\n }\n }\n }\n\n private initSyncStatus(\n syncUnitId: SynchronizationUnitId,\n status: Partial<SyncUnitStatusObject>,\n ) {\n const defaultSyncUnitStatus: SyncUnitStatusObject = Object.entries(\n status,\n ).reduce((acc, [key, _status]) => {\n return {\n ...acc,\n [key]: _status !== \"SYNCING\" ? _status : \"INITIAL_SYNC\",\n };\n }, {});\n\n this.syncStatus.set(syncUnitId, defaultSyncUnitStatus);\n if (this.eventEmitter) {\n this.eventEmitter.emit(\n \"syncStatus\",\n syncUnitId.documentId, // TODO also emit scope and branch\n this.getCombinedSyncUnitStatus(defaultSyncUnitStatus),\n undefined,\n defaultSyncUnitStatus,\n syncUnitId.scope,\n syncUnitId.branch,\n );\n }\n }\n\n async initializeDriveSyncStatus(\n driveId: string,\n drive: DocumentDriveDocument,\n ): Promise<void> {\n const syncUnits = await this.getSynchronizationUnitsIds(driveId);\n const syncStatus: SyncUnitStatusObject = {\n pull: drive.state.local.triggers.length > 0 ? \"INITIAL_SYNC\" : undefined,\n push: drive.state.local.listeners.length > 0 ? \"SUCCESS\" : undefined,\n };\n\n if (!syncStatus.pull && !syncStatus.push) return;\n\n const syncUnitsIds = [\n { documentId: driveId, scope: \"global\", branch: \"main\" },\n ...syncUnits,\n ];\n\n for (const syncUnitId of syncUnitsIds) {\n this.initSyncStatus(syncUnitId, syncStatus);\n }\n }\n}\n","import type {\n IBaseDocumentDriveServer,\n IListenerManager,\n ITransmitter,\n ITransmitterFactory,\n ServerListener,\n} from \"document-drive\";\nimport { PullResponderTransmitter } from \"./pull-responder.js\";\nimport { SwitchboardPushTransmitter } from \"./switchboard-push.js\";\n\nexport class TransmitterFactory implements ITransmitterFactory {\n private readonly listenerManager: IListenerManager;\n\n constructor(listenerManager: IListenerManager) {\n this.listenerManager = listenerManager;\n }\n\n instance(\n transmitterType: string,\n listener: ServerListener,\n driveServer: IBaseDocumentDriveServer,\n ): ITransmitter {\n switch (transmitterType) {\n case \"SwitchboardPush\": {\n if (!listener.callInfo?.data) {\n throw new Error(\"No call info data: \" + JSON.stringify(listener));\n }\n\n return new SwitchboardPushTransmitter(\n listener.callInfo.data,\n this.listenerManager,\n );\n }\n case \"Internal\": {\n throw new Error(\"Internal transmitter not implemented\");\n }\n default: {\n return new PullResponderTransmitter(listener, this.listenerManager);\n }\n }\n }\n}\n","import { InMemoryCache } from \"cache\";\nimport type {\n DocumentDriveServerOptions,\n ICache,\n IDocumentDriveServer,\n IDocumentStorage,\n IDriveOperationStorage,\n IEventEmitter,\n IListenerManager,\n IQueueManager,\n ISynchronizationManager,\n ITransmitterFactory,\n} from \"document-drive\";\nimport type { DocumentModelModule } from \"@powerhousedao/shared/document-model\";\nimport { EventQueueManager } from \"queue\";\nimport { MemoryStorage } from \"storage\";\nimport { DocumentDriveServer } from \"./base-server.js\";\nimport { DefaultEventEmitter } from \"./event-emitter.js\";\nimport { DefaultListenerManagerOptions } from \"./listener/constants.js\";\nimport { ListenerManager } from \"./listener/listener-manager.js\";\nimport { SynchronizationManager } from \"./sync-manager.js\";\nimport { TransmitterFactory } from \"./transmitter/factory.js\";\n\n/**\n * Builder class for constructing Reactor instances with proper configuration\n */\nexport class ReactorBuilder {\n public documentModelModules: DocumentModelModule<any>[] = [];\n\n public storage?: IDriveOperationStorage;\n public cache?: ICache;\n public queueManager?: IQueueManager;\n public eventEmitter?: IEventEmitter;\n public options?: DocumentDriveServerOptions;\n public synchronizationManager?: ISynchronizationManager;\n public listenerManager?: IListenerManager;\n public transmitterFactory?: ITransmitterFactory;\n\n constructor(documentModelModules: DocumentModelModule<any>[]) {\n this.documentModelModules = documentModelModules;\n }\n\n public withStorage(storage: IDriveOperationStorage): this {\n this.storage = storage;\n return this;\n }\n\n public withCache(cache: ICache): this {\n this.cache = cache;\n return this;\n }\n\n public withQueueManager(queueManager: IQueueManager): this {\n this.queueManager = queueManager;\n return this;\n }\n\n public withEventEmitter(eventEmitter: IEventEmitter): this {\n this.eventEmitter = eventEmitter;\n return this;\n }\n\n public withSynchronizationManager(\n synchronizationManager: ISynchronizationManager,\n ): this {\n this.synchronizationManager = synchronizationManager;\n return this;\n }\n\n public withListenerManager(listenerManager: IListenerManager): this {\n this.listenerManager = listenerManager;\n return this;\n }\n\n public withTransmitterFactory(transmitterFactory: ITransmitterFactory): this {\n this.transmitterFactory = transmitterFactory;\n return this;\n }\n\n public withOptions(options: DocumentDriveServerOptions): this {\n this.options = options;\n return this;\n }\n\n public build(): IDocumentDriveServer {\n if (!this.storage) {\n this.storage = new MemoryStorage();\n }\n\n if (!this.cache) {\n this.cache = new InMemoryCache();\n }\n\n if (!this.queueManager) {\n this.queueManager = new EventQueueManager();\n }\n\n if (!this.eventEmitter) {\n this.eventEmitter = new DefaultEventEmitter();\n }\n\n if (!this.synchronizationManager) {\n this.synchronizationManager = new SynchronizationManager(\n this.storage,\n // as we refactor, we're secretly making all the IStorage implementations also implement IDocumentStorage\n this.storage as unknown as IDocumentStorage,\n this.cache,\n this.documentModelModules,\n this.eventEmitter,\n );\n }\n\n if (!this.listenerManager) {\n const config = {\n ...DefaultListenerManagerOptions,\n ...this.options?.listenerManager,\n };\n\n this.listenerManager = new ListenerManager(\n this.synchronizationManager,\n config,\n );\n }\n\n if (!this.transmitterFactory) {\n this.transmitterFactory = new TransmitterFactory(this.listenerManager);\n }\n\n return new DocumentDriveServer(\n this.documentModelModules,\n this.storage,\n // as we refactor, we're secretly making all the IStorage implementations also implement IDocumentStorage\n this.storage as unknown as IDocumentStorage,\n this.cache,\n this.queueManager,\n this.eventEmitter,\n this.synchronizationManager,\n this.listenerManager,\n {\n ...this.options,\n featureFlags: {\n enableDualActionCreate: false, // default to false for safety\n ...this.options?.featureFlags,\n },\n },\n );\n }\n}\n","import type {\n Action,\n GetDocumentOptions,\n PHBaseState,\n} from \"@powerhousedao/shared/document-model\";\nimport { deriveOperationId } from \"@powerhousedao/shared/document-model\";\nimport type {\n IBaseDocumentDriveServer,\n IDocumentDriveServer,\n IProcessorLegacy,\n ITransmitter,\n InternalOperationUpdate,\n ListenerRevision,\n RunAsap,\n StrandUpdate,\n StrandUpdateSource,\n} from \"document-drive\";\nimport { logger } from \"document-model\";\nimport { operationsToRevision, runAsap, runAsapAsync } from \"utils\";\n\nexport class InternalTransmitter implements ITransmitter {\n protected drive: IBaseDocumentDriveServer;\n protected processor: IProcessorLegacy;\n protected taskQueueMethod: RunAsap<unknown> | null;\n protected transmitQueue: Promise<ListenerRevision[]> | undefined;\n\n constructor(\n drive: IDocumentDriveServer,\n processor: IProcessorLegacy,\n taskQueueMethod?: RunAsap<unknown> | null,\n ) {\n this.drive = drive;\n this.processor = processor;\n this.taskQueueMethod =\n taskQueueMethod === undefined ? runAsap : taskQueueMethod;\n }\n\n async #buildInternalOperationUpdate(\n strand: StrandUpdate,\n ): Promise<InternalOperationUpdate[]> {\n const operations: InternalOperationUpdate[] = [];\n const stateByIndex = new Map<number, PHBaseState>();\n\n const getStateByIndex = async (index: number) => {\n const state = stateByIndex.get(index);\n if (state) {\n return state;\n }\n\n const getDocumentOptions: GetDocumentOptions = {\n revisions: {\n [strand.scope]: index,\n },\n checkHashes: false,\n };\n const document = await (strand.documentId === strand.driveId\n ? this.drive.getDrive(strand.driveId, getDocumentOptions)\n : this.drive.getDocument(strand.documentId, getDocumentOptions));\n\n if (index < 0) {\n stateByIndex.set(index, (document.initialState as any)[strand.scope]);\n } else {\n stateByIndex.set(index, (document.state as any)[strand.scope]);\n }\n return stateByIndex.get(index);\n };\n for (const operation of strand.operations) {\n const stateTask = () => getStateByIndex(operation.index);\n const state = await (this.taskQueueMethod\n ? runAsapAsync(stateTask, this.taskQueueMethod)\n : stateTask());\n\n const previousStateTask = () => getStateByIndex(operation.index - 1);\n const previousState = await (this.taskQueueMethod\n ? runAsapAsync(previousStateTask, this.taskQueueMethod)\n : previousStateTask());\n\n const action: Action = {\n id: operation.actionId,\n timestampUtcMs: operation.timestampUtcMs,\n type: operation.type,\n input: operation.input,\n context: operation.context,\n scope: strand.scope,\n };\n\n operations.push({\n ...operation,\n id:\n operation.id ??\n deriveOperationId(\n strand.documentId,\n strand.scope,\n strand.branch,\n operation.actionId,\n ),\n state: state as PHBaseState,\n previousState: previousState as PHBaseState,\n action,\n });\n }\n\n return operations;\n }\n\n async transmit(\n strands: StrandUpdate[],\n _source: StrandUpdateSource,\n ): Promise<ListenerRevision[]> {\n const task = async (): Promise<ListenerRevision[]> => {\n const updates = [];\n for (const strand of strands) {\n const operations = await this.#buildInternalOperationUpdate(strand);\n const document = await this.drive.getDocument(strand.documentId);\n const state =\n operations.at(-1)?.state ??\n document.initialState[strand.scope as keyof PHBaseState];\n updates.push({\n ...strand,\n documentType: document.header.documentType,\n operations,\n state,\n document,\n });\n }\n\n try {\n await this.processor.onStrands(updates);\n return strands.map(({ operations, ...s }) => {\n return {\n ...s,\n status: \"SUCCESS\",\n revision: operationsToRevision(operations),\n };\n });\n } catch (error) {\n logger.error(\"@error\", error);\n // TODO check which strand caused an error\n return strands.map(({ operations, ...s }) => ({\n ...s,\n status: \"ERROR\",\n revision: operations.at(0)?.index ?? 0,\n }));\n }\n };\n\n // adds to queue so that each `transmit` is processed at a time to avoid concurrency issues\n this.transmitQueue = this.transmitQueue?.then(() => task()) ?? task();\n return this.transmitQueue;\n }\n\n async disconnect(): Promise<void> {\n await this.processor.onDisconnect();\n }\n}\n","import type { Options } from \"@sindresorhus/fnv1a\";\nimport fnv1a from \"@sindresorhus/fnv1a\";\nimport type {\n HashAlgorithmsLegacy,\n IBaseRelationalDbLegacy,\n IRelationalDbLegacy,\n IRelationalQueryBuilderLegacy,\n} from \"document-drive\";\n\nconst SUPPORTED_SIZES: Options[\"size\"][] = [32, 64, 128, 256, 512, 1024];\nconst LOG2_26 = Math.log2(26); //\n/**\n * Hashes a string to a lowercase base-26 string.\n * @param str The string to hash.\n * @param length The length of the hash. Defaults to 10.\n * @param algorithm The hashing algorithm to use. Defaults to \"fnv1a\".\n * @returns The hashed string.\n */\nexport function hashNamespaceLegacy(\n str: string,\n length = 10,\n algorithm: HashAlgorithmsLegacy = \"fnv1a\",\n) {\n if (algorithm === \"fnv1a\") {\n const requiredBits = Math.ceil(length * LOG2_26);\n const bitSize =\n SUPPORTED_SIZES.find((size) => size && size >= requiredBits) ?? 1024;\n const hash = fnv1a(str, { size: bitSize });\n return toBase26(hash, length);\n } else {\n throw new Error(`Unsupported hashing algorithm: ${algorithm}`);\n }\n}\n\n// converts hash to lowercase letters\nfunction toBase26(num: bigint, length = 10): string {\n const alphabet = \"abcdefghijklmnopqrstuvwxyz\";\n let out = \"\";\n while (num > 0n && out.length < length) {\n out = alphabet[Number(num % 26n)] + out;\n num /= 26n;\n }\n return out.padStart(length, \"a\"); // optional padding\n}\n\n/**\n * Creates a RelationalDb instance with namespace support.\n * @param baseDb The base RelationalDb instance to enhance.\n * @param baseOptions The default options for namespace creation. Hashes namespace by default.\n * @returns The enhanced RelationalDb instance.\n */\nexport function createRelationalDbLegacy<Schema>(\n baseDb: IBaseRelationalDbLegacy<Schema>,\n baseOptions?: NamespaceOptions,\n): IRelationalDbLegacy<Schema> {\n const relationalDb = baseDb as IRelationalDbLegacy<Schema>;\n\n relationalDb.createNamespace = <NamespaceSchema>(\n namespace: string,\n options?: NamespaceOptions,\n ) =>\n createNamespacedDbLegacy<NamespaceSchema>(\n baseDb,\n namespace,\n options ?? baseOptions,\n );\n\n relationalDb.queryNamespace = <NamespaceSchema>(\n namespace: string,\n options?: NamespaceOptions,\n ) =>\n createNamespacedQueryBuilderLegacy<NamespaceSchema>(\n baseDb,\n namespace,\n options ?? baseOptions,\n );\n\n return relationalDb;\n}\n\ntype NamespaceOptions = {\n hashNamespace?: boolean;\n};\n\nexport async function createNamespacedDbLegacy<Schema>(\n db: IBaseRelationalDbLegacy<any>,\n namespace: string,\n options?: NamespaceOptions,\n): Promise<IRelationalDbLegacy<Schema>> {\n // hash the namespace to avoid too long namespaces\n const shouldHash = options?.hashNamespace ?? true;\n const hashValue = shouldHash ? hashNamespaceLegacy(namespace) : namespace;\n await db.schema.createSchema(hashValue).ifNotExists().execute();\n const schemaRelationalDb = db.withSchema(hashValue);\n return schemaRelationalDb as IRelationalDbLegacy<Schema>;\n}\n\nexport function createNamespacedQueryBuilderLegacy<Schema>(\n db: IBaseRelationalDbLegacy<any>,\n namespace: string,\n options?: NamespaceOptions,\n): IRelationalQueryBuilderLegacy<Schema> {\n const shouldHash = options?.hashNamespace ?? true;\n const hashValue = shouldHash ? hashNamespaceLegacy(namespace) : namespace;\n const namespacedDb = db.withSchema(hashValue) as IRelationalDbLegacy<Schema>;\n return relationalDbToQueryBuilderLegacy(namespacedDb);\n}\n\n/**\n * Returns a query builder for a RelationalDb instance.\n * @param query The RelationalDb instance to convert.\n * @returns The IRelationalQueryBuilder instance.\n */\nexport function relationalDbToQueryBuilderLegacy<TSchema>(\n query: IBaseRelationalDbLegacy<TSchema>,\n): IRelationalQueryBuilderLegacy<TSchema> {\n return {\n selectFrom: query.selectFrom.bind(query),\n selectNoFrom: query.selectNoFrom.bind(query),\n with: query.with.bind(query),\n withRecursive: query.withRecursive.bind(query),\n withSchema: (schema: string) =>\n relationalDbToQueryBuilderLegacy<TSchema>(query.withSchema(schema)),\n };\n}\n","import type {\n InternalTransmitterUpdate,\n IProcessorLegacy,\n IRelationalDbLegacy,\n IRelationalDbProcessorLegacy,\n IRelationalQueryBuilderLegacy,\n RelationalDbProcessorClassLegacy,\n RelationalDbProcessorFilterLegacy,\n} from \"document-drive\";\nimport { relationalDbToQueryBuilderLegacy } from \"./utils.js\";\n\nconst IS_RELATIONAL_DB_PROCESSOR = Symbol.for(\"ph.IS_RELATIONAL_DB_PROCESSOR\");\n\n/**\n * Base class for relational db processors that require a relational database storage.\n * This class abstracts database initialization, migration management, and resource cleanup,\n * allowing derived classes to focus on business logic.\n */\nexport abstract class RelationalDbProcessorLegacy<\n TDatabaseSchema = unknown,\n> implements IRelationalDbProcessorLegacy<TDatabaseSchema> {\n constructor(\n protected _namespace: string,\n protected _filter: RelationalDbProcessorFilterLegacy,\n protected relationalDb: IRelationalDbLegacy<TDatabaseSchema>,\n ) {}\n\n static [IS_RELATIONAL_DB_PROCESSOR] = true;\n\n static is(p: unknown): p is RelationalDbProcessorLegacy {\n let proto = Object.getPrototypeOf(p);\n while (proto) {\n if (proto.constructor?.[IS_RELATIONAL_DB_PROCESSOR]) return true;\n\n proto = Object.getPrototypeOf(proto);\n }\n return false;\n }\n\n /**\n * Returns the namespace for a given drive id.\n * This method can be overridden by derived classes to provide a custom namespace.\n */\n static getNamespace(driveId: string): string {\n return `${this.name}_${driveId.replaceAll(\"-\", \"_\")}`;\n }\n\n static query<Schema>(\n this: RelationalDbProcessorClassLegacy<Schema>,\n driveId: string,\n db: IRelationalDbLegacy<any>,\n ): IRelationalQueryBuilderLegacy<Schema> {\n return db.queryNamespace(this.getNamespace(driveId));\n }\n\n /**\n * Returns the filter for the processor.\n * This method can be overridden by derived classes to provide a custom filter.\n */\n get filter(): RelationalDbProcessorFilterLegacy {\n return this._filter;\n }\n\n /**\n * Returns the namespace used by the processor.\n */\n get namespace(): string {\n return this._namespace;\n }\n\n get query(): IRelationalQueryBuilderLegacy<TDatabaseSchema> {\n return relationalDbToQueryBuilderLegacy(this.relationalDb);\n }\n\n /**\n * Abstract method that derived classes must implement.\n * This method is meant to be called on subclasses to initialize and upgrade the database.\n */\n abstract initAndUpgrade(): Promise<void>;\n\n /**\n * Abstract method that derived classes must implement.\n * This is where the business logic for processing document operations should be implemented.\n */\n abstract onStrands(strands: InternalTransmitterUpdate[]): Promise<void>;\n\n /**\n * Called when the processor is disconnected.\n * This method is meant to be overridden by subclasses to clean up resources.\n */\n abstract onDisconnect(): Promise<void>;\n}\n\nexport function isRelationalDbProcessor(\n p: IProcessorLegacy,\n): p is IRelationalDbProcessorLegacy {\n return RelationalDbProcessorLegacy.is(p);\n}\n","import { generateId } from \"@powerhousedao/shared/document-model\";\nimport type {\n IDocumentDriveServer,\n IListenerManager,\n IProcessorManagerLegacy,\n ProcessorFactoryLegacy,\n ProcessorRecordLegacy,\n ServerListener,\n} from \"document-drive\";\nimport { childLogger } from \"document-model\";\nimport { InternalTransmitter } from \"server\";\nimport { isRelationalDbProcessor } from \"./relational.js\";\n\nexport class ProcessorManagerLegacy implements IProcessorManagerLegacy {\n private readonly logger = childLogger([\n \"document-drive\",\n \"processor-manager\",\n ]);\n\n private processorsByDrive = new Map<string, ProcessorRecordLegacy[]>();\n private idToFactory = new Map<string, ProcessorFactoryLegacy>();\n private identifierToListeners = new Map<string, ServerListener[]>();\n\n constructor(\n private listeners: IListenerManager,\n private drive: IDocumentDriveServer,\n ) {\n //\n }\n\n async registerFactory(\n identifier: string,\n factory: ProcessorFactoryLegacy,\n ): Promise<void> {\n this.logger.debug(\"Registering factory '@identifier'.\", identifier);\n\n this.idToFactory.set(identifier, factory);\n\n // iterate over all drives and register the factory\n const driveIds = await this.drive.getDrives();\n for (const driveId of driveIds) {\n await this.createProcessors(driveId, identifier, factory);\n }\n }\n\n async unregisterFactory(identifier: string): Promise<void> {\n // remove all listeners for this identifier\n const listeners = this.identifierToListeners.get(identifier) ?? [];\n for (const listener of listeners) {\n await this.listeners\n .removeListener(listener.driveId, listener.listenerId)\n .catch((e) => this.logger.error(\"@error\", e));\n\n if (listener.transmitter?.disconnect) {\n await listener.transmitter.disconnect();\n }\n }\n\n this.identifierToListeners.set(identifier, []);\n }\n\n async registerDrive(driveId: string) {\n this.logger.debug(\"Registering drive '@driveId'.\", driveId);\n\n // iterate over all factories and create listeners\n for (const [identifier, factory] of this.idToFactory) {\n await this.createProcessors(driveId, identifier, factory);\n }\n }\n\n /**\n * Creates processors for a specific (drive, identifier) pair.\n *\n * This should be called once and only once for each (drive, identifier),\n * unless unregisterFactory is called, which will remove them.\n */\n async createProcessors(\n driveId: string,\n identifier: string,\n factory: ProcessorFactoryLegacy,\n ) {\n const drive = await this.drive.getDrive(driveId);\n\n let listeners = this.identifierToListeners.get(identifier);\n if (!listeners) {\n listeners = [];\n this.identifierToListeners.set(identifier, listeners);\n }\n\n let driveProcessors = this.processorsByDrive.get(driveId);\n if (!driveProcessors) {\n driveProcessors = [];\n this.processorsByDrive.set(driveId, driveProcessors);\n }\n\n // don't let the factory throw, we want to continue with the rest of the processors\n let processors: ProcessorRecordLegacy[] = [];\n try {\n processors = await factory(drive.header);\n } catch (e) {\n this.logger.error(\n \"Error creating processors for drive @driveId: @error\",\n driveId,\n e,\n );\n return;\n }\n\n for (const { filter, processor } of processors) {\n const isRelational = isRelationalDbProcessor(processor);\n\n // check for duplicated namespaces\n if (\n isRelational &&\n driveProcessors.some(\n (p) =>\n isRelationalDbProcessor(p.processor) &&\n p.processor.namespace === processor.namespace,\n )\n ) {\n this.logger.debug(\n \"Processor with namespace '@namespace' already registered for drive '@driveId'.\",\n processor.namespace,\n driveId,\n );\n continue;\n }\n\n if (isRelational) {\n await processor.initAndUpgrade();\n }\n\n const id = generateId();\n const listener: ServerListener = {\n driveId,\n listenerId: id,\n block: false,\n system: false,\n filter,\n callInfo: undefined,\n transmitter: new InternalTransmitter(this.drive, processor),\n };\n\n await this.listeners.setListener(driveId, listener);\n\n listeners.push(listener);\n driveProcessors.push({ filter, processor });\n }\n }\n}\n","import type {\n DocumentDriveAction,\n DocumentDriveDocument,\n DocumentDriveLocalState,\n LegacyAddFileAction,\n ListenerCallInfo,\n ListenerFilter,\n Trigger,\n} from \"@powerhousedao/shared/document-drive\";\nimport type {\n Action,\n ActionContext,\n DocumentModelModule,\n Operation,\n PHDocument,\n PHDocumentHeader,\n PHDocumentMeta,\n ReducerOptions,\n SignalResult,\n} from \"@powerhousedao/shared/document-model\";\nimport type { Unsubscribe } from \"nanoevents\";\nimport type { IReadModeDriveServer } from \"../read-mode/types.js\";\nimport type {\n DriveInfo,\n IDefaultDrivesManager,\n RunAsap,\n} from \"../utils/types.js\";\nimport type { BaseDocumentDriveServer } from \"./base-server.js\";\nimport type {\n OperationError,\n SynchronizationUnitNotFoundError,\n} from \"./error.js\";\nimport type { ITransmitter, StrandUpdateSource } from \"./transmitter/types.js\";\n\nexport type Constructor<T = object> = new (...args: any[]) => T;\n\n// Mixin type that returns a type extending both the base class and the interface\nexport type Mixin<T extends Constructor, I> = T &\n Constructor<InstanceType<T> & I>;\n\nexport type DriveInput = {\n global: {\n name: string;\n icon?: string | null;\n };\n id?: string;\n slug?: string;\n preferredEditor?: string;\n local?: Partial<DocumentDriveLocalState>;\n};\n\nexport type RemoteDriveAccessLevel = \"READ\" | \"WRITE\";\n\nexport type RemoteDriveOptions = DocumentDriveLocalState & {\n // TODO make local state optional\n pullFilter?: ListenerFilter;\n pullInterval?: number;\n expectedDriveInfo?: DriveInfo;\n accessLevel?: RemoteDriveAccessLevel;\n};\n\n/**\n * @deprecated In the future we will disallow this. Use the header field instead.\n */\nexport type LegacyCreateDocumentInput = {\n /**\n * @deprecated In the future we will disallow this. Use the header field instead.\n */\n id: string;\n documentType: string;\n};\n\nexport type CreateDocumentInputWithDocument<TDocument extends PHDocument> = {\n document: TDocument;\n};\n\nexport type CreateDocumentInputWithHeader = {\n header: PHDocumentHeader;\n};\n\nexport type CreateDocumentInputWithDocumentType = {\n documentType: string;\n};\n\nexport type CreateDocumentInput<TDocument extends PHDocument> =\n | LegacyCreateDocumentInput\n | CreateDocumentInputWithDocument<TDocument>\n | CreateDocumentInputWithHeader\n | CreateDocumentInputWithDocumentType;\n\nexport type IOperationResult<TDocument extends PHDocument = PHDocument> = {\n status: UpdateStatus;\n error?: OperationError;\n operations: Operation[];\n document: TDocument | undefined;\n signals: SignalResult[];\n};\n\nexport type DriveOperationResult = IOperationResult<DocumentDriveDocument>;\n\nexport type SynchronizationUnitId = {\n documentId: string;\n scope: string;\n branch: string;\n};\n\nexport type SynchronizationUnit = SynchronizationUnitId & {\n documentType: string;\n lastUpdated: string;\n revision: number;\n};\n\nexport type SynchronizationUnitQuery = Omit<\n SynchronizationUnit,\n \"revision\" | \"lastUpdated\"\n>;\n\nexport type ServerListener = {\n driveId: string;\n listenerId: string;\n label?: string;\n block: boolean;\n system: boolean;\n filter: ListenerFilter;\n callInfo?: ListenerCallInfo;\n transmitter?: ITransmitter;\n};\n\nexport type CreateListenerInput = {\n driveId: string;\n label?: string;\n block: boolean;\n system: boolean;\n filter: ListenerFilter;\n callInfo?: ListenerCallInfo;\n};\n\nexport enum ServerTransmitterType {\n Internal,\n SwitchboardPush,\n PullResponder,\n SecureConnect,\n MatrixConnect,\n RESTWebhook,\n}\n\nexport type ListenerRevision = {\n driveId: string;\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n status: UpdateStatus;\n revision: number;\n error?: string;\n};\n\nexport type ListenerRevisionWithError = Omit<ListenerRevision, \"error\"> & {\n error?: Error;\n};\n\nexport type ListenerUpdate = {\n listenerId: string;\n listenerRevisions: ListenerRevision[];\n};\n\nexport type UpdateStatus = \"SUCCESS\" | \"CONFLICT\" | \"MISSING\" | \"ERROR\";\nexport type ErrorStatus = Exclude<UpdateStatus, \"SUCCESS\">;\n\nexport type OperationUpdate = {\n actionId: string;\n timestampUtcMs: string;\n index: number;\n skip: number;\n type: string;\n input: object;\n hash: string;\n context?: ActionContext;\n id?: string;\n};\n\nexport type StrandUpdate = {\n driveId: string;\n documentId: string;\n documentType: string;\n scope: string;\n branch: string;\n operations: OperationUpdate[];\n};\n\nexport type SyncStatus = \"INITIAL_SYNC\" | \"SYNCING\" | UpdateStatus;\n\nexport type PullSyncStatus = SyncStatus;\nexport type PushSyncStatus = SyncStatus;\n\nexport type SyncUnitStatusObject = {\n push?: PushSyncStatus;\n pull?: PullSyncStatus;\n};\n\nexport type AddRemoteDriveStatus =\n | \"SUCCESS\"\n | \"ERROR\"\n | \"PENDING\"\n | \"ADDING\"\n | \"ALREADY_ADDED\";\n\nexport interface DriveEvents {\n syncStatus: (\n driveId: string,\n status: SyncStatus,\n error?: Error,\n syncUnitStatus?: SyncUnitStatusObject,\n scope?: string,\n branch?: string,\n ) => void;\n defaultRemoteDrive: (\n status: AddRemoteDriveStatus,\n defaultDrives: Map<string, DefaultRemoteDriveInfo>,\n driveInput: DefaultRemoteDriveInput,\n driveId?: string,\n driveName?: string,\n error?: Error,\n ) => void;\n strandUpdate: (update: StrandUpdate) => void;\n clientStrandsError: (\n driveId: string,\n trigger: Trigger,\n status: number,\n errorMessage: string,\n ) => void;\n documentModelModules: (documentModelModules: DocumentModelModule[]) => void;\n driveAdded: (drive: DocumentDriveDocument) => void;\n driveDeleted: (driveId: string) => void;\n documentAdded: (document: PHDocument) => void;\n documentDeleted: (documentId: string) => void;\n documentOperationsAdded: (\n documentId: string,\n operations: Operation[],\n ) => void;\n driveOperationsAdded: (driveId: string, operations: Operation[]) => void;\n operationsAdded: (documentId: string, operations: Operation[]) => void;\n}\n\nexport type PartialRecord<K extends keyof any, T> = {\n [P in K]?: T;\n};\n\nexport type RevisionsFilter = PartialRecord<string, number>;\n\nexport type GetDocumentOptions = ReducerOptions & {\n revisions?: RevisionsFilter;\n checkHashes?: boolean;\n};\n\nexport type AddOperationOptions = {\n forceSync?: boolean;\n source?: StrandUpdateSource;\n};\n\nexport type DefaultRemoteDriveInput = {\n url: string;\n options: RemoteDriveOptions;\n};\n\nexport type DefaultRemoteDriveInfo = DefaultRemoteDriveInput & {\n status: AddRemoteDriveStatus;\n metadata?: DriveInfo;\n};\n\nexport type RemoveDriveStrategy = \"remove\" | \"detach\";\n\n/**\n * Options for removing old remote drives.\n *\n * Allows specifying different strategies for handling old remote drives:\n *\n * - `remove-all`: Remove all remote drives.\n * - `preserve-all`: Preserve all remote drives (this is the default behavior).\n * - `remove-by-id`: Remove the remote drives specified by their IDs.\n * - `remove-by-url`: Remove the remote drives specified by their URLs.\n * - `preserve-by-id`: Preserve remote drives by their IDs and remove the rest.\n * - `preserve-by-url`: Preserve remote drives by their URLs and remove the rest.\n * - `detach-by-id`: Detach remote drives by their IDs (changes the remote drive to a local drive).\n * - `detach-by-url`: Detach remote drives by their URLs (changes the remote drive to a local drive).\n * - `preserve-by-id-and-detach`: Preserve the remote drives specified by their IDs and detach the rest.\n * - `preserve-by-url-and-detach`: Preserve the remote drives specified by their URLs and detach the rest.\n *\n * Each strategy is represented by an object with a `strategy` property and,\n * depending on the strategy, additional properties such as `ids` or `urls`.\n */\nexport type RemoveOldRemoteDrivesOption =\n | {\n strategy: \"remove-all\";\n }\n | {\n strategy: \"preserve-all\";\n }\n | {\n strategy: \"remove-by-id\";\n ids: string[];\n }\n | {\n strategy: \"remove-by-url\";\n urls: string[];\n }\n | {\n strategy: \"preserve-by-id\";\n ids: string[];\n }\n | {\n strategy: \"preserve-by-url\";\n urls: string[];\n }\n | {\n strategy: \"detach-by-id\";\n ids: string[];\n }\n | {\n strategy: \"detach-by-url\";\n urls: string[];\n }\n | {\n strategy: \"preserve-by-id-and-detach\";\n ids: string[];\n }\n | {\n strategy: \"preserve-by-url-and-detach\";\n urls: string[];\n };\n\nexport type DocumentDriveServerOptions = {\n defaultDrives?: {\n loadOnInit?: boolean; // defaults to true\n remoteDrives?: Array<DefaultRemoteDriveInput>;\n removeOldRemoteDrives?: RemoveOldRemoteDrivesOption;\n };\n /* method to queue heavy tasks that might block the event loop.\n * If set to null then it will queued as micro task.\n * Defaults to the most appropriate method according to the system\n */\n taskQueueMethod?: RunAsap<unknown> | null;\n listenerManager?: ListenerManagerOptions;\n jwtHandler?: (\n driveUrl: string,\n address: string | undefined,\n refresh?: boolean,\n ) => Promise<string>;\n featureFlags?: {\n enableDualActionCreate?: boolean;\n };\n};\n\nexport type GetStrandsOptions = {\n limit?: number;\n since?: string;\n fromRevision?: number;\n};\n\nexport type ListenerManagerOptions = {\n sequentialUpdates?: boolean;\n};\n\ntype PublicKeys<T> = {\n [K in keyof T]: T extends { [P in K]: T[K] } ? K : never;\n}[keyof T];\n\ntype PublicPart<T> = Pick<T, PublicKeys<T>>;\n\nexport interface IBaseDocumentDriveServer {\n initialize(): Promise<Error[] | null>;\n\n // todo: remove this once we have DI\n get listeners(): IListenerManager;\n\n setDocumentModelModules(models: DocumentModelModule<any>[]): void;\n getDrives(): Promise<string[]>;\n getDrivesSlugs(): Promise<string[]>;\n addDrive(\n input: DriveInput,\n preferredEditor?: string,\n ): Promise<DocumentDriveDocument>;\n addRemoteDrive(\n url: string,\n options: RemoteDriveOptions,\n ): Promise<DocumentDriveDocument>;\n deleteDrive(driveId: string): Promise<void>;\n getDrive(\n driveId: string,\n options?: GetDocumentOptions,\n ): Promise<DocumentDriveDocument>;\n\n getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;\n getDriveIdBySlug(\n slug: string,\n ): Promise<DocumentDriveDocument[\"header\"][\"id\"]>;\n\n addDocument<TDocument extends PHDocument>(\n input: TDocument,\n meta?: PHDocumentMeta,\n ): Promise<TDocument>;\n addDocument<TDocument extends PHDocument>(\n documentType: string,\n meta?: PHDocumentMeta,\n ): Promise<TDocument>;\n deleteDocument(documentId: string): Promise<void>;\n\n getDocuments(parentId: string): Promise<string[]>;\n\n getDocument<TDocument extends PHDocument>(\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<TDocument>;\n /**\n * @deprecated Use getDocument(documentId, options) instead. This method will be removed in the future.\n */\n getDocument<TDocument extends PHDocument>(\n driveId: string,\n documentId: string,\n options?: GetDocumentOptions,\n ): Promise<TDocument>;\n\n queueDocument<TDocument extends PHDocument>(\n input: CreateDocumentInput<TDocument>,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n addOperation(\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addOperation(documentId, operation, options) instead. This method will be removed in the future.\n */\n addOperation(\n driveId: string,\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n addOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addOperations(documentId, operations, options) instead. This method will be removed in the future.\n */\n addOperations(\n driveId: string,\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n queueOperation(\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueOperation(documentId, operation, options) instead. This method will be removed in the future.\n */\n queueOperation(\n driveId: string,\n documentId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n queueOperations(\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueOperations(documentId, operations, options) instead. This method will be removed in the future.\n */\n queueOperations(\n driveId: string,\n documentId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n queueAction(\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueAction(documentId, action, options) instead. This method will be removed in the future.\n */\n queueAction(\n driveId: string,\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n queueActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use queueActions(documentId, actions, options) instead. This method will be removed in the future.\n */\n queueActions(\n driveId: string,\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n /**\n * @deprecated Use the {@link addOperation} method instead.\n */\n addDriveOperation(\n driveId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link addOperations} method instead.\n */\n addDriveOperations(\n driveId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link queueOperation} method instead.\n */\n queueDriveOperation(\n driveId: string,\n operation: Operation,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link queueOperations} method instead.\n */\n queueDriveOperations(\n driveId: string,\n operations: Operation[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link queueAction} method instead.\n */\n queueDriveAction(\n driveId: string,\n action: DocumentDriveAction,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n /**\n * @deprecated Use the {@link queueActions} method instead.\n */\n queueDriveActions(\n driveId: string,\n actions: DocumentDriveAction[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n addAction(\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addAction(documentId, action, options) method instead. This method will be removed in the future.\n */\n addAction(\n driveId: string,\n documentId: string,\n action: Action,\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n addActions(\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n /**\n * @deprecated Use addActions(documentId, actions, options) instead. This method will be removed in the future.\n */\n addActions(\n driveId: string,\n documentId: string,\n actions: Action[],\n options?: AddOperationOptions,\n ): Promise<IOperationResult>;\n\n /**\n * @deprecated Use the {@link addAction} method with a {@link AddFileAction} and call {@link addDocument} if the document needs to be created.\n */\n addDriveAction(\n driveId: string,\n action: LegacyAddFileAction,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link addAction} method instead.\n */\n addDriveAction(\n driveId: string,\n\n action: DocumentDriveAction,\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n /**\n * @deprecated Use the {@link addActions} method instead.\n */\n addDriveActions(\n driveId: string,\n actions: DocumentDriveAction[],\n options?: AddOperationOptions,\n ): Promise<DriveOperationResult>;\n\n getSyncStatus(\n documentId: string,\n scope?: string,\n branch?: string,\n ): SyncStatus | SynchronizationUnitNotFoundError;\n\n /** Internal methods **/\n getDocumentModelModules(): DocumentModelModule[];\n\n on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe;\n\n setGenerateJwtHandler(handler: (driveUrl: string) => Promise<string>): void;\n removeJwtHandler(): void;\n generateJwtHandler?: (driveUrl: string) => Promise<string>;\n}\n\nexport type IDocumentDriveServer = IBaseDocumentDriveServer &\n IDefaultDrivesManager &\n IReadModeDriveServer;\n\nexport type DriveUpdateErrorHandler = (\n error: Error,\n driveId: string,\n listener: ListenerState,\n) => void;\n\nexport interface IListenerManager {\n initialize(handler: DriveUpdateErrorHandler): Promise<void>;\n\n removeDrive(driveId: DocumentDriveDocument[\"header\"][\"id\"]): Promise<void>;\n driveHasListeners(driveId: string): boolean;\n\n setListener(driveId: string, listener: ServerListener): Promise<void>;\n removeListener(driveId: string, listenerId: string): Promise<boolean>;\n getListenerState(driveId: string, listenerId: string): ListenerState;\n\n getStrands(\n driveId: string,\n listenerId: string,\n options?: GetStrandsOptions,\n ): Promise<StrandUpdate[]>;\n updateSynchronizationRevisions(\n syncUnits: SynchronizationUnit[],\n source: StrandUpdateSource,\n willUpdate?: (listeners: ServerListener[]) => void,\n onError?: (error: Error, driveId: string, listener: ListenerState) => void,\n forceSync?: boolean,\n ): Promise<ListenerUpdate[]>;\n updateListenerRevision(\n listenerId: string,\n driveId: string,\n syncUnitId: SynchronizationUnitId,\n listenerRev: number,\n ): Promise<void>;\n removeSyncUnits(\n parentId: string,\n syncUnits: SynchronizationUnitId[],\n ): Promise<void>;\n\n setGenerateJwtHandler(handler: (driveUrl: string) => Promise<string>): void;\n removeJwtHandler(): void;\n generateJwtHandler?: (driveUrl: string) => Promise<string>;\n}\n\nexport type ListenerStatus =\n | \"CREATED\"\n | \"PENDING\"\n | \"SUCCESS\"\n | \"MISSING\"\n | \"CONFLICT\"\n | \"ERROR\";\n\nexport type SynchronizationUnitMap = ISyncUnitMap<SyncronizationUnitState>;\n\nexport interface ListenerState {\n driveId: string;\n block: boolean;\n pendingTimeout: string;\n listener: ServerListener;\n syncUnits: SynchronizationUnitMap;\n listenerStatus: ListenerStatus;\n}\n\nexport interface SyncronizationUnitState {\n listenerRev: number;\n lastUpdated: string;\n}\n\nexport interface ITransmitterFactory {\n instance(\n transmitterType: string,\n listener: ServerListener,\n driveServer: IBaseDocumentDriveServer,\n ): ITransmitter;\n}\n\nexport interface IEventEmitter {\n emit<K extends keyof DriveEvents>(\n event: K,\n ...args: Parameters<DriveEvents[K]>\n ): void;\n\n on<K extends keyof DriveEvents>(event: K, cb: DriveEvents[K]): Unsubscribe;\n}\n\nexport interface ISynchronizationManager {\n setDocumentModelModules(arg0: DocumentModelModule[]): void;\n getSynchronizationUnits(\n parentId?: string,\n documentId?: string[],\n scope?: string[],\n branch?: string[],\n documentType?: string[],\n ): Promise<SynchronizationUnit[]>;\n\n getSynchronizationUnitsIds(\n parentId?: string,\n documentId?: string[],\n scope?: string[],\n branch?: string[],\n documentType?: string[],\n ): Promise<SynchronizationUnitQuery[]>;\n\n getSynchronizationUnit(\n syncId: SynchronizationUnitId,\n ): Promise<SynchronizationUnit | undefined>;\n\n getOperationData(\n syncId: SynchronizationUnitId,\n filter: GetStrandsOptions,\n ): Promise<OperationUpdate[]>;\n\n // Overloaded sync status methods\n getSyncStatus(\n documentId: string,\n scope?: string,\n branch?: string,\n ): SyncStatus | SynchronizationUnitNotFoundError;\n getSyncStatus(\n syncId: SynchronizationUnitId,\n ): SyncStatus | SynchronizationUnitNotFoundError;\n\n // Overloaded sync status update methods\n updateSyncStatus(\n documentId: string,\n status: Partial<SyncUnitStatusObject> | null,\n error?: Error,\n scope?: string,\n branch?: string,\n ): void;\n updateSyncStatus(\n syncId: SynchronizationUnitId,\n status: Partial<SyncUnitStatusObject> | null,\n error?: Error,\n ): void;\n\n initializeDriveSyncStatus(\n driveId: string,\n drive: DocumentDriveDocument,\n ): Promise<void>;\n\n getCombinedSyncUnitStatus(syncUnitStatus: SyncUnitStatusObject): SyncStatus;\n}\n\nexport type SharingType = \"LOCAL\" | \"CLOUD\" | \"PUBLIC\";\n\nexport type DocumentDriveServerConstructor =\n Constructor<BaseDocumentDriveServer>;\n\nexport type DocumentDriveServerMixin<I> = Mixin<\n typeof BaseDocumentDriveServer,\n I\n>;\n\n/**\n * Interface for a specialized Map implementation that manages synchronization units.\n * Each unit is identified by a SynchronizationUnitId which consists of documentId, scope, and branch.\n */\nexport interface ISyncUnitMap<Value> {\n set(id: SynchronizationUnitId, state: Value): this;\n get(id: SynchronizationUnitId): Value | undefined;\n has(id: SynchronizationUnitId): boolean;\n delete(id: SynchronizationUnitId): boolean;\n clear(): void;\n get size(): number;\n keys(): IterableIterator<SynchronizationUnitId>;\n values(): IterableIterator<Value>;\n entries(): IterableIterator<[SynchronizationUnitId, Value]>;\n [Symbol.iterator](): IterableIterator<[SynchronizationUnitId, Value]>;\n forEach(\n callbackfn: (\n value: Value,\n key: SynchronizationUnitId,\n map: ISyncUnitMap<Value>,\n ) => void,\n thisArg?: any,\n ): void;\n deleteByDocumentId(documentId: string): void;\n deleteByDocumentIdAndScope(documentId: string, scope: string): void;\n getAllByDocumentId(documentId: string): [SynchronizationUnitId, Value][];\n getAllByDocumentIdAndScope(\n documentId: string,\n scope: string,\n ): [SynchronizationUnitId, Value][];\n}\n"],"mappings":"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"}
|