document-drive 6.0.0-dev.105 → 6.0.0-dev.106
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
|
@@ -1,2000 +0,0 @@
|
|
|
1
|
-
import { isActionJob, isDocumentJob, isOperationJob, } from "document-drive/queue/utils";
|
|
2
|
-
import { ReadModeServer } from "document-drive/read-mode/server";
|
|
3
|
-
import { DefaultDrivesManager } from "document-drive/utils/default-drives-manager";
|
|
4
|
-
import { requestPublicDriveWithTokenFromReactor } from "document-drive/utils/graphql";
|
|
5
|
-
import { childLogger } from "document-drive/utils/logger";
|
|
6
|
-
import { isDocumentDrive } from "document-drive/utils/misc";
|
|
7
|
-
import { runAsap, runAsapAsync } from "document-drive/utils/run-asap";
|
|
8
|
-
import { attachBranch, createPresignedHeader, defaultBaseState, deriveOperationId, diffOperations, garbageCollect, garbageCollectDocumentOperations, generateId, groupOperationsByScope, hashDocumentStateForScope, merge, precedes, removeExistingOperations, replayDocument, reshuffleByTimestamp, skipHeaderOperations, sortOperations, validateHeader, } from "document-model/core";
|
|
9
|
-
import { ClientError } from "graphql-request";
|
|
10
|
-
import { driveCreateDocument, driveCreateState, removeListener, removeTrigger, setSharingType, } from "../drive-document-model/index.js";
|
|
11
|
-
import { ConflictOperationError, DocumentAlreadyExistsError, OperationError, } from "./error.js";
|
|
12
|
-
import { DefaultListenerManagerOptions } from "./listener/constants.js";
|
|
13
|
-
import { PullResponderTransmitter } from "./transmitter/pull-responder.js";
|
|
14
|
-
import { SwitchboardPushTransmitter } from "./transmitter/switchboard-push.js";
|
|
15
|
-
import { filterOperationsByRevision, isAtRevision, resolveCreateDocumentInput, } from "./utils.js";
|
|
16
|
-
export class BaseDocumentDriveServer {
|
|
17
|
-
logger = childLogger(["BaseDocumentDriveServer"]);
|
|
18
|
-
// external dependencies
|
|
19
|
-
documentModelModules;
|
|
20
|
-
legacyStorage;
|
|
21
|
-
documentStorage;
|
|
22
|
-
cache;
|
|
23
|
-
queueManager;
|
|
24
|
-
eventEmitter;
|
|
25
|
-
options;
|
|
26
|
-
listenerManager;
|
|
27
|
-
synchronizationManager;
|
|
28
|
-
generateJwtHandler;
|
|
29
|
-
// internal dependencies
|
|
30
|
-
defaultDrivesManager;
|
|
31
|
-
defaultDrivesManagerDelegate = {
|
|
32
|
-
detachDrive: this.detachDrive.bind(this),
|
|
33
|
-
emit: (...args) => this.eventEmitter.emit("defaultRemoteDrive", ...args),
|
|
34
|
-
};
|
|
35
|
-
queueDelegate = {
|
|
36
|
-
exists: (documentId) => this.documentStorage.exists(documentId),
|
|
37
|
-
processOperationJob: async ({ documentId, operations, options, }) => {
|
|
38
|
-
const document = await this.getDocument(documentId);
|
|
39
|
-
return isDocumentDrive(document)
|
|
40
|
-
? this.processDriveOperations(documentId, operations, options)
|
|
41
|
-
: this.processOperations(documentId, operations, options);
|
|
42
|
-
},
|
|
43
|
-
processActionJob: async ({ documentId, actions, options }) => {
|
|
44
|
-
const document = await this.getDocument(documentId);
|
|
45
|
-
return isDocumentDrive(document)
|
|
46
|
-
? this.processDriveActions(documentId, actions, options)
|
|
47
|
-
: this.processActions(documentId, actions, options);
|
|
48
|
-
},
|
|
49
|
-
processDocumentJob: async ({ documentId, documentType, header: inputHeader, initialState, options, }) => {
|
|
50
|
-
const documentModelModule = this.getDocumentModelModule(documentType);
|
|
51
|
-
const document = documentModelModule.utils.createDocument(initialState);
|
|
52
|
-
// TODO: header must be included
|
|
53
|
-
const header = createPresignedHeader(documentId, documentType);
|
|
54
|
-
document.header.id = documentId;
|
|
55
|
-
document.header.sig = header.sig;
|
|
56
|
-
document.header.documentType = documentType;
|
|
57
|
-
if (inputHeader) {
|
|
58
|
-
document.header.meta = inputHeader.meta;
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
const createdDocument = await this.createDocument({ document }, options?.source ?? { type: "local" }, document.header.meta);
|
|
62
|
-
return {
|
|
63
|
-
status: "SUCCESS",
|
|
64
|
-
operations: [],
|
|
65
|
-
document: createdDocument,
|
|
66
|
-
signals: [],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
const cause = error instanceof Error ? error : new Error(JSON.stringify(error));
|
|
71
|
-
return {
|
|
72
|
-
status: "ERROR",
|
|
73
|
-
error: new OperationError("ERROR", undefined, `Error creating document: ${cause.message}`, cause),
|
|
74
|
-
operations: [],
|
|
75
|
-
document: undefined,
|
|
76
|
-
signals: [],
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
processJob: async (job) => {
|
|
81
|
-
if (isOperationJob(job)) {
|
|
82
|
-
return this.queueDelegate.processOperationJob(job);
|
|
83
|
-
}
|
|
84
|
-
else if (isActionJob(job)) {
|
|
85
|
-
return this.queueDelegate.processActionJob(job);
|
|
86
|
-
}
|
|
87
|
-
else if (isDocumentJob(job)) {
|
|
88
|
-
return this.queueDelegate.processDocumentJob(job);
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
throw new Error("Unknown job type", job);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
// internal state
|
|
96
|
-
triggerMap = new Map();
|
|
97
|
-
initializePromise;
|
|
98
|
-
enableDualActionCreate;
|
|
99
|
-
constructor(documentModelModules, storage, documentStorage, cache, queueManager, eventEmitter, synchronizationManager, listenerManager, options) {
|
|
100
|
-
this.documentModelModules = documentModelModules;
|
|
101
|
-
this.legacyStorage = storage;
|
|
102
|
-
this.documentStorage = documentStorage;
|
|
103
|
-
this.cache = cache;
|
|
104
|
-
this.queueManager = queueManager;
|
|
105
|
-
this.eventEmitter = eventEmitter;
|
|
106
|
-
this.synchronizationManager = synchronizationManager;
|
|
107
|
-
this.listenerManager = listenerManager;
|
|
108
|
-
this.options = {
|
|
109
|
-
...options,
|
|
110
|
-
defaultDrives: {
|
|
111
|
-
...options?.defaultDrives,
|
|
112
|
-
},
|
|
113
|
-
listenerManager: {
|
|
114
|
-
...DefaultListenerManagerOptions,
|
|
115
|
-
...options?.listenerManager,
|
|
116
|
-
},
|
|
117
|
-
jwtHandler: options?.jwtHandler === undefined
|
|
118
|
-
? () => Promise.resolve("")
|
|
119
|
-
: options.jwtHandler,
|
|
120
|
-
taskQueueMethod: options?.taskQueueMethod === undefined
|
|
121
|
-
? runAsap
|
|
122
|
-
: options.taskQueueMethod,
|
|
123
|
-
featureFlags: {
|
|
124
|
-
...options?.featureFlags,
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
this.enableDualActionCreate =
|
|
128
|
-
options?.featureFlags?.enableDualActionCreate ?? false;
|
|
129
|
-
if (this.enableDualActionCreate) {
|
|
130
|
-
this.logger.warn("Dual action create is enabled.");
|
|
131
|
-
}
|
|
132
|
-
// todo: move to external dependencies
|
|
133
|
-
this.defaultDrivesManager = new DefaultDrivesManager(this, this.defaultDrivesManagerDelegate, options);
|
|
134
|
-
this.initializePromise = this._initialize();
|
|
135
|
-
}
|
|
136
|
-
// workaround for testing the ephemeral listeners -- we don't have DI in place yet
|
|
137
|
-
// todo: remove this once we have DI
|
|
138
|
-
get listeners() {
|
|
139
|
-
return this.listenerManager;
|
|
140
|
-
}
|
|
141
|
-
initialize() {
|
|
142
|
-
return this.initializePromise;
|
|
143
|
-
}
|
|
144
|
-
async _initialize() {
|
|
145
|
-
await this.listenerManager.initialize(this.handleListenerError.bind(this));
|
|
146
|
-
await this.queueManager.init(this.queueDelegate, (error) => {
|
|
147
|
-
this.logger.error("Error initializing queue manager: @error", error);
|
|
148
|
-
// errors.push(error);
|
|
149
|
-
});
|
|
150
|
-
try {
|
|
151
|
-
await this.defaultDrivesManager.removeOldremoteDrives();
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
this.logger.error("@error", error);
|
|
155
|
-
}
|
|
156
|
-
const errors = [];
|
|
157
|
-
const drives = await this.getDrives();
|
|
158
|
-
for (const drive of drives) {
|
|
159
|
-
await this._initializeDrive(drive).catch((error) => {
|
|
160
|
-
this.logger.error("Error initializing drive @drive: @error", drive, error);
|
|
161
|
-
errors.push(error);
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
if (this.options.defaultDrives.loadOnInit !== false) {
|
|
165
|
-
await this.defaultDrivesManager.initializeDefaultRemoteDrives();
|
|
166
|
-
}
|
|
167
|
-
return errors.length === 0 ? null : errors;
|
|
168
|
-
}
|
|
169
|
-
setDocumentModelModules(modules) {
|
|
170
|
-
this.documentModelModules = [...modules];
|
|
171
|
-
this.synchronizationManager.setDocumentModelModules([...modules]);
|
|
172
|
-
this.eventEmitter.emit("documentModelModules", [...modules]);
|
|
173
|
-
}
|
|
174
|
-
initializeDefaultRemoteDrives() {
|
|
175
|
-
return this.defaultDrivesManager.initializeDefaultRemoteDrives();
|
|
176
|
-
}
|
|
177
|
-
getDefaultRemoteDrives() {
|
|
178
|
-
return this.defaultDrivesManager.getDefaultRemoteDrives();
|
|
179
|
-
}
|
|
180
|
-
setDefaultDriveAccessLevel(url, level) {
|
|
181
|
-
return this.defaultDrivesManager.setDefaultDriveAccessLevel(url, level);
|
|
182
|
-
}
|
|
183
|
-
setAllDefaultDrivesAccessLevel(level) {
|
|
184
|
-
return this.defaultDrivesManager.setAllDefaultDrivesAccessLevel(level);
|
|
185
|
-
}
|
|
186
|
-
getOperationSource(source) {
|
|
187
|
-
return source.type === "local" ? "push" : "pull";
|
|
188
|
-
}
|
|
189
|
-
handleListenerError(error, driveId, listener) {
|
|
190
|
-
this.logger.error("Listener @listenerId error: @error", listener.listener.label ?? listener.listener.listenerId, error);
|
|
191
|
-
const status = error instanceof OperationError ? error.status : "ERROR";
|
|
192
|
-
this.synchronizationManager.updateSyncStatus(driveId, { push: status }, error);
|
|
193
|
-
}
|
|
194
|
-
shouldSyncRemoteDrive(drive) {
|
|
195
|
-
return (drive.state.local.availableOffline &&
|
|
196
|
-
drive.state.local.triggers.length > 0);
|
|
197
|
-
}
|
|
198
|
-
async startSyncRemoteDrive(driveId) {
|
|
199
|
-
let driveTriggers = this.triggerMap.get(driveId);
|
|
200
|
-
const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
|
|
201
|
-
const drive = await this.getDrive(driveId);
|
|
202
|
-
for (const trigger of drive.state.local.triggers) {
|
|
203
|
-
if (driveTriggers?.get(trigger.id)) {
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
if (!driveTriggers) {
|
|
207
|
-
driveTriggers = new Map();
|
|
208
|
-
}
|
|
209
|
-
this.synchronizationManager.updateSyncStatus(driveId, {
|
|
210
|
-
pull: "SYNCING",
|
|
211
|
-
});
|
|
212
|
-
for (const syncUnit of syncUnits) {
|
|
213
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, {
|
|
214
|
-
pull: "SYNCING",
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
if (PullResponderTransmitter.isPullResponderTrigger(trigger)) {
|
|
218
|
-
let firstPull = true;
|
|
219
|
-
const cancelPullLoop = PullResponderTransmitter.setupPull(driveId, trigger, this.saveStrand.bind(this), (error) => {
|
|
220
|
-
const statusError = error instanceof OperationError ? error.status : "ERROR";
|
|
221
|
-
this.synchronizationManager.updateSyncStatus(driveId, { pull: statusError }, error);
|
|
222
|
-
if (error instanceof ClientError) {
|
|
223
|
-
this.eventEmitter.emit("clientStrandsError", driveId, trigger, error.response.status, error.message);
|
|
224
|
-
}
|
|
225
|
-
}, async (revisions) => {
|
|
226
|
-
const errorRevisions = revisions.filter((r) => r.status !== "SUCCESS");
|
|
227
|
-
if (errorRevisions.length < 1) {
|
|
228
|
-
this.synchronizationManager.updateSyncStatus(driveId, {
|
|
229
|
-
pull: "SUCCESS",
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
for (const revision of revisions) {
|
|
233
|
-
const { documentId, scope, branch, status, error } = revision;
|
|
234
|
-
this.synchronizationManager.updateSyncStatus({ documentId, scope, branch }, { pull: status }, error);
|
|
235
|
-
}
|
|
236
|
-
// if it is the first pull and returns empty
|
|
237
|
-
// then updates drive documents to "SUCCESS" and
|
|
238
|
-
// updates corresponding push transmitter
|
|
239
|
-
if (firstPull) {
|
|
240
|
-
firstPull = false;
|
|
241
|
-
const syncUnitsIds = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
|
|
242
|
-
const unchangedSyncUnits = syncUnitsIds.filter((syncUnit) => {
|
|
243
|
-
return !revisions.find((revision) => {
|
|
244
|
-
return (revision.documentId === syncUnit.documentId &&
|
|
245
|
-
revision.scope === syncUnit.scope &&
|
|
246
|
-
revision.branch === syncUnit.branch);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
unchangedSyncUnits.forEach((syncUnit) => {
|
|
250
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, {
|
|
251
|
-
pull: "SUCCESS",
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
const pushListener = drive.state.local.listeners.find((listener) => trigger.data.url === listener.callInfo?.data);
|
|
255
|
-
if (pushListener) {
|
|
256
|
-
for (const revision of revisions) {
|
|
257
|
-
const { documentId, scope, branch } = revision;
|
|
258
|
-
this.listenerManager
|
|
259
|
-
.updateListenerRevision(pushListener.listenerId, driveId, { documentId, scope, branch }, revision.revision)
|
|
260
|
-
.catch((e) => this.logger.error("@error", e));
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}, undefined, this.listeners);
|
|
265
|
-
driveTriggers.set(trigger.id, cancelPullLoop);
|
|
266
|
-
this.triggerMap.set(driveId, driveTriggers);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
async stopSyncRemoteDrive(driveId) {
|
|
271
|
-
const triggers = this.triggerMap.get(driveId);
|
|
272
|
-
triggers?.forEach((cancel) => cancel());
|
|
273
|
-
this.synchronizationManager.updateSyncStatus(driveId, null);
|
|
274
|
-
const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
|
|
275
|
-
for (const syncUnit of syncUnits) {
|
|
276
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, null);
|
|
277
|
-
}
|
|
278
|
-
return this.triggerMap.delete(driveId);
|
|
279
|
-
}
|
|
280
|
-
async _initializeDrive(driveId) {
|
|
281
|
-
const drive = await this.getDrive(driveId);
|
|
282
|
-
this.logger.verbose('[SYNC DEBUG] Initializing drive @driveId with slug "@slug"', driveId, drive.header.slug);
|
|
283
|
-
await this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);
|
|
284
|
-
if (this.shouldSyncRemoteDrive(drive)) {
|
|
285
|
-
this.logger.verbose("[SYNC DEBUG] Starting sync for remote drive @driveId", driveId);
|
|
286
|
-
await this.startSyncRemoteDrive(driveId);
|
|
287
|
-
}
|
|
288
|
-
// add switchboard push listeners
|
|
289
|
-
this.logger.verbose("[SYNC DEBUG] Processing @count listeners for drive @driveId", drive.state.local.listeners.length, driveId);
|
|
290
|
-
for (const zodListener of drive.state.local.listeners) {
|
|
291
|
-
if (zodListener.callInfo?.transmitterType === "SwitchboardPush") {
|
|
292
|
-
this.logger.verbose("[SYNC DEBUG] Setting up SwitchboardPush listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
|
|
293
|
-
const transmitter = new SwitchboardPushTransmitter(zodListener.callInfo.data ?? "", this.listeners);
|
|
294
|
-
this.logger.verbose("[SYNC DEBUG] Created SwitchboardPush transmitter with URL: @url", zodListener.callInfo.data || "none");
|
|
295
|
-
await this.listenerManager
|
|
296
|
-
.setListener(driveId, {
|
|
297
|
-
block: zodListener.block,
|
|
298
|
-
driveId: drive.header.id,
|
|
299
|
-
filter: {
|
|
300
|
-
branch: zodListener.filter.branch ?? [],
|
|
301
|
-
documentId: zodListener.filter.documentId ?? [],
|
|
302
|
-
documentType: zodListener.filter.documentType ?? [],
|
|
303
|
-
scope: zodListener.filter.scope ?? [],
|
|
304
|
-
},
|
|
305
|
-
listenerId: zodListener.listenerId,
|
|
306
|
-
callInfo: zodListener.callInfo,
|
|
307
|
-
system: zodListener.system,
|
|
308
|
-
label: zodListener.label ?? "",
|
|
309
|
-
transmitter,
|
|
310
|
-
})
|
|
311
|
-
.then(() => {
|
|
312
|
-
this.logger.verbose("[SYNC DEBUG] Successfully set up listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
else if (zodListener.callInfo?.transmitterType === "PullResponder") {
|
|
316
|
-
this.logger.verbose("[SYNC DEBUG] Setting up PullResponder listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
|
|
317
|
-
const pullResponderListener = {
|
|
318
|
-
driveId,
|
|
319
|
-
listenerId: zodListener.listenerId,
|
|
320
|
-
block: false,
|
|
321
|
-
filter: zodListener.filter,
|
|
322
|
-
system: false,
|
|
323
|
-
label: `PullResponder #${zodListener.listenerId}`,
|
|
324
|
-
callInfo: {
|
|
325
|
-
data: "",
|
|
326
|
-
name: "PullResponder",
|
|
327
|
-
transmitterType: "PullResponder",
|
|
328
|
-
},
|
|
329
|
-
};
|
|
330
|
-
const pullResponder = new PullResponderTransmitter(pullResponderListener, this.listenerManager);
|
|
331
|
-
pullResponderListener.transmitter = pullResponder;
|
|
332
|
-
await this.listenerManager.setListener(driveId, pullResponderListener);
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
this.logger.error("Skipping listener @listenerId with unsupported type @transmitterType", zodListener.listenerId, zodListener.callInfo?.transmitterType || "unknown");
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
getDocumentModelModule(documentType) {
|
|
340
|
-
const documentModelModule = this.documentModelModules.find((module) => module.documentModel.global.id === documentType);
|
|
341
|
-
if (!documentModelModule) {
|
|
342
|
-
throw new Error(`Document type ${documentType} not supported`);
|
|
343
|
-
}
|
|
344
|
-
return documentModelModule;
|
|
345
|
-
}
|
|
346
|
-
getDocumentModelModules() {
|
|
347
|
-
return [...this.documentModelModules];
|
|
348
|
-
}
|
|
349
|
-
addDocument(documentOrType, meta) {
|
|
350
|
-
const input = typeof documentOrType === "string"
|
|
351
|
-
? { documentType: documentOrType }
|
|
352
|
-
: { document: documentOrType };
|
|
353
|
-
return this.createDocument(input, { type: "local" }, meta);
|
|
354
|
-
}
|
|
355
|
-
async addDrive(input, preferredEditor) {
|
|
356
|
-
// Create document with custom global and local state
|
|
357
|
-
const { global } = driveCreateState();
|
|
358
|
-
const document = driveCreateDocument({
|
|
359
|
-
global: {
|
|
360
|
-
...global,
|
|
361
|
-
name: input.global.name ?? global.name,
|
|
362
|
-
icon: input.global.icon ?? global.icon,
|
|
363
|
-
},
|
|
364
|
-
local: {
|
|
365
|
-
availableOffline: input.local?.availableOffline ?? false,
|
|
366
|
-
sharingType: input.local?.sharingType ?? "public",
|
|
367
|
-
listeners: input.local?.listeners ?? [],
|
|
368
|
-
triggers: input.local?.triggers ?? [],
|
|
369
|
-
},
|
|
370
|
-
});
|
|
371
|
-
if (input.id && input.id.length > 0) {
|
|
372
|
-
document.header.id = input.id;
|
|
373
|
-
}
|
|
374
|
-
if (input.slug && input.slug.length > 0) {
|
|
375
|
-
document.header.slug = input.slug;
|
|
376
|
-
}
|
|
377
|
-
if (input.global.name) {
|
|
378
|
-
document.header.name = input.global.name;
|
|
379
|
-
}
|
|
380
|
-
const editorToUse = input.preferredEditor || preferredEditor;
|
|
381
|
-
if (editorToUse) {
|
|
382
|
-
document.header.meta = {
|
|
383
|
-
preferredEditor: editorToUse,
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
await this.documentStorage.create(document);
|
|
387
|
-
if (input.slug && input.slug.length > 0) {
|
|
388
|
-
await this.cache.deleteDriveBySlug(input.slug);
|
|
389
|
-
}
|
|
390
|
-
await this._initializeDrive(document.header.id);
|
|
391
|
-
this.eventEmitter.emit("driveAdded", document);
|
|
392
|
-
return document;
|
|
393
|
-
}
|
|
394
|
-
async addRemoteDrive(url, options) {
|
|
395
|
-
const token = await this.generateJwtHandler?.(url);
|
|
396
|
-
const headers = token
|
|
397
|
-
? { Authorization: `Bearer ${token}` }
|
|
398
|
-
: {};
|
|
399
|
-
const { id, name, slug, icon, meta } = options.expectedDriveInfo ||
|
|
400
|
-
(await requestPublicDriveWithTokenFromReactor(url, this));
|
|
401
|
-
const { pullFilter, pullInterval, availableOffline, sharingType, listeners, triggers, } = options;
|
|
402
|
-
const pullTrigger = await PullResponderTransmitter.createPullResponderTrigger(id, url, {
|
|
403
|
-
pullFilter,
|
|
404
|
-
pullInterval,
|
|
405
|
-
}, this.listeners);
|
|
406
|
-
return await this.addDrive({
|
|
407
|
-
id,
|
|
408
|
-
slug,
|
|
409
|
-
global: {
|
|
410
|
-
name,
|
|
411
|
-
icon,
|
|
412
|
-
},
|
|
413
|
-
local: {
|
|
414
|
-
triggers: [...triggers, pullTrigger],
|
|
415
|
-
listeners: listeners,
|
|
416
|
-
availableOffline,
|
|
417
|
-
sharingType,
|
|
418
|
-
},
|
|
419
|
-
}, meta?.preferredEditor);
|
|
420
|
-
}
|
|
421
|
-
async deleteDrive(driveId) {
|
|
422
|
-
const result = await Promise.allSettled([
|
|
423
|
-
this.stopSyncRemoteDrive(driveId),
|
|
424
|
-
this.listenerManager.removeDrive(driveId),
|
|
425
|
-
this.cache.deleteDrive(driveId),
|
|
426
|
-
this.documentStorage.delete(driveId),
|
|
427
|
-
]);
|
|
428
|
-
this.eventEmitter.emit("driveDeleted", driveId);
|
|
429
|
-
result.forEach((r) => {
|
|
430
|
-
if (r.status === "rejected") {
|
|
431
|
-
throw r.reason;
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
// TODO: paginate
|
|
436
|
-
async getDrives() {
|
|
437
|
-
const drives = [];
|
|
438
|
-
let cursor;
|
|
439
|
-
do {
|
|
440
|
-
const { documents, nextCursor } = await this.documentStorage.findByType("powerhouse/document-drive", 100, cursor);
|
|
441
|
-
drives.push(...documents);
|
|
442
|
-
cursor = nextCursor;
|
|
443
|
-
} while (cursor);
|
|
444
|
-
return drives;
|
|
445
|
-
}
|
|
446
|
-
// TODO: paginate, move into IReactorClient eventually
|
|
447
|
-
async getDrivesSlugs() {
|
|
448
|
-
const drives = await this.getDrives();
|
|
449
|
-
return this.documentStorage.resolveSlugs(drives);
|
|
450
|
-
}
|
|
451
|
-
async getDrive(driveId, options) {
|
|
452
|
-
let document;
|
|
453
|
-
try {
|
|
454
|
-
const cachedDocument = await this.cache.getDrive(driveId); // TODO support GetDocumentOptions
|
|
455
|
-
if (cachedDocument && isDocumentDrive(cachedDocument)) {
|
|
456
|
-
document = cachedDocument;
|
|
457
|
-
if (isAtRevision(document, options?.revisions)) {
|
|
458
|
-
return document;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
catch (e) {
|
|
463
|
-
this.logger.error("Error getting drive from cache: @error", e);
|
|
464
|
-
}
|
|
465
|
-
const driveStorage = document ?? (await this.documentStorage.get(driveId));
|
|
466
|
-
const result = this._buildDocument(driveStorage, options);
|
|
467
|
-
if (!isDocumentDrive(result)) {
|
|
468
|
-
throw new Error(`Document with id ${driveId} is not a Document Drive`);
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
if (!options?.revisions) {
|
|
472
|
-
this.cache
|
|
473
|
-
.setDocument(driveId, result)
|
|
474
|
-
.catch((e) => this.logger.error("@error", e));
|
|
475
|
-
this.cache
|
|
476
|
-
.setDrive(driveId, result)
|
|
477
|
-
.catch((e) => this.logger.error("@error", e));
|
|
478
|
-
}
|
|
479
|
-
return result;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
async getDriveBySlug(slug, options) {
|
|
483
|
-
try {
|
|
484
|
-
const drive = await this.cache.getDriveBySlug(slug);
|
|
485
|
-
if (drive) {
|
|
486
|
-
return drive;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
catch (e) {
|
|
490
|
-
this.logger.error("Error getting drive from cache: @error", e);
|
|
491
|
-
}
|
|
492
|
-
const driveStorage = await this.documentStorage.getBySlug(slug);
|
|
493
|
-
const document = this._buildDocument(driveStorage, options);
|
|
494
|
-
if (!isDocumentDrive(document)) {
|
|
495
|
-
throw new Error(`Document with slug ${slug} is not a Document Drive`);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
this.cache
|
|
499
|
-
.setDriveBySlug(slug, document)
|
|
500
|
-
.catch((e) => this.logger.error("@error", e));
|
|
501
|
-
return document;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
async getDriveIdBySlug(slug) {
|
|
505
|
-
try {
|
|
506
|
-
const drive = await this.cache.getDriveBySlug(slug);
|
|
507
|
-
if (drive) {
|
|
508
|
-
return drive.header.id;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
catch (e) {
|
|
512
|
-
this.logger.error("Error getting drive from cache: @error", e);
|
|
513
|
-
}
|
|
514
|
-
const driveStorage = await this.documentStorage.getBySlug(slug);
|
|
515
|
-
return driveStorage.header.id;
|
|
516
|
-
}
|
|
517
|
-
getDocument(driveId, documentId, options) {
|
|
518
|
-
const id = typeof documentId === "string" ? documentId : driveId;
|
|
519
|
-
const resolvedOptions = typeof documentId === "object" ? documentId : options;
|
|
520
|
-
return this._getDocument(id, resolvedOptions);
|
|
521
|
-
}
|
|
522
|
-
async _getDocument(documentId, options) {
|
|
523
|
-
let cachedDocument;
|
|
524
|
-
try {
|
|
525
|
-
cachedDocument = await this.cache.getDocument(documentId); // TODO support GetDocumentOptions
|
|
526
|
-
if (cachedDocument && isAtRevision(cachedDocument, options?.revisions)) {
|
|
527
|
-
return cachedDocument;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
catch (e) {
|
|
531
|
-
this.logger.error("Error getting document from cache: @error", e);
|
|
532
|
-
}
|
|
533
|
-
const documentStorage = cachedDocument ?? (await this.documentStorage.get(documentId));
|
|
534
|
-
const document = this._buildDocument(documentStorage, options);
|
|
535
|
-
if (!options?.revisions) {
|
|
536
|
-
this.cache
|
|
537
|
-
.setDocument(documentId, document)
|
|
538
|
-
.catch((e) => this.logger.error("@error", e));
|
|
539
|
-
}
|
|
540
|
-
return document;
|
|
541
|
-
}
|
|
542
|
-
getDocuments(driveId) {
|
|
543
|
-
return this.documentStorage.getChildren(driveId);
|
|
544
|
-
}
|
|
545
|
-
async addChild(parentId, documentId) {
|
|
546
|
-
// TODO: check if document exists? Should that be a concern here?
|
|
547
|
-
try {
|
|
548
|
-
await this.documentStorage.addChild(parentId, documentId);
|
|
549
|
-
// TODO: update listener manager?
|
|
550
|
-
}
|
|
551
|
-
catch (e) {
|
|
552
|
-
this.logger.error("Error adding child document: @error", e);
|
|
553
|
-
throw e;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
async removeChild(parentId, documentId) {
|
|
557
|
-
// TODO: check if document exists? Should that be a concern here?
|
|
558
|
-
// cleanup child sync units state from the parent listeners
|
|
559
|
-
try {
|
|
560
|
-
const childSynUnits = await this.synchronizationManager.getSynchronizationUnitsIds(parentId, [
|
|
561
|
-
documentId,
|
|
562
|
-
]);
|
|
563
|
-
await this.listenerManager.removeSyncUnits(parentId, childSynUnits);
|
|
564
|
-
}
|
|
565
|
-
catch (e) {
|
|
566
|
-
this.logger.warn("Error removing sync units of child: @error", e);
|
|
567
|
-
}
|
|
568
|
-
// remove child relationship from storage
|
|
569
|
-
try {
|
|
570
|
-
await this.documentStorage.removeChild(parentId, documentId);
|
|
571
|
-
}
|
|
572
|
-
catch (e) {
|
|
573
|
-
this.logger.error("Error adding child document: @error", e);
|
|
574
|
-
throw e;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
async createDocument(input, source, meta) {
|
|
578
|
-
if (this.enableDualActionCreate) {
|
|
579
|
-
return this.createDocumentDualAction(input, source, meta);
|
|
580
|
-
}
|
|
581
|
-
else {
|
|
582
|
-
return this.createDocumentLegacy(input, source, meta);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
async createDocumentLegacy(input, source, meta) {
|
|
586
|
-
const { documentType, document: inputDocument } = resolveCreateDocumentInput(input);
|
|
587
|
-
// if a document was provided then checks if it's valid
|
|
588
|
-
let state = undefined;
|
|
589
|
-
if (inputDocument) {
|
|
590
|
-
if ("documentType" in input &&
|
|
591
|
-
documentType !== inputDocument.header.documentType) {
|
|
592
|
-
throw new Error(`Provided document is not ${documentType}`);
|
|
593
|
-
}
|
|
594
|
-
const doc = this._buildDocument(inputDocument);
|
|
595
|
-
state = doc.state;
|
|
596
|
-
}
|
|
597
|
-
// if no document was provided then create a new one
|
|
598
|
-
const document = inputDocument ??
|
|
599
|
-
this.getDocumentModelModule(documentType).utils.createDocument(state);
|
|
600
|
-
// get the header
|
|
601
|
-
let header;
|
|
602
|
-
// handle the legacy case where an id is provided
|
|
603
|
-
if ("id" in input && input.id) {
|
|
604
|
-
if (inputDocument) {
|
|
605
|
-
header = document.header;
|
|
606
|
-
document.header.id = input.id;
|
|
607
|
-
this.logger.warn("Assigning an id to a document is deprecated. Use the header field instead.");
|
|
608
|
-
}
|
|
609
|
-
else {
|
|
610
|
-
this.logger.warn("Creating a document with an id is deprecated. Use the header field instead.");
|
|
611
|
-
header = createPresignedHeader(input.id, documentType);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
else if ("header" in input) {
|
|
615
|
-
// validate the header passed in
|
|
616
|
-
await validateHeader(input.header);
|
|
617
|
-
header = input.header;
|
|
618
|
-
}
|
|
619
|
-
else if (inputDocument?.header) {
|
|
620
|
-
if (!inputDocument.header.id) {
|
|
621
|
-
throw new Error("Document header id is required");
|
|
622
|
-
}
|
|
623
|
-
if (!inputDocument.header.documentType) {
|
|
624
|
-
throw new Error("Document header documentType is required");
|
|
625
|
-
}
|
|
626
|
-
if (!inputDocument.header.createdAtUtcIso) {
|
|
627
|
-
throw new Error("Document header createdAtUtcIso is required");
|
|
628
|
-
}
|
|
629
|
-
if (!inputDocument.header.sig.nonce) {
|
|
630
|
-
this.logger.warn("Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.");
|
|
631
|
-
// throw new Error("Document header sig nonce is required"); TODO: uncomment when ready to enforce signed documents
|
|
632
|
-
}
|
|
633
|
-
else {
|
|
634
|
-
await validateHeader(inputDocument.header);
|
|
635
|
-
}
|
|
636
|
-
header = inputDocument.header;
|
|
637
|
-
}
|
|
638
|
-
else {
|
|
639
|
-
// otherwise, generate a header
|
|
640
|
-
header = createPresignedHeader(undefined, documentType);
|
|
641
|
-
}
|
|
642
|
-
if (meta) {
|
|
643
|
-
header.meta = { ...header.meta, ...meta };
|
|
644
|
-
}
|
|
645
|
-
// stores document information
|
|
646
|
-
const documentStorage = {
|
|
647
|
-
header,
|
|
648
|
-
operations: { global: [], local: [] },
|
|
649
|
-
initialState: document.initialState,
|
|
650
|
-
clipboard: [],
|
|
651
|
-
state: state ?? document.state,
|
|
652
|
-
};
|
|
653
|
-
await this.documentStorage.create(documentStorage);
|
|
654
|
-
// TODO set initial state for document sync units
|
|
655
|
-
// if (source.type === "trigger") {
|
|
656
|
-
// for (const scope of Object.keys(document.state)) {
|
|
657
|
-
// this.synchronizationManager.updateSyncStatus(
|
|
658
|
-
// {
|
|
659
|
-
// documentId: document.id,
|
|
660
|
-
// scope,
|
|
661
|
-
// branch: "main" /* TODO handle branches */,
|
|
662
|
-
// },
|
|
663
|
-
// {
|
|
664
|
-
// pull: "INITIAL_SYNC",
|
|
665
|
-
// push: this.listenerManager.driveHasListeners(driveId)
|
|
666
|
-
// ? "SUCCESS"
|
|
667
|
-
// : undefined,
|
|
668
|
-
// },
|
|
669
|
-
// );
|
|
670
|
-
// }
|
|
671
|
-
// }
|
|
672
|
-
// if the document contains operations then
|
|
673
|
-
// stores the operations in the storage
|
|
674
|
-
const operations = Object.values(document.operations).flat();
|
|
675
|
-
if (operations.length) {
|
|
676
|
-
if (isDocumentDrive(document)) {
|
|
677
|
-
await this.legacyStorage.addDriveOperations(header.id, operations, document);
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
await this.legacyStorage.addDocumentOperations(header.id, operations, document);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
const addedDocument = await this.getDocument(documentStorage.header.id);
|
|
684
|
-
this.eventEmitter.emit("documentAdded", addedDocument);
|
|
685
|
-
return addedDocument;
|
|
686
|
-
}
|
|
687
|
-
async createDocumentDualAction(input, source, meta) {
|
|
688
|
-
const { documentType, document: inputDocument } = resolveCreateDocumentInput(input);
|
|
689
|
-
// if a document was provided then checks if it's valid
|
|
690
|
-
let state = undefined;
|
|
691
|
-
if (inputDocument) {
|
|
692
|
-
if ("documentType" in input &&
|
|
693
|
-
documentType !== inputDocument.header.documentType) {
|
|
694
|
-
throw new Error(`Provided document is not ${documentType}`);
|
|
695
|
-
}
|
|
696
|
-
const doc = this._buildDocument(inputDocument);
|
|
697
|
-
state = doc.state;
|
|
698
|
-
}
|
|
699
|
-
// if no document was provided then create a new one
|
|
700
|
-
const document = inputDocument ??
|
|
701
|
-
this.getDocumentModelModule(documentType).utils.createDocument(state);
|
|
702
|
-
// get the header
|
|
703
|
-
let header;
|
|
704
|
-
// handle the legacy case where an id is provided
|
|
705
|
-
let isSigned = false;
|
|
706
|
-
if ("id" in input && input.id) {
|
|
707
|
-
if (inputDocument) {
|
|
708
|
-
header = document.header;
|
|
709
|
-
document.header.id = input.id;
|
|
710
|
-
this.logger.warn("Assigning an id to a document is deprecated. Use the header field instead.");
|
|
711
|
-
}
|
|
712
|
-
else {
|
|
713
|
-
this.logger.warn("Creating a document with an id is deprecated. Use the header field instead.");
|
|
714
|
-
header = createPresignedHeader(input.id, documentType);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
else if ("header" in input) {
|
|
718
|
-
// validate the header passed in
|
|
719
|
-
await validateHeader(input.header);
|
|
720
|
-
isSigned = true;
|
|
721
|
-
header = input.header;
|
|
722
|
-
}
|
|
723
|
-
else if (inputDocument?.header) {
|
|
724
|
-
if (!inputDocument.header.id) {
|
|
725
|
-
throw new Error("Document header id is required");
|
|
726
|
-
}
|
|
727
|
-
if (!inputDocument.header.documentType) {
|
|
728
|
-
throw new Error("Document header documentType is required");
|
|
729
|
-
}
|
|
730
|
-
if (!inputDocument.header.createdAtUtcIso) {
|
|
731
|
-
throw new Error("Document header createdAtUtcIso is required");
|
|
732
|
-
}
|
|
733
|
-
if (!inputDocument.header.sig.nonce) {
|
|
734
|
-
this.logger.warn("Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.");
|
|
735
|
-
// throw new Error("Document header sig nonce is required"); TODO: uncomment when ready to enforce signed documents
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
await validateHeader(inputDocument.header);
|
|
739
|
-
isSigned = true;
|
|
740
|
-
}
|
|
741
|
-
header = inputDocument.header;
|
|
742
|
-
}
|
|
743
|
-
else {
|
|
744
|
-
// otherwise, generate a header
|
|
745
|
-
header = createPresignedHeader(undefined, documentType);
|
|
746
|
-
isSigned = false;
|
|
747
|
-
}
|
|
748
|
-
if (meta) {
|
|
749
|
-
header.meta = { ...header.meta, ...meta };
|
|
750
|
-
}
|
|
751
|
-
const currentVersion = 1;
|
|
752
|
-
// Get initial state from input or model's defaultState
|
|
753
|
-
const initialState = state ?? document.state;
|
|
754
|
-
// Check if the input document already has operations
|
|
755
|
-
const existingOperations = Object.values(document.operations).flat();
|
|
756
|
-
const shouldCreateOperations = existingOperations.length === 0;
|
|
757
|
-
let operations = [];
|
|
758
|
-
if (shouldCreateOperations) {
|
|
759
|
-
const timestampUtcMs = new Date().toISOString();
|
|
760
|
-
// Determine if this is a signed document
|
|
761
|
-
const signing = isSigned
|
|
762
|
-
? {
|
|
763
|
-
signature: header.id, // The document ID is the signature
|
|
764
|
-
publicKey: header.sig.publicKey,
|
|
765
|
-
nonce: header.sig.nonce,
|
|
766
|
-
createdAtUtcIso: header.createdAtUtcIso,
|
|
767
|
-
documentType: header.documentType,
|
|
768
|
-
}
|
|
769
|
-
: undefined;
|
|
770
|
-
// Create actions for CREATE_DOCUMENT and UPGRADE_DOCUMENT
|
|
771
|
-
const createDocumentInput = {
|
|
772
|
-
model: documentType,
|
|
773
|
-
version: 0,
|
|
774
|
-
documentId: header.id,
|
|
775
|
-
signing,
|
|
776
|
-
};
|
|
777
|
-
const createDocumentAction = {
|
|
778
|
-
id: generateId(),
|
|
779
|
-
type: "CREATE_DOCUMENT",
|
|
780
|
-
timestampUtcMs,
|
|
781
|
-
input: createDocumentInput,
|
|
782
|
-
scope: "document",
|
|
783
|
-
};
|
|
784
|
-
const upgradeDocumentInput = {
|
|
785
|
-
model: documentType,
|
|
786
|
-
fromVersion: 0,
|
|
787
|
-
toVersion: currentVersion,
|
|
788
|
-
documentId: header.id,
|
|
789
|
-
initialState,
|
|
790
|
-
};
|
|
791
|
-
const upgradeDocumentAction = {
|
|
792
|
-
id: generateId(),
|
|
793
|
-
type: "UPGRADE_DOCUMENT",
|
|
794
|
-
timestampUtcMs,
|
|
795
|
-
input: upgradeDocumentInput,
|
|
796
|
-
scope: "document",
|
|
797
|
-
};
|
|
798
|
-
// we need to create hashes for later verification
|
|
799
|
-
const baseState = defaultBaseState();
|
|
800
|
-
const createStateForHash = {
|
|
801
|
-
state: baseState,
|
|
802
|
-
};
|
|
803
|
-
const createHash = hashDocumentStateForScope(createStateForHash, "document");
|
|
804
|
-
const upgradeStateForHash = {
|
|
805
|
-
state: initialState,
|
|
806
|
-
};
|
|
807
|
-
const upgradeHash = hashDocumentStateForScope(upgradeStateForHash, "document");
|
|
808
|
-
// Create operations from actions with computed hashes
|
|
809
|
-
operations = [
|
|
810
|
-
{
|
|
811
|
-
id: deriveOperationId(header.id, "document", "main", createDocumentAction.id),
|
|
812
|
-
index: 0,
|
|
813
|
-
skip: 0,
|
|
814
|
-
hash: createHash,
|
|
815
|
-
timestampUtcMs,
|
|
816
|
-
action: createDocumentAction,
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
id: deriveOperationId(header.id, "document", "main", upgradeDocumentAction.id),
|
|
820
|
-
index: 1,
|
|
821
|
-
skip: 0,
|
|
822
|
-
hash: upgradeHash,
|
|
823
|
-
timestampUtcMs,
|
|
824
|
-
action: upgradeDocumentAction,
|
|
825
|
-
},
|
|
826
|
-
];
|
|
827
|
-
}
|
|
828
|
-
else {
|
|
829
|
-
// Use existing operations from the input document
|
|
830
|
-
operations = existingOperations;
|
|
831
|
-
}
|
|
832
|
-
// Group operations by scope before storing
|
|
833
|
-
const groupedOps = groupOperationsByScope(operations);
|
|
834
|
-
// Ensure backward compatibility by initializing missing scopes
|
|
835
|
-
if (!groupedOps.header) {
|
|
836
|
-
groupedOps.header = [];
|
|
837
|
-
}
|
|
838
|
-
if (!groupedOps.document) {
|
|
839
|
-
groupedOps.document = [];
|
|
840
|
-
}
|
|
841
|
-
if (!groupedOps.global) {
|
|
842
|
-
groupedOps.global = [];
|
|
843
|
-
}
|
|
844
|
-
if (!groupedOps.local) {
|
|
845
|
-
groupedOps.local = [];
|
|
846
|
-
}
|
|
847
|
-
// After initialization, it's safe to treat as DocumentOperations
|
|
848
|
-
const operationsByScope = groupedOps;
|
|
849
|
-
// stores document information with operations
|
|
850
|
-
const documentToStore = {
|
|
851
|
-
header,
|
|
852
|
-
operations: operationsByScope,
|
|
853
|
-
initialState,
|
|
854
|
-
clipboard: [],
|
|
855
|
-
state: initialState,
|
|
856
|
-
};
|
|
857
|
-
await this.documentStorage.create(documentToStore);
|
|
858
|
-
// Force rebuild to ensure operations are properly merged
|
|
859
|
-
const addedDocument = await this.getDocument(documentToStore.header.id, {
|
|
860
|
-
checkHashes: true,
|
|
861
|
-
});
|
|
862
|
-
this.eventEmitter.emit("documentAdded", addedDocument);
|
|
863
|
-
return addedDocument;
|
|
864
|
-
}
|
|
865
|
-
async deleteDocument(documentId) {
|
|
866
|
-
try {
|
|
867
|
-
const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(undefined, [documentId]);
|
|
868
|
-
// remove document sync units status when a document is deleted
|
|
869
|
-
for (const syncUnit of syncUnits) {
|
|
870
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, null);
|
|
871
|
-
}
|
|
872
|
-
const parents = await this.documentStorage.getParents(documentId);
|
|
873
|
-
for (const parent of parents) {
|
|
874
|
-
this.listenerManager
|
|
875
|
-
.removeSyncUnits(parent, syncUnits)
|
|
876
|
-
.catch(this.logger.warn);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
catch (error) {
|
|
880
|
-
this.logger.warn("Error deleting document: @error", error);
|
|
881
|
-
}
|
|
882
|
-
await Promise.allSettled([
|
|
883
|
-
this.cache.deleteDocument(documentId).catch(this.logger.warn),
|
|
884
|
-
this.documentStorage.delete(documentId).catch(this.logger.warn),
|
|
885
|
-
]);
|
|
886
|
-
this.eventEmitter.emit("documentDeleted", documentId);
|
|
887
|
-
}
|
|
888
|
-
async _processOperations(documentId, documentStorage, operations) {
|
|
889
|
-
const operationsApplied = [];
|
|
890
|
-
const signals = [];
|
|
891
|
-
const documentStorageWithState = await this._addDocumentResultingStage(documentStorage, documentId);
|
|
892
|
-
let document = this._buildDocument(documentStorageWithState);
|
|
893
|
-
let error; // TODO: replace with an array of errors/consistency issues
|
|
894
|
-
const operationsByScope = groupOperationsByScope(operations);
|
|
895
|
-
for (const scope of Object.keys(operationsByScope)) {
|
|
896
|
-
const storageDocumentOperations = documentStorage.operations[scope] || [];
|
|
897
|
-
// TODO two equal operations done by two clients will be considered the same, ie: { type: "INCREMENT" }
|
|
898
|
-
const branch = removeExistingOperations(operationsByScope[scope] || [], storageDocumentOperations);
|
|
899
|
-
// No operations to apply
|
|
900
|
-
if (branch.length < 1) {
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
const trunk = garbageCollect(sortOperations(storageDocumentOperations));
|
|
904
|
-
const [invertedTrunk, tail] = attachBranch(trunk, branch);
|
|
905
|
-
const newHistory = tail.length < 1
|
|
906
|
-
? invertedTrunk
|
|
907
|
-
: merge(trunk, invertedTrunk, reshuffleByTimestamp);
|
|
908
|
-
const newOperations = newHistory.filter((op) => trunk.length < 1 || precedes(trunk[trunk.length - 1], op));
|
|
909
|
-
for (const nextOperation of newOperations) {
|
|
910
|
-
let skipHashValidation = false;
|
|
911
|
-
// when dealing with a merge (tail.length > 0) we have to skip hash validation
|
|
912
|
-
// for the operations that were re-indexed (previous hash becomes invalid due the new position in the history)
|
|
913
|
-
if (tail.length > 0) {
|
|
914
|
-
const sourceOperation = operations.find((op) => op.hash === nextOperation.hash);
|
|
915
|
-
skipHashValidation =
|
|
916
|
-
!sourceOperation ||
|
|
917
|
-
sourceOperation.index !== nextOperation.index ||
|
|
918
|
-
sourceOperation.skip !== nextOperation.skip;
|
|
919
|
-
}
|
|
920
|
-
try {
|
|
921
|
-
// runs operation on next available tick, to avoid blocking the main thread
|
|
922
|
-
const taskQueueMethod = this.options.taskQueueMethod;
|
|
923
|
-
const task = () => this._performOperation(documentId, document, nextOperation, skipHashValidation);
|
|
924
|
-
const appliedResult = await (taskQueueMethod
|
|
925
|
-
? runAsapAsync(task, taskQueueMethod)
|
|
926
|
-
: task());
|
|
927
|
-
document = appliedResult.document;
|
|
928
|
-
signals.push(...appliedResult.signals);
|
|
929
|
-
operationsApplied.push(appliedResult.operation);
|
|
930
|
-
// TODO what to do if one of the applied operations has an error?
|
|
931
|
-
}
|
|
932
|
-
catch (e) {
|
|
933
|
-
error =
|
|
934
|
-
e instanceof OperationError
|
|
935
|
-
? e
|
|
936
|
-
: new OperationError("ERROR", nextOperation, e.message, e.cause);
|
|
937
|
-
// TODO: don't break on errors...
|
|
938
|
-
break;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
return {
|
|
943
|
-
document,
|
|
944
|
-
operationsApplied,
|
|
945
|
-
signals,
|
|
946
|
-
error,
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
async _addDocumentResultingStage(document, documentId, options) {
|
|
950
|
-
// apply skip header operations to all scopes
|
|
951
|
-
const operations = options?.revisions !== undefined
|
|
952
|
-
? filterOperationsByRevision(document.operations, options.revisions)
|
|
953
|
-
: document.operations;
|
|
954
|
-
const documentOperations = garbageCollectDocumentOperations(operations);
|
|
955
|
-
for (const scope of Object.keys(documentOperations)) {
|
|
956
|
-
const scopeOps = documentOperations[scope];
|
|
957
|
-
if (!scopeOps) {
|
|
958
|
-
continue;
|
|
959
|
-
}
|
|
960
|
-
const lastRemainingOperation = scopeOps.at(-1);
|
|
961
|
-
// if the latest operation doesn't have a resulting state then tries
|
|
962
|
-
// to retrieve it from the db to avoid rerunning all the operations
|
|
963
|
-
if (lastRemainingOperation && !lastRemainingOperation.resultingState) {
|
|
964
|
-
lastRemainingOperation.resultingState = await (isDocumentDrive(document)
|
|
965
|
-
? this.legacyStorage.getOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main")
|
|
966
|
-
: this.legacyStorage.getDriveOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main"));
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
return {
|
|
970
|
-
...document,
|
|
971
|
-
operations: documentOperations,
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
_buildDocument(documentStorage, options) {
|
|
975
|
-
if (documentStorage.state &&
|
|
976
|
-
(!options || options.checkHashes === false) &&
|
|
977
|
-
isAtRevision(documentStorage, options?.revisions)) {
|
|
978
|
-
return documentStorage;
|
|
979
|
-
}
|
|
980
|
-
const documentModelModule = this.getDocumentModelModule(documentStorage.header.documentType);
|
|
981
|
-
const revisionOperations = options?.revisions !== undefined
|
|
982
|
-
? filterOperationsByRevision(documentStorage.operations, options.revisions)
|
|
983
|
-
: documentStorage.operations;
|
|
984
|
-
const operations = garbageCollectDocumentOperations(revisionOperations);
|
|
985
|
-
// Get all scopes from operations
|
|
986
|
-
const allScopes = Object.keys(operations);
|
|
987
|
-
// Initialize with all scopes found in operations, plus global and local for backward compatibility
|
|
988
|
-
const scopesToInitialize = new Set([...allScopes, "global", "local"]);
|
|
989
|
-
const headerOperations = {};
|
|
990
|
-
const operationsToReplay = {};
|
|
991
|
-
for (const scope of scopesToInitialize) {
|
|
992
|
-
headerOperations[scope] = [];
|
|
993
|
-
operationsToReplay[scope] = [];
|
|
994
|
-
}
|
|
995
|
-
// Filter out CREATE_DOCUMENT and UPGRADE_DOCUMENT operations
|
|
996
|
-
// (these don't currently have reducers and should not be replayed)
|
|
997
|
-
for (const [scope, scopeOps] of Object.entries(operations)) {
|
|
998
|
-
if (!scopeOps) {
|
|
999
|
-
continue;
|
|
1000
|
-
}
|
|
1001
|
-
for (const op of scopeOps) {
|
|
1002
|
-
if (op.action.type === "CREATE_DOCUMENT" ||
|
|
1003
|
-
op.action.type === "UPGRADE_DOCUMENT") {
|
|
1004
|
-
const headerOps = headerOperations[scope];
|
|
1005
|
-
if (headerOps) {
|
|
1006
|
-
headerOps.push(op);
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
else {
|
|
1010
|
-
const replayOps = operationsToReplay[scope];
|
|
1011
|
-
if (replayOps) {
|
|
1012
|
-
replayOps.push(op);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
// If revisions filter is specified, compute header revision from filtered operations
|
|
1018
|
-
// This ensures the returned document's header.revision reflects the requested revision,
|
|
1019
|
-
// not the current storage state
|
|
1020
|
-
let headerForReplay = documentStorage.header;
|
|
1021
|
-
if (options?.revisions) {
|
|
1022
|
-
const newRevision = {
|
|
1023
|
-
...documentStorage.header.revision,
|
|
1024
|
-
};
|
|
1025
|
-
// For each scope in the revision filter, compute actual revision from filtered ops
|
|
1026
|
-
for (const scope of Object.keys(options.revisions)) {
|
|
1027
|
-
const scopeOps = operations[scope] ?? [];
|
|
1028
|
-
if (scopeOps.length === 0) {
|
|
1029
|
-
// No ops means revision should not exist for this scope
|
|
1030
|
-
delete newRevision[scope];
|
|
1031
|
-
}
|
|
1032
|
-
else {
|
|
1033
|
-
const lastOp = scopeOps.at(-1);
|
|
1034
|
-
newRevision[scope] = lastOp ? lastOp.index + 1 : 0;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
headerForReplay = {
|
|
1038
|
-
...documentStorage.header,
|
|
1039
|
-
revision: newRevision,
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
const replayed = replayDocument(documentStorage.initialState, operationsToReplay, documentModelModule.reducer, headerForReplay, undefined, {}, {
|
|
1043
|
-
...options,
|
|
1044
|
-
checkHashes: options?.checkHashes ?? true,
|
|
1045
|
-
reuseOperationResultingState: options?.checkHashes ?? true,
|
|
1046
|
-
});
|
|
1047
|
-
// merge header operations back into the result
|
|
1048
|
-
// Include ALL scopes from input operations, header operations, and replayed operations
|
|
1049
|
-
const allScopesForMerge = new Set([
|
|
1050
|
-
...Object.keys(operations), // From input storage
|
|
1051
|
-
...Object.keys(headerOperations),
|
|
1052
|
-
...Object.keys(replayed.operations),
|
|
1053
|
-
]);
|
|
1054
|
-
const finalOperations = {};
|
|
1055
|
-
for (const scope of allScopesForMerge) {
|
|
1056
|
-
finalOperations[scope] = [
|
|
1057
|
-
...(headerOperations[scope] || []),
|
|
1058
|
-
...(replayed.operations[scope] || []),
|
|
1059
|
-
];
|
|
1060
|
-
}
|
|
1061
|
-
return {
|
|
1062
|
-
...replayed,
|
|
1063
|
-
operations: finalOperations,
|
|
1064
|
-
clipboard: documentStorage.clipboard ?? [],
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
async _performOperation(documentId, document, operation, skipHashValidation = false) {
|
|
1068
|
-
const documentModelModule = this.getDocumentModelModule(document.header.documentType);
|
|
1069
|
-
const signalResults = [];
|
|
1070
|
-
let newDocument = document;
|
|
1071
|
-
const scope = operation.action.scope;
|
|
1072
|
-
const currentScopeOperations = document.operations[scope] || [];
|
|
1073
|
-
const documentOperations = garbageCollectDocumentOperations({
|
|
1074
|
-
...document.operations,
|
|
1075
|
-
[scope]: skipHeaderOperations(currentScopeOperations, operation),
|
|
1076
|
-
});
|
|
1077
|
-
const remainingScopeOps = documentOperations[scope];
|
|
1078
|
-
const lastRemainingOperation = remainingScopeOps?.at(-1);
|
|
1079
|
-
// if the latest operation doesn't have a resulting state then tries
|
|
1080
|
-
// to retrieve it from the db to avoid rerunning all the operations
|
|
1081
|
-
if (lastRemainingOperation && !lastRemainingOperation.resultingState) {
|
|
1082
|
-
lastRemainingOperation.resultingState = await (isDocumentDrive(document)
|
|
1083
|
-
? this.legacyStorage.getOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main")
|
|
1084
|
-
: this.legacyStorage.getDriveOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main"));
|
|
1085
|
-
}
|
|
1086
|
-
const operationsBeforeReducer = newDocument.operations[scope] || [];
|
|
1087
|
-
const operationSignals = [];
|
|
1088
|
-
newDocument = documentModelModule.reducer(newDocument, operation.action, (signal) => {
|
|
1089
|
-
let handler = undefined;
|
|
1090
|
-
switch (signal.type) {
|
|
1091
|
-
case "CREATE_CHILD_DOCUMENT":
|
|
1092
|
-
handler = () => this.addChild(documentId, signal.input.id);
|
|
1093
|
-
break;
|
|
1094
|
-
case "DELETE_CHILD_DOCUMENT":
|
|
1095
|
-
handler = () => this.removeChild(documentId, signal.input.id);
|
|
1096
|
-
break;
|
|
1097
|
-
case "COPY_CHILD_DOCUMENT":
|
|
1098
|
-
handler = () => this.addChild(documentId, signal.input.newId);
|
|
1099
|
-
break;
|
|
1100
|
-
}
|
|
1101
|
-
if (handler) {
|
|
1102
|
-
operationSignals.push(() => handler().then((result) => ({ signal, result })));
|
|
1103
|
-
}
|
|
1104
|
-
}, {
|
|
1105
|
-
skip: operation.skip,
|
|
1106
|
-
reuseOperationResultingState: true,
|
|
1107
|
-
replayOptions: { operation },
|
|
1108
|
-
});
|
|
1109
|
-
// when we have NOOP operations with skip > 0 we need to populate the
|
|
1110
|
-
// clipboard with the operations that were skipped to allow redo
|
|
1111
|
-
if (operation.action.type === "NOOP" &&
|
|
1112
|
-
operation.skip > 0 &&
|
|
1113
|
-
newDocument.clipboard.length === 0) {
|
|
1114
|
-
const scopeOperationsAfter = newDocument.operations[scope] || [];
|
|
1115
|
-
// Get operations AFTER garbageCollect (with NOOP)
|
|
1116
|
-
const afterOperations = garbageCollect(sortOperations(scopeOperationsAfter));
|
|
1117
|
-
// Get operations BEFORE the reducer ran (before NOOP was applied)
|
|
1118
|
-
const beforeOperations = garbageCollect(sortOperations(operationsBeforeReducer));
|
|
1119
|
-
// Calculate what was removed by comparing before vs after
|
|
1120
|
-
// The diff shows operations that were in "before" but not in "after"
|
|
1121
|
-
const diff = diffOperations(beforeOperations, afterOperations);
|
|
1122
|
-
// Populate clipboard with skipped operations (excluding NOOPs)
|
|
1123
|
-
newDocument = {
|
|
1124
|
-
...newDocument,
|
|
1125
|
-
clipboard: sortOperations(diff.filter((op) => op.action.type !== "NOOP")).reverse(),
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
const newDocScopeOperations = newDocument.operations[operation.action.scope];
|
|
1129
|
-
if (!newDocScopeOperations) {
|
|
1130
|
-
throw new OperationError("ERROR", operation, `No operations found for scope: ${operation.action.scope}`);
|
|
1131
|
-
}
|
|
1132
|
-
const appliedOperations = newDocScopeOperations.filter((op) => op.index == operation.index && op.skip == operation.skip);
|
|
1133
|
-
const appliedOperation = appliedOperations.at(0);
|
|
1134
|
-
if (!appliedOperation) {
|
|
1135
|
-
throw new OperationError("ERROR", operation, `Operation with index ${operation.index}:${operation.skip} was not applied.`);
|
|
1136
|
-
}
|
|
1137
|
-
if (!appliedOperation.error &&
|
|
1138
|
-
appliedOperation.hash !== operation.hash &&
|
|
1139
|
-
!skipHashValidation) {
|
|
1140
|
-
this.logger.warn("@appliedOperation", appliedOperation);
|
|
1141
|
-
throw new ConflictOperationError(operation, appliedOperation);
|
|
1142
|
-
}
|
|
1143
|
-
for (const signalHandler of operationSignals) {
|
|
1144
|
-
const result = await signalHandler();
|
|
1145
|
-
signalResults.push(result);
|
|
1146
|
-
}
|
|
1147
|
-
return {
|
|
1148
|
-
document: newDocument,
|
|
1149
|
-
signals: signalResults,
|
|
1150
|
-
operation: appliedOperation,
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
addOperation(driveIdOrDocumentId, documentIdOrOperation, operationOrOptions, maybeOptions) {
|
|
1154
|
-
let documentId;
|
|
1155
|
-
let operation;
|
|
1156
|
-
let options;
|
|
1157
|
-
if (typeof documentIdOrOperation === "string") {
|
|
1158
|
-
// Deprecated overload: (driveId, documentId, operation, options)
|
|
1159
|
-
documentId = documentIdOrOperation;
|
|
1160
|
-
operation = operationOrOptions;
|
|
1161
|
-
options = maybeOptions;
|
|
1162
|
-
}
|
|
1163
|
-
else {
|
|
1164
|
-
// Standard overload: (documentId, operation, options)
|
|
1165
|
-
documentId = driveIdOrDocumentId;
|
|
1166
|
-
operation = documentIdOrOperation;
|
|
1167
|
-
options = operationOrOptions;
|
|
1168
|
-
}
|
|
1169
|
-
return this.addOperations(documentId, [operation], options);
|
|
1170
|
-
}
|
|
1171
|
-
async _addOperations(documentId, callback) {
|
|
1172
|
-
if (!this.legacyStorage.addDocumentOperationsWithTransaction) {
|
|
1173
|
-
const documentStorage = await this.documentStorage.get(documentId);
|
|
1174
|
-
const result = await callback(documentStorage);
|
|
1175
|
-
// saves the applied operations to storage
|
|
1176
|
-
if (result.operations.length > 0) {
|
|
1177
|
-
await this.legacyStorage.addDocumentOperations(documentId, result.operations, result.document);
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
else {
|
|
1181
|
-
await this.legacyStorage.addDocumentOperationsWithTransaction(documentId, callback);
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
async queueDocument(input, options) {
|
|
1185
|
-
const { id, documentType, document } = resolveCreateDocumentInput(input);
|
|
1186
|
-
if (!id) {
|
|
1187
|
-
throw new Error("Document id is required", { cause: input });
|
|
1188
|
-
}
|
|
1189
|
-
if (!documentType) {
|
|
1190
|
-
throw new Error("Document type is required", { cause: input });
|
|
1191
|
-
}
|
|
1192
|
-
const exists = await this.documentStorage.exists(id);
|
|
1193
|
-
if (exists) {
|
|
1194
|
-
throw new DocumentAlreadyExistsError(id);
|
|
1195
|
-
}
|
|
1196
|
-
// add listeners first
|
|
1197
|
-
let jobId;
|
|
1198
|
-
const promise = new Promise((resolve, reject) => {
|
|
1199
|
-
const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
|
|
1200
|
-
if (job.jobId === jobId) {
|
|
1201
|
-
unsubscribe();
|
|
1202
|
-
unsubscribeError();
|
|
1203
|
-
resolve(result);
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
|
|
1207
|
-
if (job.jobId === jobId) {
|
|
1208
|
-
unsubscribe();
|
|
1209
|
-
unsubscribeError();
|
|
1210
|
-
reject(error);
|
|
1211
|
-
}
|
|
1212
|
-
});
|
|
1213
|
-
});
|
|
1214
|
-
// now queue the job
|
|
1215
|
-
try {
|
|
1216
|
-
jobId = await this.queueManager.addJob({
|
|
1217
|
-
documentId: id,
|
|
1218
|
-
documentType,
|
|
1219
|
-
initialState: document?.state,
|
|
1220
|
-
header: document?.header,
|
|
1221
|
-
options,
|
|
1222
|
-
});
|
|
1223
|
-
}
|
|
1224
|
-
catch (error) {
|
|
1225
|
-
this.logger.error("Error adding job: @error", error);
|
|
1226
|
-
throw error;
|
|
1227
|
-
}
|
|
1228
|
-
return promise;
|
|
1229
|
-
}
|
|
1230
|
-
queueOperation(driveIdOrDocumentId, documentIdOrOperation, operationOrOptions, maybeOptions) {
|
|
1231
|
-
let documentId;
|
|
1232
|
-
let operation;
|
|
1233
|
-
let options;
|
|
1234
|
-
if (typeof documentIdOrOperation === "string") {
|
|
1235
|
-
// Deprecated overload: (driveId, documentId, operation, options)
|
|
1236
|
-
documentId = documentIdOrOperation;
|
|
1237
|
-
operation = operationOrOptions;
|
|
1238
|
-
options = maybeOptions;
|
|
1239
|
-
}
|
|
1240
|
-
else {
|
|
1241
|
-
// Standard overload: (documentId, operation, options)
|
|
1242
|
-
documentId = driveIdOrDocumentId;
|
|
1243
|
-
operation = documentIdOrOperation;
|
|
1244
|
-
options = operationOrOptions;
|
|
1245
|
-
}
|
|
1246
|
-
return this._queueOperations(documentId, [operation], options);
|
|
1247
|
-
}
|
|
1248
|
-
async resultIfExistingOperations(id, operations) {
|
|
1249
|
-
try {
|
|
1250
|
-
const document = await this.getDocument(id);
|
|
1251
|
-
const newOperation = operations.find((op) => {
|
|
1252
|
-
if (!op.id) {
|
|
1253
|
-
return true;
|
|
1254
|
-
}
|
|
1255
|
-
const scopeOps = document.operations[op.action.scope];
|
|
1256
|
-
if (!scopeOps) {
|
|
1257
|
-
return true;
|
|
1258
|
-
}
|
|
1259
|
-
return !scopeOps.find((existingOp) => existingOp.id === op.id &&
|
|
1260
|
-
existingOp.index === op.index &&
|
|
1261
|
-
existingOp.action.type === op.action.type &&
|
|
1262
|
-
existingOp.hash === op.hash);
|
|
1263
|
-
});
|
|
1264
|
-
if (!newOperation) {
|
|
1265
|
-
return {
|
|
1266
|
-
status: "SUCCESS",
|
|
1267
|
-
document,
|
|
1268
|
-
operations,
|
|
1269
|
-
signals: [],
|
|
1270
|
-
};
|
|
1271
|
-
}
|
|
1272
|
-
else {
|
|
1273
|
-
return undefined;
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
catch (error) {
|
|
1277
|
-
if (!error.message.includes(`Document with id ${id} not found`)) {
|
|
1278
|
-
console.error(error);
|
|
1279
|
-
}
|
|
1280
|
-
return undefined;
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
queueOperations(driveIdOrDocumentId, documentIdOrOperations, operationsOrOptions, maybeOptions) {
|
|
1284
|
-
let documentId;
|
|
1285
|
-
let operations;
|
|
1286
|
-
let options;
|
|
1287
|
-
if (typeof documentIdOrOperations === "string") {
|
|
1288
|
-
// Deprecated overload: (driveId, documentId, operations, options)
|
|
1289
|
-
documentId = documentIdOrOperations;
|
|
1290
|
-
operations = operationsOrOptions;
|
|
1291
|
-
options = maybeOptions;
|
|
1292
|
-
}
|
|
1293
|
-
else {
|
|
1294
|
-
// Standard overload: (documentId, operations, options)
|
|
1295
|
-
documentId = driveIdOrDocumentId;
|
|
1296
|
-
operations = documentIdOrOperations;
|
|
1297
|
-
options = operationsOrOptions;
|
|
1298
|
-
}
|
|
1299
|
-
return this._queueOperations(documentId, operations, options);
|
|
1300
|
-
}
|
|
1301
|
-
async _queueOperations(documentId, operations, options) {
|
|
1302
|
-
// if operations are already stored then returns cached document
|
|
1303
|
-
const result = await this.resultIfExistingOperations(documentId, operations);
|
|
1304
|
-
if (result) {
|
|
1305
|
-
return result;
|
|
1306
|
-
}
|
|
1307
|
-
// add listeners first
|
|
1308
|
-
let jobId;
|
|
1309
|
-
const promise = new Promise((resolve, reject) => {
|
|
1310
|
-
const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
|
|
1311
|
-
if (job.jobId === jobId) {
|
|
1312
|
-
unsubscribe();
|
|
1313
|
-
unsubscribeError();
|
|
1314
|
-
resolve(result);
|
|
1315
|
-
}
|
|
1316
|
-
});
|
|
1317
|
-
const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
|
|
1318
|
-
if (job.jobId === jobId) {
|
|
1319
|
-
unsubscribe();
|
|
1320
|
-
unsubscribeError();
|
|
1321
|
-
reject(error);
|
|
1322
|
-
}
|
|
1323
|
-
});
|
|
1324
|
-
});
|
|
1325
|
-
// now queue the job
|
|
1326
|
-
try {
|
|
1327
|
-
jobId = await this.queueManager.addJob({
|
|
1328
|
-
documentId,
|
|
1329
|
-
operations,
|
|
1330
|
-
options,
|
|
1331
|
-
});
|
|
1332
|
-
}
|
|
1333
|
-
catch (error) {
|
|
1334
|
-
this.logger.error("Error adding job: @error", error);
|
|
1335
|
-
throw error;
|
|
1336
|
-
}
|
|
1337
|
-
return promise;
|
|
1338
|
-
}
|
|
1339
|
-
queueAction(driveIdOrDocumentId, documentIdOrAction, actionOrOptions, maybeOptions) {
|
|
1340
|
-
let documentId;
|
|
1341
|
-
let action;
|
|
1342
|
-
let options;
|
|
1343
|
-
if (typeof documentIdOrAction === "string") {
|
|
1344
|
-
// Deprecated overload: (driveId, documentId, action, options)
|
|
1345
|
-
documentId = documentIdOrAction;
|
|
1346
|
-
action = actionOrOptions;
|
|
1347
|
-
options = maybeOptions;
|
|
1348
|
-
}
|
|
1349
|
-
else {
|
|
1350
|
-
// Standard overload: (documentId, action, options)
|
|
1351
|
-
documentId = driveIdOrDocumentId;
|
|
1352
|
-
action = documentIdOrAction;
|
|
1353
|
-
options = actionOrOptions;
|
|
1354
|
-
}
|
|
1355
|
-
return this._queueActions(documentId, [action], options);
|
|
1356
|
-
}
|
|
1357
|
-
queueActions(driveIdOrDocumentId, documentIdOrActions, actionsOrOptions, maybeOptions) {
|
|
1358
|
-
let documentId;
|
|
1359
|
-
let actions;
|
|
1360
|
-
let options;
|
|
1361
|
-
if (typeof documentIdOrActions === "string") {
|
|
1362
|
-
// Deprecated overload: (driveId, documentId, actions, options)
|
|
1363
|
-
documentId = documentIdOrActions;
|
|
1364
|
-
actions = actionsOrOptions;
|
|
1365
|
-
options = maybeOptions;
|
|
1366
|
-
}
|
|
1367
|
-
else {
|
|
1368
|
-
// Standard overload: (documentId, actions, options)
|
|
1369
|
-
documentId = driveIdOrDocumentId;
|
|
1370
|
-
actions = documentIdOrActions;
|
|
1371
|
-
options = actionsOrOptions;
|
|
1372
|
-
}
|
|
1373
|
-
return this._queueActions(documentId, actions, options);
|
|
1374
|
-
}
|
|
1375
|
-
async _queueActions(documentId, actions, options) {
|
|
1376
|
-
try {
|
|
1377
|
-
const jobId = await this.queueManager.addJob({
|
|
1378
|
-
documentId,
|
|
1379
|
-
actions,
|
|
1380
|
-
options,
|
|
1381
|
-
});
|
|
1382
|
-
return await new Promise((resolve, reject) => {
|
|
1383
|
-
const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
|
|
1384
|
-
if (job.jobId === jobId) {
|
|
1385
|
-
unsubscribe();
|
|
1386
|
-
unsubscribeError();
|
|
1387
|
-
resolve(result);
|
|
1388
|
-
}
|
|
1389
|
-
});
|
|
1390
|
-
const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
|
|
1391
|
-
if (job.jobId === jobId) {
|
|
1392
|
-
unsubscribe();
|
|
1393
|
-
unsubscribeError();
|
|
1394
|
-
reject(error);
|
|
1395
|
-
}
|
|
1396
|
-
});
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
catch (error) {
|
|
1400
|
-
this.logger.error("Error adding job: @error", error);
|
|
1401
|
-
throw error;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
/**
|
|
1405
|
-
* @deprecated Use the {@link queueAction} method instead.
|
|
1406
|
-
*/
|
|
1407
|
-
async queueDriveAction(driveId, action, options) {
|
|
1408
|
-
return this.queueDriveActions(driveId, [action], options);
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* @deprecated Use the {@link queueActions} method instead.
|
|
1412
|
-
*/
|
|
1413
|
-
async queueDriveActions(driveId, actions, options) {
|
|
1414
|
-
try {
|
|
1415
|
-
const jobId = await this.queueManager.addJob({
|
|
1416
|
-
documentId: driveId,
|
|
1417
|
-
actions,
|
|
1418
|
-
options,
|
|
1419
|
-
});
|
|
1420
|
-
return await new Promise((resolve, reject) => {
|
|
1421
|
-
const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
|
|
1422
|
-
if (job.jobId === jobId) {
|
|
1423
|
-
unsubscribe();
|
|
1424
|
-
unsubscribeError();
|
|
1425
|
-
resolve(result);
|
|
1426
|
-
}
|
|
1427
|
-
});
|
|
1428
|
-
const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
|
|
1429
|
-
if (job.jobId === jobId) {
|
|
1430
|
-
unsubscribe();
|
|
1431
|
-
unsubscribeError();
|
|
1432
|
-
reject(error);
|
|
1433
|
-
}
|
|
1434
|
-
});
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
1437
|
-
catch (error) {
|
|
1438
|
-
this.logger.error("Error adding drive job: @error", error);
|
|
1439
|
-
throw error;
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
addOperations(driveIdOrDocumentId, documentIdOrOperations, operationsOrOptions, maybeOptions) {
|
|
1443
|
-
let documentId;
|
|
1444
|
-
let operations;
|
|
1445
|
-
let options;
|
|
1446
|
-
if (typeof documentIdOrOperations === "string") {
|
|
1447
|
-
// Deprecated overload: (driveId, documentId, operations, options)
|
|
1448
|
-
documentId = documentIdOrOperations;
|
|
1449
|
-
operations = operationsOrOptions;
|
|
1450
|
-
options = maybeOptions;
|
|
1451
|
-
}
|
|
1452
|
-
else {
|
|
1453
|
-
// Standard overload: (documentId, operations, options)
|
|
1454
|
-
documentId = driveIdOrDocumentId;
|
|
1455
|
-
operations = documentIdOrOperations;
|
|
1456
|
-
options = operationsOrOptions;
|
|
1457
|
-
}
|
|
1458
|
-
return this._queueOperations(documentId, operations, options);
|
|
1459
|
-
}
|
|
1460
|
-
async processOperations(documentId, operations, options) {
|
|
1461
|
-
// if operations are already stored then returns the result
|
|
1462
|
-
const result = await this.resultIfExistingOperations(documentId, operations);
|
|
1463
|
-
if (result) {
|
|
1464
|
-
return result;
|
|
1465
|
-
}
|
|
1466
|
-
let document;
|
|
1467
|
-
const operationsApplied = [];
|
|
1468
|
-
const signals = [];
|
|
1469
|
-
let error;
|
|
1470
|
-
try {
|
|
1471
|
-
await this._addOperations(documentId, async (documentStorage) => {
|
|
1472
|
-
const result = await this._processOperations(documentId, documentStorage, operations);
|
|
1473
|
-
if (!result.document) {
|
|
1474
|
-
this.logger.error("Invalid document");
|
|
1475
|
-
throw result.error ?? new Error("Invalid document");
|
|
1476
|
-
}
|
|
1477
|
-
document = result.document;
|
|
1478
|
-
error = result.error;
|
|
1479
|
-
signals.push(...result.signals);
|
|
1480
|
-
operationsApplied.push(...result.operationsApplied);
|
|
1481
|
-
return {
|
|
1482
|
-
operations: result.operationsApplied,
|
|
1483
|
-
document: result.document,
|
|
1484
|
-
};
|
|
1485
|
-
});
|
|
1486
|
-
const syncUnits = new Array();
|
|
1487
|
-
if (document) {
|
|
1488
|
-
this.cache
|
|
1489
|
-
.setDocument(documentId, document)
|
|
1490
|
-
.catch((e) => this.logger.error("@error", e));
|
|
1491
|
-
// creates array of unique sync units from the applied operations
|
|
1492
|
-
for (const operation of operationsApplied) {
|
|
1493
|
-
const syncUnit = {
|
|
1494
|
-
documentId,
|
|
1495
|
-
documentType: document.header.documentType,
|
|
1496
|
-
scope: operation.action.scope,
|
|
1497
|
-
branch: "main", // TODO: handle branches
|
|
1498
|
-
revision: operation.index + 1,
|
|
1499
|
-
lastUpdated: operation.timestampUtcMs,
|
|
1500
|
-
};
|
|
1501
|
-
// checks if this sync unit was already added
|
|
1502
|
-
const exists = syncUnits.some((unit) => unit.documentId === syncUnit.documentId &&
|
|
1503
|
-
unit.scope === syncUnit.scope &&
|
|
1504
|
-
unit.branch === syncUnit.branch);
|
|
1505
|
-
if (!exists) {
|
|
1506
|
-
syncUnits.push(syncUnit);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
// checks if any of the provided operations where reshufled
|
|
1511
|
-
const newOp = operationsApplied.find((appliedOp) => !operations.find((o) => o.id === appliedOp.id &&
|
|
1512
|
-
o.index === appliedOp.index &&
|
|
1513
|
-
o.skip === appliedOp.skip &&
|
|
1514
|
-
o.hash === appliedOp.hash));
|
|
1515
|
-
// if there are no new operations then reuses the provided source
|
|
1516
|
-
// otherwise sets it to local so listeners know that there were
|
|
1517
|
-
// new changes originating from this document drive server
|
|
1518
|
-
const source = newOp
|
|
1519
|
-
? { type: "local" }
|
|
1520
|
-
: (options?.source ?? { type: "local" });
|
|
1521
|
-
// update listener cache
|
|
1522
|
-
const operationSource = this.getOperationSource(source);
|
|
1523
|
-
// TODO Decouple the operation processing from syncing it to the listeners?
|
|
1524
|
-
// Listener manager should be the one keeping the sync status since it depends on the listeners
|
|
1525
|
-
if (syncUnits.length) {
|
|
1526
|
-
this.listenerManager
|
|
1527
|
-
.updateSynchronizationRevisions(syncUnits, source, () => {
|
|
1528
|
-
this.synchronizationManager.updateSyncStatus(documentId, {
|
|
1529
|
-
[operationSource]: "SYNCING",
|
|
1530
|
-
});
|
|
1531
|
-
for (const syncUnit of syncUnits) {
|
|
1532
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, {
|
|
1533
|
-
[operationSource]: "SYNCING",
|
|
1534
|
-
});
|
|
1535
|
-
}
|
|
1536
|
-
}, this.handleListenerError.bind(this), options?.forceSync ?? source.type === "local")
|
|
1537
|
-
.then((updates) => {
|
|
1538
|
-
if (updates.length) {
|
|
1539
|
-
this.synchronizationManager.updateSyncStatus(documentId, {
|
|
1540
|
-
[operationSource]: "SUCCESS",
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
for (const syncUnit of syncUnits) {
|
|
1544
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, {
|
|
1545
|
-
[operationSource]: "SUCCESS",
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
})
|
|
1549
|
-
.catch((error) => {
|
|
1550
|
-
this.logger.error("Non handled error updating sync revision: @error", error);
|
|
1551
|
-
this.synchronizationManager.updateSyncStatus(documentId, {
|
|
1552
|
-
[operationSource]: "ERROR",
|
|
1553
|
-
}, error);
|
|
1554
|
-
for (const syncUnit of syncUnits) {
|
|
1555
|
-
this.synchronizationManager.updateSyncStatus(syncUnit, {
|
|
1556
|
-
[operationSource]: "ERROR",
|
|
1557
|
-
}, error);
|
|
1558
|
-
}
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1561
|
-
// after applying all the valid operations,throws
|
|
1562
|
-
// an error if there was an invalid operation
|
|
1563
|
-
if (error) {
|
|
1564
|
-
throw error;
|
|
1565
|
-
}
|
|
1566
|
-
this.eventEmitter.emit("documentOperationsAdded", documentId, operations);
|
|
1567
|
-
this.eventEmitter.emit("operationsAdded", documentId, operations);
|
|
1568
|
-
return {
|
|
1569
|
-
status: "SUCCESS",
|
|
1570
|
-
document,
|
|
1571
|
-
operations: operationsApplied,
|
|
1572
|
-
signals,
|
|
1573
|
-
};
|
|
1574
|
-
}
|
|
1575
|
-
catch (error) {
|
|
1576
|
-
const operationError = error instanceof OperationError
|
|
1577
|
-
? error
|
|
1578
|
-
: new OperationError("ERROR", undefined, error.message, error.cause);
|
|
1579
|
-
return {
|
|
1580
|
-
status: operationError.status,
|
|
1581
|
-
error: operationError,
|
|
1582
|
-
document,
|
|
1583
|
-
operations: operationsApplied,
|
|
1584
|
-
signals,
|
|
1585
|
-
};
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
/**
|
|
1589
|
-
* @deprecated Use the {@link addOperation} method instead.
|
|
1590
|
-
*/
|
|
1591
|
-
addDriveOperation(driveId, operation, options) {
|
|
1592
|
-
return this.addDriveOperations(driveId, [operation], options);
|
|
1593
|
-
}
|
|
1594
|
-
async _addDriveOperations(driveId, callback) {
|
|
1595
|
-
if (!this.legacyStorage.addDriveOperationsWithTransaction) {
|
|
1596
|
-
const documentStorage = await this.documentStorage.get(driveId);
|
|
1597
|
-
const result = await callback(documentStorage);
|
|
1598
|
-
// saves the applied operations to storage
|
|
1599
|
-
if (result.operations.length > 0) {
|
|
1600
|
-
await this.legacyStorage.addDriveOperations(driveId, result.operations, result.document);
|
|
1601
|
-
}
|
|
1602
|
-
return result;
|
|
1603
|
-
}
|
|
1604
|
-
else {
|
|
1605
|
-
return this.legacyStorage.addDriveOperationsWithTransaction(driveId, callback);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
/**
|
|
1609
|
-
* @deprecated Use the {@link queueOperation} method instead.
|
|
1610
|
-
*/
|
|
1611
|
-
queueDriveOperation(driveId, operation, options) {
|
|
1612
|
-
return this.queueDriveOperations(driveId, [operation], options);
|
|
1613
|
-
}
|
|
1614
|
-
async resultIfExistingDriveOperations(driveId, operations) {
|
|
1615
|
-
try {
|
|
1616
|
-
const drive = await this.getDrive(driveId);
|
|
1617
|
-
const newOperation = operations.find((op) => {
|
|
1618
|
-
if (!op.id) {
|
|
1619
|
-
return true;
|
|
1620
|
-
}
|
|
1621
|
-
const scopeOps = drive.operations[op.action.scope];
|
|
1622
|
-
if (!scopeOps) {
|
|
1623
|
-
return true;
|
|
1624
|
-
}
|
|
1625
|
-
return !scopeOps.find((existingOp) => existingOp.id === op.id &&
|
|
1626
|
-
existingOp.index === op.index &&
|
|
1627
|
-
existingOp.action.type === op.action.type &&
|
|
1628
|
-
existingOp.hash === op.hash);
|
|
1629
|
-
});
|
|
1630
|
-
if (!newOperation) {
|
|
1631
|
-
return {
|
|
1632
|
-
status: "SUCCESS",
|
|
1633
|
-
document: drive,
|
|
1634
|
-
operations: operations,
|
|
1635
|
-
signals: [],
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
else {
|
|
1639
|
-
return undefined;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
catch (error) {
|
|
1643
|
-
console.error(error); // TODO error
|
|
1644
|
-
return undefined;
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* @deprecated Use the {@link queueOperations} method instead.
|
|
1649
|
-
*/
|
|
1650
|
-
async queueDriveOperations(driveId, operations, options) {
|
|
1651
|
-
// if operations are already stored then returns cached document
|
|
1652
|
-
const result = await this.resultIfExistingDriveOperations(driveId, operations);
|
|
1653
|
-
if (result) {
|
|
1654
|
-
return result;
|
|
1655
|
-
}
|
|
1656
|
-
try {
|
|
1657
|
-
const jobId = await this.queueManager.addJob({
|
|
1658
|
-
documentId: driveId,
|
|
1659
|
-
operations,
|
|
1660
|
-
options,
|
|
1661
|
-
});
|
|
1662
|
-
return await new Promise((resolve, reject) => {
|
|
1663
|
-
const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
|
|
1664
|
-
if (job.jobId === jobId) {
|
|
1665
|
-
unsubscribe();
|
|
1666
|
-
unsubscribeError();
|
|
1667
|
-
resolve(result);
|
|
1668
|
-
}
|
|
1669
|
-
});
|
|
1670
|
-
const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
|
|
1671
|
-
if (job.jobId === jobId) {
|
|
1672
|
-
unsubscribe();
|
|
1673
|
-
unsubscribeError();
|
|
1674
|
-
reject(error);
|
|
1675
|
-
}
|
|
1676
|
-
});
|
|
1677
|
-
});
|
|
1678
|
-
}
|
|
1679
|
-
catch (error) {
|
|
1680
|
-
this.logger.error("Error adding drive job: @error", error);
|
|
1681
|
-
throw error;
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
/**
|
|
1685
|
-
* @deprecated Use the {@link addOperations} method instead.
|
|
1686
|
-
*/
|
|
1687
|
-
async addDriveOperations(driveId, operations, options) {
|
|
1688
|
-
return this.queueDriveOperations(driveId, operations, options);
|
|
1689
|
-
}
|
|
1690
|
-
async processDriveOperations(driveId, operations, options) {
|
|
1691
|
-
let document;
|
|
1692
|
-
const operationsApplied = [];
|
|
1693
|
-
const signals = [];
|
|
1694
|
-
let error;
|
|
1695
|
-
// if operations are already stored then returns cached drive
|
|
1696
|
-
const result = await this.resultIfExistingDriveOperations(driveId, operations);
|
|
1697
|
-
if (result) {
|
|
1698
|
-
return result;
|
|
1699
|
-
}
|
|
1700
|
-
try {
|
|
1701
|
-
await this._addDriveOperations(driveId, async (documentStorage) => {
|
|
1702
|
-
const result = await this._processOperations(driveId, documentStorage, operations.slice());
|
|
1703
|
-
document = result.document;
|
|
1704
|
-
operationsApplied.push(...result.operationsApplied);
|
|
1705
|
-
signals.push(...result.signals);
|
|
1706
|
-
error = result.error;
|
|
1707
|
-
return {
|
|
1708
|
-
operations: result.operationsApplied,
|
|
1709
|
-
document: result.document,
|
|
1710
|
-
};
|
|
1711
|
-
});
|
|
1712
|
-
if (!document || !isDocumentDrive(document)) {
|
|
1713
|
-
throw error ?? new Error("Invalid Document Drive document");
|
|
1714
|
-
}
|
|
1715
|
-
this.cache
|
|
1716
|
-
.setDocument(driveId, document)
|
|
1717
|
-
.catch((e) => this.logger.error("@error", e));
|
|
1718
|
-
this.cache
|
|
1719
|
-
.setDrive(driveId, document)
|
|
1720
|
-
.catch((e) => this.logger.error("@error", e));
|
|
1721
|
-
// update listener cache
|
|
1722
|
-
const lastOperation = operationsApplied
|
|
1723
|
-
.filter((op) => op.action.scope === "global")
|
|
1724
|
-
.slice()
|
|
1725
|
-
.pop();
|
|
1726
|
-
if (lastOperation) {
|
|
1727
|
-
// checks if any of the provided operations where reshufled
|
|
1728
|
-
const newOp = operationsApplied.find((appliedOp) => !operations.find((o) => o.id === appliedOp.id &&
|
|
1729
|
-
o.index === appliedOp.index &&
|
|
1730
|
-
o.skip === appliedOp.skip &&
|
|
1731
|
-
o.hash === appliedOp.hash));
|
|
1732
|
-
// if there are no new operations then reuses the provided source
|
|
1733
|
-
// otherwise sets it to local so listeners know that there were
|
|
1734
|
-
// new changes originating from this document drive server
|
|
1735
|
-
const source = newOp
|
|
1736
|
-
? { type: "local" }
|
|
1737
|
-
: (options?.source ?? { type: "local" });
|
|
1738
|
-
const operationSource = this.getOperationSource(source);
|
|
1739
|
-
this.listenerManager
|
|
1740
|
-
.updateSynchronizationRevisions([
|
|
1741
|
-
{
|
|
1742
|
-
documentId: driveId,
|
|
1743
|
-
documentType: document.header.documentType,
|
|
1744
|
-
scope: "global",
|
|
1745
|
-
branch: "main",
|
|
1746
|
-
lastUpdated: lastOperation.timestampUtcMs,
|
|
1747
|
-
revision: lastOperation.index,
|
|
1748
|
-
},
|
|
1749
|
-
], source, () => {
|
|
1750
|
-
this.synchronizationManager.updateSyncStatus(driveId, {
|
|
1751
|
-
[operationSource]: "SYNCING",
|
|
1752
|
-
});
|
|
1753
|
-
}, this.handleListenerError.bind(this), options?.forceSync ?? source.type === "local")
|
|
1754
|
-
.then((updates) => {
|
|
1755
|
-
if (updates.length) {
|
|
1756
|
-
this.synchronizationManager.updateSyncStatus(driveId, {
|
|
1757
|
-
[operationSource]: "SUCCESS",
|
|
1758
|
-
});
|
|
1759
|
-
}
|
|
1760
|
-
})
|
|
1761
|
-
.catch((error) => {
|
|
1762
|
-
this.logger.error("Non handled error updating sync revision: @error", error);
|
|
1763
|
-
this.synchronizationManager.updateSyncStatus(driveId, {
|
|
1764
|
-
[operationSource]: "ERROR",
|
|
1765
|
-
}, error);
|
|
1766
|
-
});
|
|
1767
|
-
}
|
|
1768
|
-
if (this.shouldSyncRemoteDrive(document)) {
|
|
1769
|
-
this.startSyncRemoteDrive(driveId).catch((e) => this.logger.error("@error", e));
|
|
1770
|
-
}
|
|
1771
|
-
else {
|
|
1772
|
-
this.stopSyncRemoteDrive(driveId).catch((e) => this.logger.error("@error", e));
|
|
1773
|
-
}
|
|
1774
|
-
// after applying all the valid operations,throws
|
|
1775
|
-
// an error if there was an invalid operation
|
|
1776
|
-
if (error) {
|
|
1777
|
-
throw error;
|
|
1778
|
-
}
|
|
1779
|
-
this.eventEmitter.emit("driveOperationsAdded", driveId, operations);
|
|
1780
|
-
this.eventEmitter.emit("operationsAdded", driveId, operations);
|
|
1781
|
-
return {
|
|
1782
|
-
status: "SUCCESS",
|
|
1783
|
-
document,
|
|
1784
|
-
operations: operationsApplied,
|
|
1785
|
-
signals,
|
|
1786
|
-
};
|
|
1787
|
-
}
|
|
1788
|
-
catch (error) {
|
|
1789
|
-
const operationError = error instanceof OperationError
|
|
1790
|
-
? error
|
|
1791
|
-
: new OperationError("ERROR", undefined, error.message, error);
|
|
1792
|
-
return {
|
|
1793
|
-
status: operationError.status,
|
|
1794
|
-
error: operationError,
|
|
1795
|
-
document,
|
|
1796
|
-
operations: operationsApplied,
|
|
1797
|
-
signals,
|
|
1798
|
-
};
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
_buildOperations(documentId, actions) {
|
|
1802
|
-
const operations = [];
|
|
1803
|
-
const { reducer } = this.getDocumentModelModule(documentId.header.documentType);
|
|
1804
|
-
for (const action of actions) {
|
|
1805
|
-
documentId = reducer(documentId, action);
|
|
1806
|
-
const scopeOps = documentId.operations[action.scope];
|
|
1807
|
-
if (!scopeOps) {
|
|
1808
|
-
throw new Error(`No operations found for scope: ${action.scope}`);
|
|
1809
|
-
}
|
|
1810
|
-
const operation = scopeOps.slice().pop();
|
|
1811
|
-
if (!operation) {
|
|
1812
|
-
throw new Error("Error creating operations");
|
|
1813
|
-
}
|
|
1814
|
-
operations.push(operation);
|
|
1815
|
-
}
|
|
1816
|
-
return operations;
|
|
1817
|
-
}
|
|
1818
|
-
addAction(driveIdOrDocumentId, documentIdOrAction, actionOrOptions, maybeOptions) {
|
|
1819
|
-
let documentId;
|
|
1820
|
-
let action;
|
|
1821
|
-
let options;
|
|
1822
|
-
if (typeof documentIdOrAction === "string") {
|
|
1823
|
-
// Deprecated overload: (driveId, documentId, action, options)
|
|
1824
|
-
documentId = documentIdOrAction;
|
|
1825
|
-
action = actionOrOptions;
|
|
1826
|
-
options = maybeOptions;
|
|
1827
|
-
}
|
|
1828
|
-
else {
|
|
1829
|
-
// Standard overload: (documentId, action, options)
|
|
1830
|
-
documentId = driveIdOrDocumentId;
|
|
1831
|
-
action = documentIdOrAction;
|
|
1832
|
-
options = actionOrOptions;
|
|
1833
|
-
}
|
|
1834
|
-
return this._addAction(documentId, action, options);
|
|
1835
|
-
}
|
|
1836
|
-
async _addAction(documentId, action, options) {
|
|
1837
|
-
return this.addActions(documentId, [action], options);
|
|
1838
|
-
}
|
|
1839
|
-
addActions(driveIdOrDocumentId, documentIdOrActions, actionsOrOptions, maybeOptions) {
|
|
1840
|
-
let documentId;
|
|
1841
|
-
let actions;
|
|
1842
|
-
let options;
|
|
1843
|
-
if (typeof documentIdOrActions === "string") {
|
|
1844
|
-
// Deprecated overload: (driveId, documentId, actions, options)
|
|
1845
|
-
documentId = documentIdOrActions;
|
|
1846
|
-
actions = actionsOrOptions;
|
|
1847
|
-
options = maybeOptions;
|
|
1848
|
-
}
|
|
1849
|
-
else {
|
|
1850
|
-
// Standard overload: (documentId, actions, options)
|
|
1851
|
-
documentId = driveIdOrDocumentId;
|
|
1852
|
-
actions = documentIdOrActions;
|
|
1853
|
-
options = actionsOrOptions;
|
|
1854
|
-
}
|
|
1855
|
-
return this._queueActions(documentId, actions, options);
|
|
1856
|
-
}
|
|
1857
|
-
async processActions(documentId, actions, options) {
|
|
1858
|
-
const document = await this.getDocument(documentId);
|
|
1859
|
-
const operations = this._buildOperations(document, actions);
|
|
1860
|
-
return this.processOperations(documentId, operations, options);
|
|
1861
|
-
}
|
|
1862
|
-
/**
|
|
1863
|
-
* @deprecated Use the {@link addAction} method instead.
|
|
1864
|
-
*/
|
|
1865
|
-
async addDriveAction(driveId, action, options) {
|
|
1866
|
-
if ("synchronizationUnits" in action.input) {
|
|
1867
|
-
return this._legacyAddFileAction(driveId, action, options);
|
|
1868
|
-
}
|
|
1869
|
-
return this.addDriveActions(driveId, [action], options);
|
|
1870
|
-
}
|
|
1871
|
-
async _legacyAddFileAction(driveId, action, options) {
|
|
1872
|
-
// create document before adding it to the drive
|
|
1873
|
-
const document = this.getDocumentModelModule(action.input.documentType).utils.createDocument(action.input.document?.state || undefined);
|
|
1874
|
-
document.header.id = action.input.id;
|
|
1875
|
-
document.header.name = action.input.name;
|
|
1876
|
-
document.header.documentType = action.input.documentType;
|
|
1877
|
-
await this.queueDocument({ document }, { source: options?.source || { type: "local" } });
|
|
1878
|
-
// create updated version of the ADD_FILE action
|
|
1879
|
-
const newAction = {
|
|
1880
|
-
...action,
|
|
1881
|
-
input: {
|
|
1882
|
-
id: action.input.id,
|
|
1883
|
-
documentType: document.header.documentType,
|
|
1884
|
-
name: action.input.name,
|
|
1885
|
-
parentFolder: action.input.parentFolder,
|
|
1886
|
-
},
|
|
1887
|
-
};
|
|
1888
|
-
return (await this.addAction(driveId, newAction, options));
|
|
1889
|
-
}
|
|
1890
|
-
/**
|
|
1891
|
-
* @deprecated Use the {@link addActions} method instead.
|
|
1892
|
-
*/
|
|
1893
|
-
async addDriveActions(driveId, actions, options) {
|
|
1894
|
-
return this.queueDriveActions(driveId, actions, options);
|
|
1895
|
-
}
|
|
1896
|
-
async processDriveActions(driveId, actions, options) {
|
|
1897
|
-
const document = await this.getDrive(driveId);
|
|
1898
|
-
const operations = this._buildOperations(document, actions);
|
|
1899
|
-
return this.processDriveOperations(driveId, operations, options);
|
|
1900
|
-
}
|
|
1901
|
-
async detachDrive(driveId) {
|
|
1902
|
-
const documentDrive = await this.getDrive(driveId);
|
|
1903
|
-
const listeners = documentDrive.state.local.listeners || [];
|
|
1904
|
-
const triggers = documentDrive.state.local.triggers || [];
|
|
1905
|
-
for (const listener of listeners) {
|
|
1906
|
-
await this.addDriveAction(driveId, removeListener({ listenerId: listener.listenerId }));
|
|
1907
|
-
}
|
|
1908
|
-
for (const trigger of triggers) {
|
|
1909
|
-
await this.addDriveAction(driveId, removeTrigger({ triggerId: trigger.id }));
|
|
1910
|
-
}
|
|
1911
|
-
await this.addDriveAction(driveId, setSharingType({ type: "LOCAL" }));
|
|
1912
|
-
}
|
|
1913
|
-
getSyncStatus(documentId, scope, branch) {
|
|
1914
|
-
return this.synchronizationManager.getSyncStatus(documentId, scope, branch);
|
|
1915
|
-
}
|
|
1916
|
-
on(event, cb) {
|
|
1917
|
-
return this.eventEmitter.on(event, cb);
|
|
1918
|
-
}
|
|
1919
|
-
emit(event, ...args) {
|
|
1920
|
-
return this.eventEmitter.emit(event, ...args);
|
|
1921
|
-
}
|
|
1922
|
-
// Add delegated methods to properly implement ISynchronizationManager
|
|
1923
|
-
updateSyncStatus(syncUnitId, status, error) {
|
|
1924
|
-
this.synchronizationManager.updateSyncStatus(syncUnitId, status, error);
|
|
1925
|
-
}
|
|
1926
|
-
initializeDriveSyncStatus(driveId, drive) {
|
|
1927
|
-
return this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);
|
|
1928
|
-
}
|
|
1929
|
-
getCombinedSyncUnitStatus(syncUnitStatus) {
|
|
1930
|
-
return this.synchronizationManager.getCombinedSyncUnitStatus(syncUnitStatus);
|
|
1931
|
-
}
|
|
1932
|
-
// Add back the saveStrand method that was accidentally removed
|
|
1933
|
-
async saveStrand(strand, source) {
|
|
1934
|
-
const isNewDocument = !(await this.documentStorage.exists(strand.documentId));
|
|
1935
|
-
let result = undefined;
|
|
1936
|
-
if (isNewDocument) {
|
|
1937
|
-
result = await this.queueDocument({
|
|
1938
|
-
id: strand.documentId,
|
|
1939
|
-
documentType: strand.documentType,
|
|
1940
|
-
});
|
|
1941
|
-
}
|
|
1942
|
-
const operations = strand.operations.map((op) => ({
|
|
1943
|
-
...op,
|
|
1944
|
-
id: op.id ??
|
|
1945
|
-
deriveOperationId(strand.documentId, strand.scope, strand.branch, op.actionId),
|
|
1946
|
-
action: {
|
|
1947
|
-
id: op.actionId,
|
|
1948
|
-
timestampUtcMs: op.timestampUtcMs,
|
|
1949
|
-
type: op.type,
|
|
1950
|
-
input: op.input,
|
|
1951
|
-
context: op.context,
|
|
1952
|
-
scope: strand.scope,
|
|
1953
|
-
},
|
|
1954
|
-
scope: strand.scope,
|
|
1955
|
-
branch: strand.branch,
|
|
1956
|
-
}));
|
|
1957
|
-
// if document already existed or queueDocument
|
|
1958
|
-
// was successful, queues the operations
|
|
1959
|
-
if ((!isNewDocument || result?.status === "SUCCESS") && operations.length) {
|
|
1960
|
-
try {
|
|
1961
|
-
result = await this.queueOperations(strand.documentId, operations, {
|
|
1962
|
-
source,
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
catch (error) {
|
|
1966
|
-
this.logger.error("Error queueing operations: @error", error);
|
|
1967
|
-
throw error;
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
if (!result) {
|
|
1971
|
-
this.logger.debug("Document @documentId already exists", strand.documentId);
|
|
1972
|
-
return {
|
|
1973
|
-
status: "SUCCESS",
|
|
1974
|
-
document: await this.getDocument(strand.documentId),
|
|
1975
|
-
operations: [],
|
|
1976
|
-
signals: [],
|
|
1977
|
-
};
|
|
1978
|
-
}
|
|
1979
|
-
if (result.status === "ERROR") {
|
|
1980
|
-
const operationSource = this.getOperationSource(source);
|
|
1981
|
-
this.synchronizationManager.updateSyncStatus({
|
|
1982
|
-
documentId: strand.documentId || strand.driveId,
|
|
1983
|
-
scope: strand.scope,
|
|
1984
|
-
branch: strand.branch,
|
|
1985
|
-
}, { [operationSource]: result.status }, result.error);
|
|
1986
|
-
}
|
|
1987
|
-
this.eventEmitter.emit("strandUpdate", strand);
|
|
1988
|
-
return result;
|
|
1989
|
-
}
|
|
1990
|
-
setGenerateJwtHandler(handler) {
|
|
1991
|
-
this.generateJwtHandler = handler;
|
|
1992
|
-
this.listenerManager.setGenerateJwtHandler(handler);
|
|
1993
|
-
}
|
|
1994
|
-
removeJwtHandler() {
|
|
1995
|
-
this.generateJwtHandler = undefined;
|
|
1996
|
-
this.listenerManager.removeJwtHandler();
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
export const DocumentDriveServer = ReadModeServer(BaseDocumentDriveServer);
|
|
2000
|
-
//# sourceMappingURL=base-server.js.map
|