anchordb 0.2.0
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/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/cjs/conflict/strategies.d.ts +110 -0
- package/dist/cjs/conflict/strategies.d.ts.map +1 -0
- package/dist/cjs/conflict/strategies.js +298 -0
- package/dist/cjs/conflict/strategies.js.map +1 -0
- package/dist/cjs/conflict/types.d.ts +38 -0
- package/dist/cjs/conflict/types.d.ts.map +1 -0
- package/dist/cjs/conflict/types.js +3 -0
- package/dist/cjs/conflict/types.js.map +1 -0
- package/dist/cjs/core/anchor-db.d.ts +154 -0
- package/dist/cjs/core/anchor-db.d.ts.map +1 -0
- package/dist/cjs/core/anchor-db.js +273 -0
- package/dist/cjs/core/anchor-db.js.map +1 -0
- package/dist/cjs/core/errors.d.ts +125 -0
- package/dist/cjs/core/errors.d.ts.map +1 -0
- package/dist/cjs/core/errors.js +174 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/hex.d.ts +4 -0
- package/dist/cjs/core/hex.d.ts.map +1 -0
- package/dist/cjs/core/hex.js +41 -0
- package/dist/cjs/core/hex.js.map +1 -0
- package/dist/cjs/core/hlc.d.ts +96 -0
- package/dist/cjs/core/hlc.d.ts.map +1 -0
- package/dist/cjs/core/hlc.js +161 -0
- package/dist/cjs/core/hlc.js.map +1 -0
- package/dist/cjs/core/object-id.d.ts +38 -0
- package/dist/cjs/core/object-id.d.ts.map +1 -0
- package/dist/cjs/core/object-id.js +167 -0
- package/dist/cjs/core/object-id.js.map +1 -0
- package/dist/cjs/core/random.d.ts +6 -0
- package/dist/cjs/core/random.d.ts.map +1 -0
- package/dist/cjs/core/random.js +39 -0
- package/dist/cjs/core/random.js.map +1 -0
- package/dist/cjs/core/runtime.d.ts +96 -0
- package/dist/cjs/core/runtime.d.ts.map +1 -0
- package/dist/cjs/core/runtime.js +3 -0
- package/dist/cjs/core/runtime.js.map +1 -0
- package/dist/cjs/core/uuid.d.ts +16 -0
- package/dist/cjs/core/uuid.d.ts.map +1 -0
- package/dist/cjs/core/uuid.js +37 -0
- package/dist/cjs/core/uuid.js.map +1 -0
- package/dist/cjs/decorators/index.d.ts +48 -0
- package/dist/cjs/decorators/index.d.ts.map +1 -0
- package/dist/cjs/decorators/index.js +295 -0
- package/dist/cjs/decorators/index.js.map +1 -0
- package/dist/cjs/events/emitter.d.ts +16 -0
- package/dist/cjs/events/emitter.d.ts.map +1 -0
- package/dist/cjs/events/emitter.js +56 -0
- package/dist/cjs/events/emitter.js.map +1 -0
- package/dist/cjs/index/keys.d.ts +79 -0
- package/dist/cjs/index/keys.d.ts.map +1 -0
- package/dist/cjs/index/keys.js +208 -0
- package/dist/cjs/index/keys.js.map +1 -0
- package/dist/cjs/index.d.ts +81 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +193 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/inspector/agent.d.ts +75 -0
- package/dist/cjs/inspector/agent.d.ts.map +1 -0
- package/dist/cjs/inspector/agent.js +520 -0
- package/dist/cjs/inspector/agent.js.map +1 -0
- package/dist/cjs/inspector/auth.d.ts +49 -0
- package/dist/cjs/inspector/auth.d.ts.map +1 -0
- package/dist/cjs/inspector/auth.js +234 -0
- package/dist/cjs/inspector/auth.js.map +1 -0
- package/dist/cjs/inspector/bridge.d.ts +141 -0
- package/dist/cjs/inspector/bridge.d.ts.map +1 -0
- package/dist/cjs/inspector/bridge.js +190 -0
- package/dist/cjs/inspector/bridge.js.map +1 -0
- package/dist/cjs/inspector/client.d.ts +111 -0
- package/dist/cjs/inspector/client.d.ts.map +1 -0
- package/dist/cjs/inspector/client.js +218 -0
- package/dist/cjs/inspector/client.js.map +1 -0
- package/dist/cjs/inspector/protocol.d.ts +160 -0
- package/dist/cjs/inspector/protocol.d.ts.map +1 -0
- package/dist/cjs/inspector/protocol.js +53 -0
- package/dist/cjs/inspector/protocol.js.map +1 -0
- package/dist/cjs/inspector/transports/in-process.d.ts +7 -0
- package/dist/cjs/inspector/transports/in-process.d.ts.map +1 -0
- package/dist/cjs/inspector/transports/in-process.js +58 -0
- package/dist/cjs/inspector/transports/in-process.js.map +1 -0
- package/dist/cjs/inspector/transports/websocket.d.ts +39 -0
- package/dist/cjs/inspector/transports/websocket.d.ts.map +1 -0
- package/dist/cjs/inspector/transports/websocket.js +60 -0
- package/dist/cjs/inspector/transports/websocket.js.map +1 -0
- package/dist/cjs/interop/csv.d.ts +53 -0
- package/dist/cjs/interop/csv.d.ts.map +1 -0
- package/dist/cjs/interop/csv.js +230 -0
- package/dist/cjs/interop/csv.js.map +1 -0
- package/dist/cjs/interop/ejson.d.ts +41 -0
- package/dist/cjs/interop/ejson.d.ts.map +1 -0
- package/dist/cjs/interop/ejson.js +182 -0
- package/dist/cjs/interop/ejson.js.map +1 -0
- package/dist/cjs/interop/export-import.d.ts +98 -0
- package/dist/cjs/interop/export-import.d.ts.map +1 -0
- package/dist/cjs/interop/export-import.js +222 -0
- package/dist/cjs/interop/export-import.js.map +1 -0
- package/dist/cjs/model/document.d.ts +66 -0
- package/dist/cjs/model/document.d.ts.map +1 -0
- package/dist/cjs/model/document.js +302 -0
- package/dist/cjs/model/document.js.map +1 -0
- package/dist/cjs/model/model.d.ts +178 -0
- package/dist/cjs/model/model.d.ts.map +1 -0
- package/dist/cjs/model/model.js +823 -0
- package/dist/cjs/model/model.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/query/aggregation/expressions.d.ts +34 -0
- package/dist/cjs/query/aggregation/expressions.d.ts.map +1 -0
- package/dist/cjs/query/aggregation/expressions.js +552 -0
- package/dist/cjs/query/aggregation/expressions.js.map +1 -0
- package/dist/cjs/query/aggregation/pipeline.d.ts +79 -0
- package/dist/cjs/query/aggregation/pipeline.d.ts.map +1 -0
- package/dist/cjs/query/aggregation/pipeline.js +597 -0
- package/dist/cjs/query/aggregation/pipeline.js.map +1 -0
- package/dist/cjs/query/aggregation/source.d.ts +35 -0
- package/dist/cjs/query/aggregation/source.d.ts.map +1 -0
- package/dist/cjs/query/aggregation/source.js +81 -0
- package/dist/cjs/query/aggregation/source.js.map +1 -0
- package/dist/cjs/query/builder/query.d.ts +113 -0
- package/dist/cjs/query/builder/query.d.ts.map +1 -0
- package/dist/cjs/query/builder/query.js +215 -0
- package/dist/cjs/query/builder/query.js.map +1 -0
- package/dist/cjs/query/filter.d.ts +50 -0
- package/dist/cjs/query/filter.d.ts.map +1 -0
- package/dist/cjs/query/filter.js +275 -0
- package/dist/cjs/query/filter.js.map +1 -0
- package/dist/cjs/query/path.d.ts +41 -0
- package/dist/cjs/query/path.d.ts.map +1 -0
- package/dist/cjs/query/path.js +294 -0
- package/dist/cjs/query/path.js.map +1 -0
- package/dist/cjs/query/update.d.ts +30 -0
- package/dist/cjs/query/update.d.ts.map +1 -0
- package/dist/cjs/query/update.js +205 -0
- package/dist/cjs/query/update.js.map +1 -0
- package/dist/cjs/reactive/live-query.d.ts +41 -0
- package/dist/cjs/reactive/live-query.d.ts.map +1 -0
- package/dist/cjs/reactive/live-query.js +88 -0
- package/dist/cjs/reactive/live-query.js.map +1 -0
- package/dist/cjs/schema/cast.d.ts +38 -0
- package/dist/cjs/schema/cast.d.ts.map +1 -0
- package/dist/cjs/schema/cast.js +280 -0
- package/dist/cjs/schema/cast.js.map +1 -0
- package/dist/cjs/schema/index.d.ts +5 -0
- package/dist/cjs/schema/index.d.ts.map +1 -0
- package/dist/cjs/schema/index.js +27 -0
- package/dist/cjs/schema/index.js.map +1 -0
- package/dist/cjs/schema/schema.d.ts +58 -0
- package/dist/cjs/schema/schema.d.ts.map +1 -0
- package/dist/cjs/schema/schema.js +363 -0
- package/dist/cjs/schema/schema.js.map +1 -0
- package/dist/cjs/schema/types.d.ts +144 -0
- package/dist/cjs/schema/types.d.ts.map +1 -0
- package/dist/cjs/schema/types.js +20 -0
- package/dist/cjs/schema/types.js.map +1 -0
- package/dist/cjs/schema/validate.d.ts +15 -0
- package/dist/cjs/schema/validate.d.ts.map +1 -0
- package/dist/cjs/schema/validate.js +101 -0
- package/dist/cjs/schema/validate.js.map +1 -0
- package/dist/cjs/storage/adapters/capacitor-sqlite.d.ts +67 -0
- package/dist/cjs/storage/adapters/capacitor-sqlite.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/capacitor-sqlite.js +69 -0
- package/dist/cjs/storage/adapters/capacitor-sqlite.js.map +1 -0
- package/dist/cjs/storage/adapters/expo-sqlite.d.ts +55 -0
- package/dist/cjs/storage/adapters/expo-sqlite.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/expo-sqlite.js +53 -0
- package/dist/cjs/storage/adapters/expo-sqlite.js.map +1 -0
- package/dist/cjs/storage/adapters/indexeddb.d.ts +55 -0
- package/dist/cjs/storage/adapters/indexeddb.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/indexeddb.js +393 -0
- package/dist/cjs/storage/adapters/indexeddb.js.map +1 -0
- package/dist/cjs/storage/adapters/memory.d.ts +44 -0
- package/dist/cjs/storage/adapters/memory.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/memory.js +286 -0
- package/dist/cjs/storage/adapters/memory.js.map +1 -0
- package/dist/cjs/storage/adapters/node-sqlite.d.ts +59 -0
- package/dist/cjs/storage/adapters/node-sqlite.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/node-sqlite.js +457 -0
- package/dist/cjs/storage/adapters/node-sqlite.js.map +1 -0
- package/dist/cjs/storage/adapters/sql-base.d.ts +84 -0
- package/dist/cjs/storage/adapters/sql-base.d.ts.map +1 -0
- package/dist/cjs/storage/adapters/sql-base.js +393 -0
- package/dist/cjs/storage/adapters/sql-base.js.map +1 -0
- package/dist/cjs/storage/types.d.ts +131 -0
- package/dist/cjs/storage/types.d.ts.map +1 -0
- package/dist/cjs/storage/types.js +3 -0
- package/dist/cjs/storage/types.js.map +1 -0
- package/dist/cjs/sync/adapters/rest.d.ts +31 -0
- package/dist/cjs/sync/adapters/rest.d.ts.map +1 -0
- package/dist/cjs/sync/adapters/rest.js +75 -0
- package/dist/cjs/sync/adapters/rest.js.map +1 -0
- package/dist/cjs/sync/attach.d.ts +30 -0
- package/dist/cjs/sync/attach.d.ts.map +1 -0
- package/dist/cjs/sync/attach.js +104 -0
- package/dist/cjs/sync/attach.js.map +1 -0
- package/dist/cjs/sync/engine.d.ts +96 -0
- package/dist/cjs/sync/engine.d.ts.map +1 -0
- package/dist/cjs/sync/engine.js +491 -0
- package/dist/cjs/sync/engine.js.map +1 -0
- package/dist/cjs/sync/protocol.d.ts +128 -0
- package/dist/cjs/sync/protocol.d.ts.map +1 -0
- package/dist/cjs/sync/protocol.js +38 -0
- package/dist/cjs/sync/protocol.js.map +1 -0
- package/dist/cjs/sync/queue.d.ts +77 -0
- package/dist/cjs/sync/queue.d.ts.map +1 -0
- package/dist/cjs/sync/queue.js +245 -0
- package/dist/cjs/sync/queue.js.map +1 -0
- package/dist/cjs/sync/server/memory-server.d.ts +65 -0
- package/dist/cjs/sync/server/memory-server.d.ts.map +1 -0
- package/dist/cjs/sync/server/memory-server.js +193 -0
- package/dist/cjs/sync/server/memory-server.js.map +1 -0
- package/dist/cjs/timestamps/index.d.ts +47 -0
- package/dist/cjs/timestamps/index.d.ts.map +1 -0
- package/dist/cjs/timestamps/index.js +88 -0
- package/dist/cjs/timestamps/index.js.map +1 -0
- package/dist/cjs/timestamps/timezone.d.ts +65 -0
- package/dist/cjs/timestamps/timezone.d.ts.map +1 -0
- package/dist/cjs/timestamps/timezone.js +208 -0
- package/dist/cjs/timestamps/timezone.js.map +1 -0
- package/dist/esm/conflict/strategies.d.ts +110 -0
- package/dist/esm/conflict/strategies.d.ts.map +1 -0
- package/dist/esm/conflict/strategies.js +289 -0
- package/dist/esm/conflict/strategies.js.map +1 -0
- package/dist/esm/conflict/types.d.ts +38 -0
- package/dist/esm/conflict/types.d.ts.map +1 -0
- package/dist/esm/conflict/types.js +2 -0
- package/dist/esm/conflict/types.js.map +1 -0
- package/dist/esm/core/anchor-db.d.ts +154 -0
- package/dist/esm/core/anchor-db.d.ts.map +1 -0
- package/dist/esm/core/anchor-db.js +269 -0
- package/dist/esm/core/anchor-db.js.map +1 -0
- package/dist/esm/core/errors.d.ts +125 -0
- package/dist/esm/core/errors.d.ts.map +1 -0
- package/dist/esm/core/errors.js +161 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/hex.d.ts +4 -0
- package/dist/esm/core/hex.d.ts.map +1 -0
- package/dist/esm/core/hex.js +37 -0
- package/dist/esm/core/hex.js.map +1 -0
- package/dist/esm/core/hlc.d.ts +96 -0
- package/dist/esm/core/hlc.d.ts.map +1 -0
- package/dist/esm/core/hlc.js +153 -0
- package/dist/esm/core/hlc.js.map +1 -0
- package/dist/esm/core/object-id.d.ts +38 -0
- package/dist/esm/core/object-id.d.ts.map +1 -0
- package/dist/esm/core/object-id.js +163 -0
- package/dist/esm/core/object-id.js.map +1 -0
- package/dist/esm/core/random.d.ts +6 -0
- package/dist/esm/core/random.d.ts.map +1 -0
- package/dist/esm/core/random.js +34 -0
- package/dist/esm/core/random.js.map +1 -0
- package/dist/esm/core/runtime.d.ts +96 -0
- package/dist/esm/core/runtime.d.ts.map +1 -0
- package/dist/esm/core/runtime.js +2 -0
- package/dist/esm/core/runtime.js.map +1 -0
- package/dist/esm/core/uuid.d.ts +16 -0
- package/dist/esm/core/uuid.d.ts.map +1 -0
- package/dist/esm/core/uuid.js +33 -0
- package/dist/esm/core/uuid.js.map +1 -0
- package/dist/esm/decorators/index.d.ts +48 -0
- package/dist/esm/decorators/index.d.ts.map +1 -0
- package/dist/esm/decorators/index.js +286 -0
- package/dist/esm/decorators/index.js.map +1 -0
- package/dist/esm/events/emitter.d.ts +16 -0
- package/dist/esm/events/emitter.d.ts.map +1 -0
- package/dist/esm/events/emitter.js +52 -0
- package/dist/esm/events/emitter.js.map +1 -0
- package/dist/esm/index/keys.d.ts +79 -0
- package/dist/esm/index/keys.d.ts.map +1 -0
- package/dist/esm/index/keys.js +198 -0
- package/dist/esm/index/keys.js.map +1 -0
- package/dist/esm/index.d.ts +81 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +59 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/inspector/agent.d.ts +75 -0
- package/dist/esm/inspector/agent.d.ts.map +1 -0
- package/dist/esm/inspector/agent.js +482 -0
- package/dist/esm/inspector/agent.js.map +1 -0
- package/dist/esm/inspector/auth.d.ts +49 -0
- package/dist/esm/inspector/auth.d.ts.map +1 -0
- package/dist/esm/inspector/auth.js +228 -0
- package/dist/esm/inspector/auth.js.map +1 -0
- package/dist/esm/inspector/bridge.d.ts +141 -0
- package/dist/esm/inspector/bridge.d.ts.map +1 -0
- package/dist/esm/inspector/bridge.js +182 -0
- package/dist/esm/inspector/bridge.js.map +1 -0
- package/dist/esm/inspector/client.d.ts +111 -0
- package/dist/esm/inspector/client.d.ts.map +1 -0
- package/dist/esm/inspector/client.js +213 -0
- package/dist/esm/inspector/client.js.map +1 -0
- package/dist/esm/inspector/protocol.d.ts +160 -0
- package/dist/esm/inspector/protocol.d.ts.map +1 -0
- package/dist/esm/inspector/protocol.js +43 -0
- package/dist/esm/inspector/protocol.js.map +1 -0
- package/dist/esm/inspector/transports/in-process.d.ts +7 -0
- package/dist/esm/inspector/transports/in-process.d.ts.map +1 -0
- package/dist/esm/inspector/transports/in-process.js +55 -0
- package/dist/esm/inspector/transports/in-process.js.map +1 -0
- package/dist/esm/inspector/transports/websocket.d.ts +39 -0
- package/dist/esm/inspector/transports/websocket.d.ts.map +1 -0
- package/dist/esm/inspector/transports/websocket.js +56 -0
- package/dist/esm/inspector/transports/websocket.js.map +1 -0
- package/dist/esm/interop/csv.d.ts +53 -0
- package/dist/esm/interop/csv.d.ts.map +1 -0
- package/dist/esm/interop/csv.js +222 -0
- package/dist/esm/interop/csv.js.map +1 -0
- package/dist/esm/interop/ejson.d.ts +41 -0
- package/dist/esm/interop/ejson.d.ts.map +1 -0
- package/dist/esm/interop/ejson.js +176 -0
- package/dist/esm/interop/ejson.js.map +1 -0
- package/dist/esm/interop/export-import.d.ts +98 -0
- package/dist/esm/interop/export-import.d.ts.map +1 -0
- package/dist/esm/interop/export-import.js +210 -0
- package/dist/esm/interop/export-import.js.map +1 -0
- package/dist/esm/model/document.d.ts +66 -0
- package/dist/esm/model/document.d.ts.map +1 -0
- package/dist/esm/model/document.js +297 -0
- package/dist/esm/model/document.js.map +1 -0
- package/dist/esm/model/model.d.ts +178 -0
- package/dist/esm/model/model.d.ts.map +1 -0
- package/dist/esm/model/model.js +815 -0
- package/dist/esm/model/model.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/query/aggregation/expressions.d.ts +34 -0
- package/dist/esm/query/aggregation/expressions.d.ts.map +1 -0
- package/dist/esm/query/aggregation/expressions.js +545 -0
- package/dist/esm/query/aggregation/expressions.js.map +1 -0
- package/dist/esm/query/aggregation/pipeline.d.ts +79 -0
- package/dist/esm/query/aggregation/pipeline.d.ts.map +1 -0
- package/dist/esm/query/aggregation/pipeline.js +591 -0
- package/dist/esm/query/aggregation/pipeline.js.map +1 -0
- package/dist/esm/query/aggregation/source.d.ts +35 -0
- package/dist/esm/query/aggregation/source.d.ts.map +1 -0
- package/dist/esm/query/aggregation/source.js +77 -0
- package/dist/esm/query/aggregation/source.js.map +1 -0
- package/dist/esm/query/builder/query.d.ts +113 -0
- package/dist/esm/query/builder/query.d.ts.map +1 -0
- package/dist/esm/query/builder/query.js +209 -0
- package/dist/esm/query/builder/query.js.map +1 -0
- package/dist/esm/query/filter.d.ts +50 -0
- package/dist/esm/query/filter.d.ts.map +1 -0
- package/dist/esm/query/filter.js +267 -0
- package/dist/esm/query/filter.js.map +1 -0
- package/dist/esm/query/path.d.ts +41 -0
- package/dist/esm/query/path.d.ts.map +1 -0
- package/dist/esm/query/path.js +282 -0
- package/dist/esm/query/path.js.map +1 -0
- package/dist/esm/query/update.d.ts +30 -0
- package/dist/esm/query/update.d.ts.map +1 -0
- package/dist/esm/query/update.js +198 -0
- package/dist/esm/query/update.js.map +1 -0
- package/dist/esm/reactive/live-query.d.ts +41 -0
- package/dist/esm/reactive/live-query.d.ts.map +1 -0
- package/dist/esm/reactive/live-query.js +83 -0
- package/dist/esm/reactive/live-query.js.map +1 -0
- package/dist/esm/schema/cast.d.ts +38 -0
- package/dist/esm/schema/cast.d.ts.map +1 -0
- package/dist/esm/schema/cast.js +275 -0
- package/dist/esm/schema/cast.js.map +1 -0
- package/dist/esm/schema/index.d.ts +5 -0
- package/dist/esm/schema/index.d.ts.map +1 -0
- package/dist/esm/schema/index.js +5 -0
- package/dist/esm/schema/index.js.map +1 -0
- package/dist/esm/schema/schema.d.ts +58 -0
- package/dist/esm/schema/schema.d.ts.map +1 -0
- package/dist/esm/schema/schema.js +358 -0
- package/dist/esm/schema/schema.js.map +1 -0
- package/dist/esm/schema/types.d.ts +144 -0
- package/dist/esm/schema/types.d.ts.map +1 -0
- package/dist/esm/schema/types.js +17 -0
- package/dist/esm/schema/types.js.map +1 -0
- package/dist/esm/schema/validate.d.ts +15 -0
- package/dist/esm/schema/validate.d.ts.map +1 -0
- package/dist/esm/schema/validate.js +98 -0
- package/dist/esm/schema/validate.js.map +1 -0
- package/dist/esm/storage/adapters/capacitor-sqlite.d.ts +67 -0
- package/dist/esm/storage/adapters/capacitor-sqlite.d.ts.map +1 -0
- package/dist/esm/storage/adapters/capacitor-sqlite.js +65 -0
- package/dist/esm/storage/adapters/capacitor-sqlite.js.map +1 -0
- package/dist/esm/storage/adapters/expo-sqlite.d.ts +55 -0
- package/dist/esm/storage/adapters/expo-sqlite.d.ts.map +1 -0
- package/dist/esm/storage/adapters/expo-sqlite.js +49 -0
- package/dist/esm/storage/adapters/expo-sqlite.js.map +1 -0
- package/dist/esm/storage/adapters/indexeddb.d.ts +55 -0
- package/dist/esm/storage/adapters/indexeddb.d.ts.map +1 -0
- package/dist/esm/storage/adapters/indexeddb.js +389 -0
- package/dist/esm/storage/adapters/indexeddb.js.map +1 -0
- package/dist/esm/storage/adapters/memory.d.ts +44 -0
- package/dist/esm/storage/adapters/memory.d.ts.map +1 -0
- package/dist/esm/storage/adapters/memory.js +282 -0
- package/dist/esm/storage/adapters/memory.js.map +1 -0
- package/dist/esm/storage/adapters/node-sqlite.d.ts +59 -0
- package/dist/esm/storage/adapters/node-sqlite.d.ts.map +1 -0
- package/dist/esm/storage/adapters/node-sqlite.js +450 -0
- package/dist/esm/storage/adapters/node-sqlite.js.map +1 -0
- package/dist/esm/storage/adapters/sql-base.d.ts +84 -0
- package/dist/esm/storage/adapters/sql-base.d.ts.map +1 -0
- package/dist/esm/storage/adapters/sql-base.js +383 -0
- package/dist/esm/storage/adapters/sql-base.js.map +1 -0
- package/dist/esm/storage/types.d.ts +131 -0
- package/dist/esm/storage/types.d.ts.map +1 -0
- package/dist/esm/storage/types.js +2 -0
- package/dist/esm/storage/types.js.map +1 -0
- package/dist/esm/sync/adapters/rest.d.ts +31 -0
- package/dist/esm/sync/adapters/rest.d.ts.map +1 -0
- package/dist/esm/sync/adapters/rest.js +71 -0
- package/dist/esm/sync/adapters/rest.js.map +1 -0
- package/dist/esm/sync/attach.d.ts +30 -0
- package/dist/esm/sync/attach.d.ts.map +1 -0
- package/dist/esm/sync/attach.js +98 -0
- package/dist/esm/sync/attach.js.map +1 -0
- package/dist/esm/sync/engine.d.ts +96 -0
- package/dist/esm/sync/engine.d.ts.map +1 -0
- package/dist/esm/sync/engine.js +487 -0
- package/dist/esm/sync/engine.js.map +1 -0
- package/dist/esm/sync/protocol.d.ts +128 -0
- package/dist/esm/sync/protocol.d.ts.map +1 -0
- package/dist/esm/sync/protocol.js +33 -0
- package/dist/esm/sync/protocol.js.map +1 -0
- package/dist/esm/sync/queue.d.ts +77 -0
- package/dist/esm/sync/queue.d.ts.map +1 -0
- package/dist/esm/sync/queue.js +241 -0
- package/dist/esm/sync/queue.js.map +1 -0
- package/dist/esm/sync/server/memory-server.d.ts +65 -0
- package/dist/esm/sync/server/memory-server.d.ts.map +1 -0
- package/dist/esm/sync/server/memory-server.js +189 -0
- package/dist/esm/sync/server/memory-server.js.map +1 -0
- package/dist/esm/timestamps/index.d.ts +47 -0
- package/dist/esm/timestamps/index.d.ts.map +1 -0
- package/dist/esm/timestamps/index.js +70 -0
- package/dist/esm/timestamps/index.js.map +1 -0
- package/dist/esm/timestamps/timezone.d.ts +65 -0
- package/dist/esm/timestamps/timezone.d.ts.map +1 -0
- package/dist/esm/timestamps/timezone.js +196 -0
- package/dist/esm/timestamps/timezone.js.map +1 -0
- package/package.json +163 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The Anchor Sync Protocol, version 1.
|
|
4
|
+
*
|
|
5
|
+
* Design constraints that shaped this:
|
|
6
|
+
*
|
|
7
|
+
* - **Plain JSON, Mongoose-friendly.** Documents travel with `_id` as a 24-char hex string and
|
|
8
|
+
* timestamps as ISO-8601 UTC strings, because Mongoose casts both automatically. A backend can
|
|
9
|
+
* hand the payload straight to a model with no field mapping.
|
|
10
|
+
* - **Every change gets exactly one verdict.** `accepted | rejected | conflict`. A push that
|
|
11
|
+
* silently drops a change is indistinguishable from a lost mutation, so the response is
|
|
12
|
+
* positionally complete.
|
|
13
|
+
* - **Idempotent by construction.** The server memoises `(clientId, mutationId)`, so a retry after
|
|
14
|
+
* a timeout replays the original verdict rather than applying the write twice. This is what
|
|
15
|
+
* makes at-least-once delivery safe on a flaky mobile network.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.SyncTransportError = exports.SyncAuthError = exports.PROTOCOL_VERSION = void 0;
|
|
19
|
+
exports.PROTOCOL_VERSION = 1;
|
|
20
|
+
/** Thrown for HTTP 401/403 so the engine can pause rather than discard queued work. */
|
|
21
|
+
class SyncAuthError extends Error {
|
|
22
|
+
constructor(status, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "SyncAuthError";
|
|
25
|
+
this.status = status;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.SyncAuthError = SyncAuthError;
|
|
29
|
+
/** Thrown for transport failures — retryable, unlike an auth or validation error. */
|
|
30
|
+
class SyncTransportError extends Error {
|
|
31
|
+
constructor(message, status) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "SyncTransportError";
|
|
34
|
+
this.status = status;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.SyncTransportError = SyncTransportError;
|
|
38
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/sync/protocol.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEU,QAAA,gBAAgB,GAAG,CAAC,CAAC;AAgHlC,uFAAuF;AACvF,MAAa,aAAc,SAAQ,KAAK;IAGtC,YAAY,MAAc,EAAE,OAAe;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAG,eAAe,CAAC;QAIvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAPD,sCAOC;AAED,qFAAqF;AACrF,MAAa,kBAAmB,SAAQ,KAAK;IAG3C,YAAY,OAAe,EAAE,MAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAG,oBAAoB,CAAC;QAI5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAPD,gDAOC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "../storage/types.js";
|
|
2
|
+
import type { Mutation, QueuedMutation } from "./protocol.js";
|
|
3
|
+
/**
|
|
4
|
+
* The durable mutation queue.
|
|
5
|
+
*
|
|
6
|
+
* Stored as an ordinary collection through the `DatabaseAdapter`, not in a bespoke table, so every
|
|
7
|
+
* adapter (SQLite, IndexedDB, memory) gets persistence for free and the queue survives whatever the
|
|
8
|
+
* storage engine survives.
|
|
9
|
+
*
|
|
10
|
+
* Two reliability properties this file is responsible for:
|
|
11
|
+
*
|
|
12
|
+
* - **Nothing is lost to a crash.** Rows are written in the same call that persists the document
|
|
13
|
+
* change, before the caller's `await` resolves. If the process dies immediately after a write,
|
|
14
|
+
* the mutation is already on disk.
|
|
15
|
+
* - **Nothing is stuck after a crash.** A mutation marked `inflight` when the process died is
|
|
16
|
+
* indistinguishable from one still in transit, so `recover()` returns them all to `pending` on
|
|
17
|
+
* startup. Combined with server-side idempotency on `(clientId, mutationId)`, at-least-once
|
|
18
|
+
* delivery becomes effectively-once.
|
|
19
|
+
*/
|
|
20
|
+
export declare const QUEUE_COLLECTION = "__anchor_mutations";
|
|
21
|
+
export declare class MutationQueue {
|
|
22
|
+
private readonly adapter;
|
|
23
|
+
private readonly clientId;
|
|
24
|
+
private seq;
|
|
25
|
+
private ready;
|
|
26
|
+
constructor(adapter: DatabaseAdapter, clientId: string);
|
|
27
|
+
private init;
|
|
28
|
+
/** Append mutations. Ordering is by `seq`, which is monotonic and persisted. */
|
|
29
|
+
enqueue(mutations: Array<Omit<Mutation, "mutationId" | "clientId" | "createdAt"> & Partial<Mutation>>): Promise<QueuedMutation[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Return `inflight` mutations to `pending`.
|
|
32
|
+
*
|
|
33
|
+
* Called on startup. A mutation that was in flight when the process died may or may not have
|
|
34
|
+
* reached the server — we cannot tell. Re-sending is safe because the server deduplicates on
|
|
35
|
+
* `(clientId, mutationId)`; *not* re-sending would silently lose the change.
|
|
36
|
+
*/
|
|
37
|
+
recover(): Promise<number>;
|
|
38
|
+
/**
|
|
39
|
+
* Next batch to push, in `seq` order.
|
|
40
|
+
*
|
|
41
|
+
* Skips any document that already has an earlier failed mutation: applying a later change to a
|
|
42
|
+
* document whose earlier change never landed would corrupt it. Per-document ordering is a
|
|
43
|
+
* correctness requirement, not an optimisation.
|
|
44
|
+
*/
|
|
45
|
+
take(limit: number, now?: number): Promise<QueuedMutation[]>;
|
|
46
|
+
markInflight(mutations: QueuedMutation[]): Promise<void>;
|
|
47
|
+
remove(mutationIds: string[]): Promise<void>;
|
|
48
|
+
update(mutations: QueuedMutation[]): Promise<void>;
|
|
49
|
+
/** Exponential backoff with jitter, so a fleet reconnecting at once does not stampede. */
|
|
50
|
+
scheduleRetry(mutation: QueuedMutation, error: string, baseDelayMs?: number, maxDelayMs?: number): Promise<void>;
|
|
51
|
+
/** Park a mutation that retrying cannot fix (duplicate key, validation, conflict loop). */
|
|
52
|
+
markFatal(mutation: QueuedMutation, error: string): Promise<void>;
|
|
53
|
+
list(filter?: {
|
|
54
|
+
status?: QueuedMutation["status"];
|
|
55
|
+
collection?: string;
|
|
56
|
+
}): Promise<QueuedMutation[]>;
|
|
57
|
+
get(mutationId: string): Promise<QueuedMutation | null>;
|
|
58
|
+
counts(): Promise<{
|
|
59
|
+
pending: number;
|
|
60
|
+
inflight: number;
|
|
61
|
+
failed: number;
|
|
62
|
+
total: number;
|
|
63
|
+
}>;
|
|
64
|
+
/** Developer/debug action surfaced by Lens: retry a parked mutation. */
|
|
65
|
+
retry(mutationId: string): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Drop all backoff timers.
|
|
68
|
+
*
|
|
69
|
+
* Backoff is right for *automatic* retries — it stops a fleet stampeding a recovering server.
|
|
70
|
+
* But when the app knows connectivity just returned, or the user explicitly pulled to refresh,
|
|
71
|
+
* waiting out a timer computed during the outage is pointless and feels broken. This is the
|
|
72
|
+
* escape hatch for those cases; the engine calls it for user-initiated syncs only.
|
|
73
|
+
*/
|
|
74
|
+
clearBackoff(): Promise<number>;
|
|
75
|
+
clear(): Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../src/sync/queue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAa,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AAGrD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,KAAK,CAA8B;gBAE/B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM;YAKxC,IAAI;IASlB,gFAAgF;IAC1E,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAmCvI;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAShC;;;;;;OAMG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA6BhE,YAAY,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,0FAA0F;IACpF,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,SAAO,EAAE,UAAU,SAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASrH,2FAA2F;IACrF,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjE,IAAI,CAAC,MAAM,GAAE;QAAE,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAYxG,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAMvD,MAAM,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAU7F,wEAAwE;IAClE,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYjD;;;;;;;OAOG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAY/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MutationQueue = exports.QUEUE_COLLECTION = void 0;
|
|
4
|
+
const uuid_ts_1 = require("../core/uuid.js");
|
|
5
|
+
/**
|
|
6
|
+
* The durable mutation queue.
|
|
7
|
+
*
|
|
8
|
+
* Stored as an ordinary collection through the `DatabaseAdapter`, not in a bespoke table, so every
|
|
9
|
+
* adapter (SQLite, IndexedDB, memory) gets persistence for free and the queue survives whatever the
|
|
10
|
+
* storage engine survives.
|
|
11
|
+
*
|
|
12
|
+
* Two reliability properties this file is responsible for:
|
|
13
|
+
*
|
|
14
|
+
* - **Nothing is lost to a crash.** Rows are written in the same call that persists the document
|
|
15
|
+
* change, before the caller's `await` resolves. If the process dies immediately after a write,
|
|
16
|
+
* the mutation is already on disk.
|
|
17
|
+
* - **Nothing is stuck after a crash.** A mutation marked `inflight` when the process died is
|
|
18
|
+
* indistinguishable from one still in transit, so `recover()` returns them all to `pending` on
|
|
19
|
+
* startup. Combined with server-side idempotency on `(clientId, mutationId)`, at-least-once
|
|
20
|
+
* delivery becomes effectively-once.
|
|
21
|
+
*/
|
|
22
|
+
exports.QUEUE_COLLECTION = "__anchor_mutations";
|
|
23
|
+
const SEQ_STATE_KEY = "anchor:queue:seq";
|
|
24
|
+
class MutationQueue {
|
|
25
|
+
constructor(adapter, clientId) {
|
|
26
|
+
this.seq = 0;
|
|
27
|
+
this.ready = null;
|
|
28
|
+
this.adapter = adapter;
|
|
29
|
+
this.clientId = clientId;
|
|
30
|
+
}
|
|
31
|
+
async init() {
|
|
32
|
+
this.ready ??= (async () => {
|
|
33
|
+
await this.adapter.ensureCollection(exports.QUEUE_COLLECTION);
|
|
34
|
+
const stored = await this.adapter.getState(SEQ_STATE_KEY);
|
|
35
|
+
this.seq = stored ? Number(stored) : 0;
|
|
36
|
+
})();
|
|
37
|
+
return this.ready;
|
|
38
|
+
}
|
|
39
|
+
/** Append mutations. Ordering is by `seq`, which is monotonic and persisted. */
|
|
40
|
+
async enqueue(mutations) {
|
|
41
|
+
await this.init();
|
|
42
|
+
const now = new Date().toISOString();
|
|
43
|
+
const rows = [];
|
|
44
|
+
const queued = [];
|
|
45
|
+
for (const m of mutations) {
|
|
46
|
+
this.seq += 1;
|
|
47
|
+
const record = {
|
|
48
|
+
mutationId: m.mutationId ?? (0, uuid_ts_1.uuidv7)(),
|
|
49
|
+
collection: m.collection,
|
|
50
|
+
documentId: m.documentId,
|
|
51
|
+
operation: m.operation,
|
|
52
|
+
payload: m.payload ?? null,
|
|
53
|
+
clientId: m.clientId ?? this.clientId,
|
|
54
|
+
baseVersion: m.baseVersion ?? 0,
|
|
55
|
+
hlc: m.hlc,
|
|
56
|
+
createdAt: m.createdAt ?? now,
|
|
57
|
+
seq: this.seq,
|
|
58
|
+
status: "pending",
|
|
59
|
+
attempts: 0,
|
|
60
|
+
conflictAttempts: 0,
|
|
61
|
+
...(m.resolvedFrom ? { resolvedFrom: m.resolvedFrom } : {}),
|
|
62
|
+
};
|
|
63
|
+
queued.push(record);
|
|
64
|
+
rows.push(toRow(record));
|
|
65
|
+
}
|
|
66
|
+
await this.adapter.write(rows.map((row) => ({ type: "insert", collection: exports.QUEUE_COLLECTION, _id: row.doc._id, row })));
|
|
67
|
+
await this.adapter.setState(SEQ_STATE_KEY, String(this.seq));
|
|
68
|
+
return queued;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Return `inflight` mutations to `pending`.
|
|
72
|
+
*
|
|
73
|
+
* Called on startup. A mutation that was in flight when the process died may or may not have
|
|
74
|
+
* reached the server — we cannot tell. Re-sending is safe because the server deduplicates on
|
|
75
|
+
* `(clientId, mutationId)`; *not* re-sending would silently lose the change.
|
|
76
|
+
*/
|
|
77
|
+
async recover() {
|
|
78
|
+
await this.init();
|
|
79
|
+
const inflight = await this.list({ status: "inflight" });
|
|
80
|
+
if (inflight.length === 0)
|
|
81
|
+
return 0;
|
|
82
|
+
for (const m of inflight)
|
|
83
|
+
m.status = "pending";
|
|
84
|
+
await this.update(inflight);
|
|
85
|
+
return inflight.length;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Next batch to push, in `seq` order.
|
|
89
|
+
*
|
|
90
|
+
* Skips any document that already has an earlier failed mutation: applying a later change to a
|
|
91
|
+
* document whose earlier change never landed would corrupt it. Per-document ordering is a
|
|
92
|
+
* correctness requirement, not an optimisation.
|
|
93
|
+
*/
|
|
94
|
+
async take(limit, now = Date.now()) {
|
|
95
|
+
await this.init();
|
|
96
|
+
const all = (await this.list({})).sort((a, b) => a.seq - b.seq);
|
|
97
|
+
const blocked = new Set();
|
|
98
|
+
const batch = [];
|
|
99
|
+
for (const m of all) {
|
|
100
|
+
const key = `${m.collection}/${m.documentId}`;
|
|
101
|
+
if (m.fatal || m.status === "failed") {
|
|
102
|
+
blocked.add(key);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (blocked.has(key))
|
|
106
|
+
continue;
|
|
107
|
+
if (m.status === "inflight") {
|
|
108
|
+
blocked.add(key);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (m.nextAttemptAt && Date.parse(m.nextAttemptAt) > now) {
|
|
112
|
+
blocked.add(key); // backing off: hold later changes to the same document too
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
batch.push(m);
|
|
116
|
+
blocked.add(key); // one in-flight mutation per document at a time
|
|
117
|
+
if (batch.length >= limit)
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
return batch;
|
|
121
|
+
}
|
|
122
|
+
async markInflight(mutations) {
|
|
123
|
+
for (const m of mutations) {
|
|
124
|
+
m.status = "inflight";
|
|
125
|
+
m.attempts += 1;
|
|
126
|
+
}
|
|
127
|
+
await this.update(mutations);
|
|
128
|
+
}
|
|
129
|
+
async remove(mutationIds) {
|
|
130
|
+
await this.init();
|
|
131
|
+
if (mutationIds.length === 0)
|
|
132
|
+
return;
|
|
133
|
+
await this.adapter.write(mutationIds.map((id) => ({ type: "hardDelete", collection: exports.QUEUE_COLLECTION, _id: id })));
|
|
134
|
+
}
|
|
135
|
+
async update(mutations) {
|
|
136
|
+
await this.init();
|
|
137
|
+
if (mutations.length === 0)
|
|
138
|
+
return;
|
|
139
|
+
await this.adapter.write(mutations.map((m) => {
|
|
140
|
+
const row = toRow(m);
|
|
141
|
+
return { type: "update", collection: exports.QUEUE_COLLECTION, _id: row.doc._id, row };
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
/** Exponential backoff with jitter, so a fleet reconnecting at once does not stampede. */
|
|
145
|
+
async scheduleRetry(mutation, error, baseDelayMs = 1000, maxDelayMs = 300_000) {
|
|
146
|
+
const exponential = Math.min(maxDelayMs, baseDelayMs * 2 ** Math.min(mutation.attempts, 10));
|
|
147
|
+
const jitter = Math.random() * exponential * 0.3;
|
|
148
|
+
mutation.status = "pending";
|
|
149
|
+
mutation.lastError = error;
|
|
150
|
+
mutation.nextAttemptAt = new Date(Date.now() + exponential + jitter).toISOString();
|
|
151
|
+
await this.update([mutation]);
|
|
152
|
+
}
|
|
153
|
+
/** Park a mutation that retrying cannot fix (duplicate key, validation, conflict loop). */
|
|
154
|
+
async markFatal(mutation, error) {
|
|
155
|
+
mutation.status = "failed";
|
|
156
|
+
mutation.fatal = true;
|
|
157
|
+
mutation.lastError = error;
|
|
158
|
+
await this.update([mutation]);
|
|
159
|
+
}
|
|
160
|
+
async list(filter = {}) {
|
|
161
|
+
await this.init();
|
|
162
|
+
const out = [];
|
|
163
|
+
for await (const row of this.adapter.scan(exports.QUEUE_COLLECTION)) {
|
|
164
|
+
const m = fromRow(row);
|
|
165
|
+
if (filter.status && m.status !== filter.status)
|
|
166
|
+
continue;
|
|
167
|
+
if (filter.collection && m.collection !== filter.collection)
|
|
168
|
+
continue;
|
|
169
|
+
out.push(m);
|
|
170
|
+
}
|
|
171
|
+
return out.sort((a, b) => a.seq - b.seq);
|
|
172
|
+
}
|
|
173
|
+
async get(mutationId) {
|
|
174
|
+
await this.init();
|
|
175
|
+
const row = await this.adapter.get(exports.QUEUE_COLLECTION, mutationId);
|
|
176
|
+
return row ? fromRow(row) : null;
|
|
177
|
+
}
|
|
178
|
+
async counts() {
|
|
179
|
+
const all = await this.list({});
|
|
180
|
+
return {
|
|
181
|
+
pending: all.filter((m) => m.status === "pending").length,
|
|
182
|
+
inflight: all.filter((m) => m.status === "inflight").length,
|
|
183
|
+
failed: all.filter((m) => m.status === "failed").length,
|
|
184
|
+
total: all.length,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/** Developer/debug action surfaced by Lens: retry a parked mutation. */
|
|
188
|
+
async retry(mutationId) {
|
|
189
|
+
const m = await this.get(mutationId);
|
|
190
|
+
if (!m)
|
|
191
|
+
return false;
|
|
192
|
+
m.status = "pending";
|
|
193
|
+
m.fatal = false;
|
|
194
|
+
m.attempts = 0;
|
|
195
|
+
delete m.nextAttemptAt;
|
|
196
|
+
delete m.lastError;
|
|
197
|
+
await this.update([m]);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Drop all backoff timers.
|
|
202
|
+
*
|
|
203
|
+
* Backoff is right for *automatic* retries — it stops a fleet stampeding a recovering server.
|
|
204
|
+
* But when the app knows connectivity just returned, or the user explicitly pulled to refresh,
|
|
205
|
+
* waiting out a timer computed during the outage is pointless and feels broken. This is the
|
|
206
|
+
* escape hatch for those cases; the engine calls it for user-initiated syncs only.
|
|
207
|
+
*/
|
|
208
|
+
async clearBackoff() {
|
|
209
|
+
await this.init();
|
|
210
|
+
const waiting = (await this.list({})).filter((m) => m.nextAttemptAt && !m.fatal);
|
|
211
|
+
if (waiting.length === 0)
|
|
212
|
+
return 0;
|
|
213
|
+
for (const m of waiting) {
|
|
214
|
+
delete m.nextAttemptAt;
|
|
215
|
+
m.status = m.status === "failed" ? "failed" : "pending";
|
|
216
|
+
}
|
|
217
|
+
await this.update(waiting);
|
|
218
|
+
return waiting.length;
|
|
219
|
+
}
|
|
220
|
+
async clear() {
|
|
221
|
+
const all = await this.list({});
|
|
222
|
+
await this.remove(all.map((m) => m.mutationId));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.MutationQueue = MutationQueue;
|
|
226
|
+
function toRow(m) {
|
|
227
|
+
return {
|
|
228
|
+
doc: { ...m, _id: m.mutationId },
|
|
229
|
+
meta: {
|
|
230
|
+
version: 0,
|
|
231
|
+
hlc: m.hlc,
|
|
232
|
+
dirty: false,
|
|
233
|
+
// The queue is local bookkeeping and must never itself be synced.
|
|
234
|
+
deleted: false,
|
|
235
|
+
createdAt: m.createdAt,
|
|
236
|
+
updatedAt: new Date().toISOString(),
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function fromRow(row) {
|
|
241
|
+
const { _id, ...rest } = row.doc;
|
|
242
|
+
void _id;
|
|
243
|
+
return rest;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../../src/sync/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type PullRequest, type PullResponse, type PushRequest, type PushResponse, type SyncAdapter } from "../protocol.js";
|
|
2
|
+
/**
|
|
3
|
+
* A complete, correct implementation of the server half of the sync protocol, backed by memory.
|
|
4
|
+
*
|
|
5
|
+
* This is the reference: the Express, NestJS and Next.js adapters all delegate to the same logic
|
|
6
|
+
* over a pluggable store, so what the tests exercise here is what a real backend runs. It is also
|
|
7
|
+
* the peer the E2E demo syncs against, which is what lets the offline -> conflict -> resolution
|
|
8
|
+
* lifecycle actually execute rather than be described.
|
|
9
|
+
*
|
|
10
|
+
* The four server-side responsibilities:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Version counters.** Each document carries a monotonically increasing integer. This is the
|
|
13
|
+
* basis of conflict detection: a push whose `baseVersion` no longer matches has been overtaken.
|
|
14
|
+
* 2. **Authoritative timestamps.** `serverTime` on every response lets clients measure and correct
|
|
15
|
+
* their own clock skew instead of trusting the device.
|
|
16
|
+
* 3. **A global change sequence.** Pull cursors are positions in this sequence, which is what makes
|
|
17
|
+
* incremental sync resumable after a partial transfer.
|
|
18
|
+
* 4. **Idempotency.** `(clientId, mutationId)` verdicts are memoised, so a retry after a timeout
|
|
19
|
+
* replays the original result rather than applying the write a second time.
|
|
20
|
+
*/
|
|
21
|
+
export interface ServerDocument {
|
|
22
|
+
_id: string;
|
|
23
|
+
collection: string;
|
|
24
|
+
document: Record<string, unknown>;
|
|
25
|
+
version: number;
|
|
26
|
+
deleted: boolean;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
hlc: string;
|
|
29
|
+
seq: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ServerUniqueIndex {
|
|
32
|
+
collection: string;
|
|
33
|
+
field: string;
|
|
34
|
+
}
|
|
35
|
+
export interface MemorySyncServerOptions {
|
|
36
|
+
/** Unique constraints the server enforces, mirroring a real database's indexes. */
|
|
37
|
+
uniqueIndexes?: ServerUniqueIndex[];
|
|
38
|
+
/** Fixed clock for deterministic tests. */
|
|
39
|
+
now?: () => number;
|
|
40
|
+
}
|
|
41
|
+
export declare class MemorySyncServer implements SyncAdapter {
|
|
42
|
+
readonly name = "memory-server";
|
|
43
|
+
private readonly docs;
|
|
44
|
+
private readonly processed;
|
|
45
|
+
private readonly uniqueIndexes;
|
|
46
|
+
private readonly now;
|
|
47
|
+
private seq;
|
|
48
|
+
private hlcCounter;
|
|
49
|
+
/** Test hooks: force failures to exercise the client's reliability paths. */
|
|
50
|
+
failNextPush: Error | null;
|
|
51
|
+
failNextPull: Error | null;
|
|
52
|
+
pushCallCount: number;
|
|
53
|
+
constructor(options?: MemorySyncServerOptions);
|
|
54
|
+
push(request: PushRequest): Promise<PushResponse>;
|
|
55
|
+
pull(request: PullRequest): Promise<PullResponse>;
|
|
56
|
+
private applyChange;
|
|
57
|
+
private decide;
|
|
58
|
+
private nextHlc;
|
|
59
|
+
/** Simulate another device (or a server-side process) editing a document. */
|
|
60
|
+
serverEdit(collection: string, documentId: string, changes: Record<string, unknown>): ServerDocument;
|
|
61
|
+
get(collection: string, documentId: string): ServerDocument | undefined;
|
|
62
|
+
all(collection?: string): ServerDocument[];
|
|
63
|
+
reset(): void;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=memory-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-server.d.ts","sourceRoot":"","sources":["../../../../src/sync/server/memory-server.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EAEjB,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,mFAAmF;IACnF,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACpC,2CAA2C;IAC3C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,mBAAmB;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqC;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,UAAU,CAAK;IAEvB,6EAA6E;IAC7E,YAAY,EAAE,KAAK,GAAG,IAAI,CAAQ;IAClC,YAAY,EAAE,KAAK,GAAG,IAAI,CAAQ;IAClC,aAAa,SAAK;gBAEN,OAAO,GAAE,uBAA4B;IAO3C,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAqBjD,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAsCvD,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,MAAM;IAiFd,OAAO,CAAC,OAAO;IAOf,6EAA6E;IAC7E,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc;IAkBpG,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIvE,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;IAI1C,KAAK,IAAI,IAAI;CAMd"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemorySyncServer = void 0;
|
|
4
|
+
const errors_ts_1 = require("../../core/errors.js");
|
|
5
|
+
const protocol_ts_1 = require("../protocol.js");
|
|
6
|
+
class MemorySyncServer {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.name = "memory-server";
|
|
9
|
+
this.docs = new Map();
|
|
10
|
+
this.processed = new Map();
|
|
11
|
+
this.seq = 0;
|
|
12
|
+
this.hlcCounter = 0;
|
|
13
|
+
/** Test hooks: force failures to exercise the client's reliability paths. */
|
|
14
|
+
this.failNextPush = null;
|
|
15
|
+
this.failNextPull = null;
|
|
16
|
+
this.pushCallCount = 0;
|
|
17
|
+
this.uniqueIndexes = options.uniqueIndexes ?? [];
|
|
18
|
+
this.now = options.now ?? (() => Date.now());
|
|
19
|
+
}
|
|
20
|
+
// ---- protocol ------------------------------------------------------------
|
|
21
|
+
async push(request) {
|
|
22
|
+
this.pushCallCount++;
|
|
23
|
+
if (this.failNextPush) {
|
|
24
|
+
const err = this.failNextPush;
|
|
25
|
+
this.failNextPush = null;
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const change of request.changes) {
|
|
30
|
+
results.push(this.applyChange(request.clientId, change));
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
protocolVersion: protocol_ts_1.PROTOCOL_VERSION,
|
|
34
|
+
serverTime: new Date(this.now()).toISOString(),
|
|
35
|
+
serverHlc: this.nextHlc("server"),
|
|
36
|
+
results,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async pull(request) {
|
|
40
|
+
if (this.failNextPull) {
|
|
41
|
+
const err = this.failNextPull;
|
|
42
|
+
this.failNextPull = null;
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
const after = request.cursor ? Number(request.cursor) : 0;
|
|
46
|
+
const limit = request.limit ?? 100;
|
|
47
|
+
const ordered = [...this.docs.values()]
|
|
48
|
+
.filter((d) => d.seq > after)
|
|
49
|
+
.sort((a, b) => a.seq - b.seq);
|
|
50
|
+
const page = ordered.slice(0, limit);
|
|
51
|
+
const changes = page.map((d) => ({
|
|
52
|
+
collection: d.collection,
|
|
53
|
+
documentId: d._id,
|
|
54
|
+
document: d.deleted ? null : d.document,
|
|
55
|
+
version: d.version,
|
|
56
|
+
deleted: d.deleted,
|
|
57
|
+
updatedAt: d.updatedAt,
|
|
58
|
+
hlc: d.hlc,
|
|
59
|
+
}));
|
|
60
|
+
const last = page[page.length - 1];
|
|
61
|
+
return {
|
|
62
|
+
protocolVersion: protocol_ts_1.PROTOCOL_VERSION,
|
|
63
|
+
serverTime: new Date(this.now()).toISOString(),
|
|
64
|
+
serverHlc: this.nextHlc("server"),
|
|
65
|
+
changes,
|
|
66
|
+
nextCursor: last ? String(last.seq) : (request.cursor ?? null),
|
|
67
|
+
hasMore: ordered.length > page.length,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ---- core logic ----------------------------------------------------------
|
|
71
|
+
applyChange(clientId, change) {
|
|
72
|
+
// Idempotency: replay the original verdict for a mutation we have already decided.
|
|
73
|
+
const key = `${clientId}:${change.mutationId}`;
|
|
74
|
+
const memoised = this.processed.get(key);
|
|
75
|
+
if (memoised)
|
|
76
|
+
return memoised;
|
|
77
|
+
const docKey = `${change.collection}/${change.documentId}`;
|
|
78
|
+
const existing = this.docs.get(docKey);
|
|
79
|
+
const result = this.decide(change, existing, docKey);
|
|
80
|
+
this.processed.set(key, result);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
decide(change, existing, docKey) {
|
|
84
|
+
const currentVersion = existing?.version ?? 0;
|
|
85
|
+
// Optimistic concurrency: the client edited a version the server has since moved past.
|
|
86
|
+
if (currentVersion !== change.baseVersion) {
|
|
87
|
+
return {
|
|
88
|
+
mutationId: change.mutationId,
|
|
89
|
+
status: "conflict",
|
|
90
|
+
version: currentVersion,
|
|
91
|
+
document: existing && !existing.deleted ? existing.document : null,
|
|
92
|
+
hlc: existing?.hlc ?? "",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (change.operation === "delete") {
|
|
96
|
+
if (existing) {
|
|
97
|
+
existing.deleted = true;
|
|
98
|
+
existing.version += 1;
|
|
99
|
+
existing.updatedAt = new Date(this.now()).toISOString();
|
|
100
|
+
existing.seq = ++this.seq;
|
|
101
|
+
existing.hlc = this.nextHlc("server");
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
mutationId: change.mutationId,
|
|
105
|
+
status: "accepted",
|
|
106
|
+
version: existing?.version ?? currentVersion + 1,
|
|
107
|
+
document: null,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const payload = (change.payload ?? {});
|
|
111
|
+
// Unique constraint check — the case two offline devices cannot detect themselves.
|
|
112
|
+
for (const index of this.uniqueIndexes) {
|
|
113
|
+
if (index.collection !== change.collection)
|
|
114
|
+
continue;
|
|
115
|
+
const value = payload[index.field];
|
|
116
|
+
if (value === undefined)
|
|
117
|
+
continue;
|
|
118
|
+
for (const [otherKey, other] of this.docs) {
|
|
119
|
+
if (otherKey === docKey || other.deleted)
|
|
120
|
+
continue;
|
|
121
|
+
if (other.collection !== change.collection)
|
|
122
|
+
continue;
|
|
123
|
+
if (other.document[index.field] === value) {
|
|
124
|
+
return {
|
|
125
|
+
mutationId: change.mutationId,
|
|
126
|
+
status: "rejected",
|
|
127
|
+
code: errors_ts_1.DUPLICATE_KEY_CODE,
|
|
128
|
+
reason: `E11000 duplicate key error collection: ${change.collection} ` +
|
|
129
|
+
`index: ${index.field}_1 dup key: { ${index.field}: "${String(value)}" }`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const version = currentVersion + 1;
|
|
135
|
+
const updatedAt = new Date(this.now()).toISOString();
|
|
136
|
+
const hlc = this.nextHlc("server");
|
|
137
|
+
const stored = {
|
|
138
|
+
_id: change.documentId,
|
|
139
|
+
collection: change.collection,
|
|
140
|
+
document: { ...payload, _id: change.documentId, updatedAt },
|
|
141
|
+
version,
|
|
142
|
+
deleted: false,
|
|
143
|
+
updatedAt,
|
|
144
|
+
hlc,
|
|
145
|
+
seq: ++this.seq,
|
|
146
|
+
};
|
|
147
|
+
this.docs.set(docKey, stored);
|
|
148
|
+
return {
|
|
149
|
+
mutationId: change.mutationId,
|
|
150
|
+
status: "accepted",
|
|
151
|
+
version,
|
|
152
|
+
document: stored.document,
|
|
153
|
+
hlc,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
nextHlc(node) {
|
|
157
|
+
this.hlcCounter += 1;
|
|
158
|
+
return `${String(this.now()).padStart(15, "0")}-${String(this.hlcCounter).padStart(5, "0")}-${node}`;
|
|
159
|
+
}
|
|
160
|
+
// ---- test/demo helpers ---------------------------------------------------
|
|
161
|
+
/** Simulate another device (or a server-side process) editing a document. */
|
|
162
|
+
serverEdit(collection, documentId, changes) {
|
|
163
|
+
const key = `${collection}/${documentId}`;
|
|
164
|
+
const existing = this.docs.get(key);
|
|
165
|
+
const updatedAt = new Date(this.now()).toISOString();
|
|
166
|
+
const next = {
|
|
167
|
+
_id: documentId,
|
|
168
|
+
collection,
|
|
169
|
+
document: { ...(existing?.document ?? { _id: documentId }), ...changes, _id: documentId, updatedAt },
|
|
170
|
+
version: (existing?.version ?? 0) + 1,
|
|
171
|
+
deleted: false,
|
|
172
|
+
updatedAt,
|
|
173
|
+
hlc: this.nextHlc("server"),
|
|
174
|
+
seq: ++this.seq,
|
|
175
|
+
};
|
|
176
|
+
this.docs.set(key, next);
|
|
177
|
+
return next;
|
|
178
|
+
}
|
|
179
|
+
get(collection, documentId) {
|
|
180
|
+
return this.docs.get(`${collection}/${documentId}`);
|
|
181
|
+
}
|
|
182
|
+
all(collection) {
|
|
183
|
+
return [...this.docs.values()].filter((d) => !collection || d.collection === collection);
|
|
184
|
+
}
|
|
185
|
+
reset() {
|
|
186
|
+
this.docs.clear();
|
|
187
|
+
this.processed.clear();
|
|
188
|
+
this.seq = 0;
|
|
189
|
+
this.hlcCounter = 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
exports.MemorySyncServer = MemorySyncServer;
|
|
193
|
+
//# sourceMappingURL=memory-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-server.js","sourceRoot":"","sources":["../../../../src/sync/server/memory-server.ts"],"names":[],"mappings":"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"}
|