@opendatalabs/personal-server-ts-core 1.34.2 → 1.35.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/dist/additions/durable.d.ts +32 -2
- package/dist/additions/durable.d.ts.map +1 -1
- package/dist/additions/durable.js +237 -88
- package/dist/additions/durable.js.map +1 -1
- package/dist/additions/version-inventory.d.ts +4 -0
- package/dist/additions/version-inventory.d.ts.map +1 -1
- package/dist/additions/version-inventory.js +11 -1
- package/dist/additions/version-inventory.js.map +1 -1
- package/dist/api/index.d.ts +18 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +172 -4
- package/dist/api/index.js.map +1 -1
- package/dist/api/oura-collection-requirements.d.ts +16 -0
- package/dist/api/oura-collection-requirements.d.ts.map +1 -0
- package/dist/api/oura-collection-requirements.js +70 -0
- package/dist/api/oura-collection-requirements.js.map +1 -0
- package/dist/api/scope-upload-batches.d.ts +18 -0
- package/dist/api/scope-upload-batches.d.ts.map +1 -0
- package/dist/api/scope-upload-batches.js +71 -0
- package/dist/api/scope-upload-batches.js.map +1 -0
- package/dist/api/scope-uploads.d.ts +112 -0
- package/dist/api/scope-uploads.d.ts.map +1 -0
- package/dist/api/scope-uploads.js +369 -0
- package/dist/api/scope-uploads.js.map +1 -0
- package/dist/client.d.ts +70 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/contracts/data.d.ts +8 -0
- package/dist/contracts/data.d.ts.map +1 -1
- package/dist/contracts/data.js +31 -1
- package/dist/contracts/data.js.map +1 -1
- package/dist/contracts/grants.d.ts.map +1 -1
- package/dist/contracts/grants.js +3 -0
- package/dist/contracts/grants.js.map +1 -1
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +3 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/oura-collection-requirements.d.ts +17 -0
- package/dist/contracts/oura-collection-requirements.d.ts.map +1 -0
- package/dist/contracts/oura-collection-requirements.js +49 -0
- package/dist/contracts/oura-collection-requirements.js.map +1 -0
- package/dist/legacy-projection/bindings.d.ts +1 -7
- package/dist/legacy-projection/bindings.d.ts.map +1 -1
- package/dist/legacy-projection/bindings.js +162 -28
- package/dist/legacy-projection/bindings.js.map +1 -1
- package/dist/legacy-projection/index.d.ts +6 -5
- package/dist/legacy-projection/index.d.ts.map +1 -1
- package/dist/legacy-projection/index.js +9 -21
- package/dist/legacy-projection/index.js.map +1 -1
- package/dist/legacy-projection/oura-browser-bindings.d.ts +2 -0
- package/dist/legacy-projection/oura-browser-bindings.d.ts.map +1 -1
- package/dist/legacy-projection/oura-browser-bindings.js +2 -0
- package/dist/legacy-projection/oura-browser-bindings.js.map +1 -1
- package/dist/legacy-projection/strava-browser-bindings.d.ts +3 -0
- package/dist/legacy-projection/strava-browser-bindings.d.ts.map +1 -0
- package/dist/legacy-projection/strava-browser-bindings.js +32 -0
- package/dist/legacy-projection/strava-browser-bindings.js.map +1 -0
- package/dist/legacy-projection/types.d.ts +44 -12
- package/dist/legacy-projection/types.d.ts.map +1 -1
- package/dist/mcp/connection-api.d.ts +11 -1
- package/dist/mcp/connection-api.d.ts.map +1 -1
- package/dist/mcp/connection-api.js +94 -9
- package/dist/mcp/connection-api.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +19 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/store.d.ts +10 -1
- package/dist/mcp/store.d.ts.map +1 -1
- package/dist/mcp/store.js +51 -0
- package/dist/mcp/store.js.map +1 -1
- package/dist/mcp/tools.d.ts +52 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +395 -11
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts +36 -2
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js +12 -0
- package/dist/mcp/types.js.map +1 -1
- package/dist/mcp/write-client.d.ts +81 -0
- package/dist/mcp/write-client.d.ts.map +1 -0
- package/dist/mcp/write-client.js +140 -0
- package/dist/mcp/write-client.js.map +1 -0
- package/dist/oura/history-policy.d.ts +12 -0
- package/dist/oura/history-policy.d.ts.map +1 -0
- package/dist/oura/history-policy.js +54 -0
- package/dist/oura/history-policy.js.map +1 -0
- package/dist/oura/index.d.ts +51 -0
- package/dist/oura/index.d.ts.map +1 -0
- package/dist/oura/index.js +315 -0
- package/dist/oura/index.js.map +1 -0
- package/dist/pdpp/approval.d.ts +1 -1
- package/dist/pdpp/approval.d.ts.map +1 -1
- package/dist/pdpp/approval.js +29 -10
- package/dist/pdpp/approval.js.map +1 -1
- package/dist/pdpp/declaration-limits.d.ts +7 -0
- package/dist/pdpp/declaration-limits.d.ts.map +1 -0
- package/dist/pdpp/declaration-limits.js +7 -0
- package/dist/pdpp/declaration-limits.js.map +1 -0
- package/dist/pdpp/declaration.d.ts +2 -1
- package/dist/pdpp/declaration.d.ts.map +1 -1
- package/dist/pdpp/declaration.js +2 -1
- package/dist/pdpp/declaration.js.map +1 -1
- package/dist/pdpp/index.d.ts +3 -2
- package/dist/pdpp/index.d.ts.map +1 -1
- package/dist/pdpp/index.js +3 -2
- package/dist/pdpp/index.js.map +1 -1
- package/dist/pdpp/issuance.d.ts.map +1 -1
- package/dist/pdpp/issuance.js +6 -2
- package/dist/pdpp/issuance.js.map +1 -1
- package/dist/pdpp/resolve.d.ts +12 -1
- package/dist/pdpp/resolve.d.ts.map +1 -1
- package/dist/pdpp/resolve.js +156 -58
- package/dist/pdpp/resolve.js.map +1 -1
- package/dist/pdpp/selection.d.ts +30 -1
- package/dist/pdpp/selection.d.ts.map +1 -1
- package/dist/pdpp/selection.js +77 -26
- package/dist/pdpp/selection.js.map +1 -1
- package/dist/pdpp/time.d.ts +39 -0
- package/dist/pdpp/time.d.ts.map +1 -0
- package/dist/pdpp/time.js +173 -0
- package/dist/pdpp/time.js.map +1 -0
- package/dist/pdpp/tokens.d.ts.map +1 -1
- package/dist/pdpp/tokens.js +4 -2
- package/dist/pdpp/tokens.js.map +1 -1
- package/dist/pdpp/types.d.ts +18 -2
- package/dist/pdpp/types.d.ts.map +1 -1
- package/dist/pdpp/types.js +7 -0
- package/dist/pdpp/types.js.map +1 -1
- package/dist/policy/reserved-scopes.d.ts +7 -0
- package/dist/policy/reserved-scopes.d.ts.map +1 -1
- package/dist/policy/reserved-scopes.js +12 -1
- package/dist/policy/reserved-scopes.js.map +1 -1
- package/dist/ports/index.d.ts +85 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/pdpp-auth.d.ts +17 -27
- package/dist/ports/pdpp-auth.d.ts.map +1 -1
- package/dist/ports/pdpp-auth.js +14 -28
- package/dist/ports/pdpp-auth.js.map +1 -1
- package/dist/publication/publish.d.ts +96 -0
- package/dist/publication/publish.d.ts.map +1 -0
- package/dist/publication/publish.js +261 -0
- package/dist/publication/publish.js.map +1 -0
- package/dist/replication/completion.d.ts +20 -0
- package/dist/replication/completion.d.ts.map +1 -0
- package/dist/replication/completion.js +73 -0
- package/dist/replication/completion.js.map +1 -0
- package/dist/replication/coordinator-state.d.ts +29 -0
- package/dist/replication/coordinator-state.d.ts.map +1 -0
- package/dist/replication/coordinator-state.js +88 -0
- package/dist/replication/coordinator-state.js.map +1 -0
- package/dist/replication/coordinator-state.test-utils.d.ts +32 -0
- package/dist/replication/coordinator-state.test-utils.d.ts.map +1 -0
- package/dist/replication/coordinator-state.test-utils.js +113 -0
- package/dist/replication/coordinator-state.test-utils.js.map +1 -0
- package/dist/replication/coordinator.d.ts +264 -0
- package/dist/replication/coordinator.d.ts.map +1 -0
- package/dist/replication/coordinator.js +499 -0
- package/dist/replication/coordinator.js.map +1 -0
- package/dist/replication/copies.d.ts +126 -0
- package/dist/replication/copies.d.ts.map +1 -0
- package/dist/replication/copies.js +437 -0
- package/dist/replication/copies.js.map +1 -0
- package/dist/replication/copy-promotion.d.ts +132 -0
- package/dist/replication/copy-promotion.d.ts.map +1 -0
- package/dist/replication/copy-promotion.js +126 -0
- package/dist/replication/copy-promotion.js.map +1 -0
- package/dist/replication/door.d.ts +33 -0
- package/dist/replication/door.d.ts.map +1 -0
- package/dist/replication/door.js +10 -0
- package/dist/replication/door.js.map +1 -0
- package/dist/replication/dpv2.d.ts +141 -0
- package/dist/replication/dpv2.d.ts.map +1 -0
- package/dist/replication/dpv2.js +320 -0
- package/dist/replication/dpv2.js.map +1 -0
- package/dist/replication/effects.d.ts +68 -0
- package/dist/replication/effects.d.ts.map +1 -0
- package/dist/replication/effects.js +89 -0
- package/dist/replication/effects.js.map +1 -0
- package/dist/replication/engine.d.ts +378 -0
- package/dist/replication/engine.d.ts.map +1 -0
- package/dist/replication/engine.js +3197 -0
- package/dist/replication/engine.js.map +1 -0
- package/dist/replication/envelope.d.ts +481 -0
- package/dist/replication/envelope.d.ts.map +1 -0
- package/dist/replication/envelope.js +192 -0
- package/dist/replication/envelope.js.map +1 -0
- package/dist/replication/evidence.d.ts +118 -0
- package/dist/replication/evidence.d.ts.map +1 -0
- package/dist/replication/evidence.js +198 -0
- package/dist/replication/evidence.js.map +1 -0
- package/dist/replication/finality.d.ts +16 -0
- package/dist/replication/finality.d.ts.map +1 -0
- package/dist/replication/finality.js +11 -0
- package/dist/replication/finality.js.map +1 -0
- package/dist/replication/fixtures.d.ts +16 -0
- package/dist/replication/fixtures.d.ts.map +1 -0
- package/dist/replication/fixtures.js +47 -0
- package/dist/replication/fixtures.js.map +1 -0
- package/dist/replication/host-config.d.ts +52 -0
- package/dist/replication/host-config.d.ts.map +1 -0
- package/dist/replication/host-config.js +111 -0
- package/dist/replication/host-config.js.map +1 -0
- package/dist/replication/host-driver.d.ts +95 -0
- package/dist/replication/host-driver.d.ts.map +1 -0
- package/dist/replication/host-driver.js +202 -0
- package/dist/replication/host-driver.js.map +1 -0
- package/dist/replication/host-ports.d.ts +48 -0
- package/dist/replication/host-ports.d.ts.map +1 -0
- package/dist/replication/host-ports.js +69 -0
- package/dist/replication/host-ports.js.map +1 -0
- package/dist/replication/identity.d.ts +13 -0
- package/dist/replication/identity.d.ts.map +1 -0
- package/dist/replication/identity.js +22 -0
- package/dist/replication/identity.js.map +1 -0
- package/dist/replication/limits.d.ts +124 -0
- package/dist/replication/limits.d.ts.map +1 -0
- package/dist/replication/limits.js +182 -0
- package/dist/replication/limits.js.map +1 -0
- package/dist/replication/merge-plan.d.ts +92 -0
- package/dist/replication/merge-plan.d.ts.map +1 -0
- package/dist/replication/merge-plan.js +229 -0
- package/dist/replication/merge-plan.js.map +1 -0
- package/dist/replication/namespace.d.ts +4 -0
- package/dist/replication/namespace.d.ts.map +1 -0
- package/dist/replication/namespace.js +7 -0
- package/dist/replication/namespace.js.map +1 -0
- package/dist/replication/outcome.d.ts +178 -0
- package/dist/replication/outcome.d.ts.map +1 -0
- package/dist/replication/outcome.js +83 -0
- package/dist/replication/outcome.js.map +1 -0
- package/dist/replication/payload.d.ts +39 -0
- package/dist/replication/payload.d.ts.map +1 -0
- package/dist/replication/payload.js +137 -0
- package/dist/replication/payload.js.map +1 -0
- package/dist/replication/preparation.d.ts +42 -0
- package/dist/replication/preparation.d.ts.map +1 -0
- package/dist/replication/preparation.js +118 -0
- package/dist/replication/preparation.js.map +1 -0
- package/dist/replication/rebaseline.d.ts +33 -0
- package/dist/replication/rebaseline.d.ts.map +1 -0
- package/dist/replication/rebaseline.js +40 -0
- package/dist/replication/rebaseline.js.map +1 -0
- package/dist/replication/rebinding.d.ts +43 -0
- package/dist/replication/rebinding.d.ts.map +1 -0
- package/dist/replication/rebinding.js +52 -0
- package/dist/replication/rebinding.js.map +1 -0
- package/dist/replication/receive.d.ts +57 -0
- package/dist/replication/receive.d.ts.map +1 -0
- package/dist/replication/receive.js +114 -0
- package/dist/replication/receive.js.map +1 -0
- package/dist/replication/record-reducer.d.ts +16 -0
- package/dist/replication/record-reducer.d.ts.map +1 -0
- package/dist/replication/record-reducer.js +52 -0
- package/dist/replication/record-reducer.js.map +1 -0
- package/dist/replication/revision.d.ts +24 -0
- package/dist/replication/revision.d.ts.map +1 -0
- package/dist/replication/revision.js +35 -0
- package/dist/replication/revision.js.map +1 -0
- package/dist/replication/roster.d.ts +53 -0
- package/dist/replication/roster.d.ts.map +1 -0
- package/dist/replication/roster.js +115 -0
- package/dist/replication/roster.js.map +1 -0
- package/dist/replication/schedule.d.ts +73 -0
- package/dist/replication/schedule.d.ts.map +1 -0
- package/dist/replication/schedule.js +182 -0
- package/dist/replication/schedule.js.map +1 -0
- package/dist/replication/stream.d.ts +73 -0
- package/dist/replication/stream.d.ts.map +1 -0
- package/dist/replication/stream.js +542 -0
- package/dist/replication/stream.js.map +1 -0
- package/dist/replication/transport.d.ts +236 -0
- package/dist/replication/transport.d.ts.map +1 -0
- package/dist/replication/transport.js +440 -0
- package/dist/replication/transport.js.map +1 -0
- package/dist/replication/visibility-engine.d.ts +337 -0
- package/dist/replication/visibility-engine.d.ts.map +1 -0
- package/dist/replication/visibility-engine.js +602 -0
- package/dist/replication/visibility-engine.js.map +1 -0
- package/dist/replication/visibility-policy.d.ts +26 -0
- package/dist/replication/visibility-policy.d.ts.map +1 -0
- package/dist/replication/visibility-policy.js +33 -0
- package/dist/replication/visibility-policy.js.map +1 -0
- package/dist/replication/writer-identity-store.d.ts +100 -0
- package/dist/replication/writer-identity-store.d.ts.map +1 -0
- package/dist/replication/writer-identity-store.js +218 -0
- package/dist/replication/writer-identity-store.js.map +1 -0
- package/dist/replication/writer-identity.d.ts +252 -0
- package/dist/replication/writer-identity.d.ts.map +1 -0
- package/dist/replication/writer-identity.js +281 -0
- package/dist/replication/writer-identity.js.map +1 -0
- package/dist/replication/writer-identity.test-utils.d.ts +24 -0
- package/dist/replication/writer-identity.test-utils.d.ts.map +1 -0
- package/dist/replication/writer-identity.test-utils.js +86 -0
- package/dist/replication/writer-identity.test-utils.js.map +1 -0
- package/dist/schemas/server-config.d.ts +13 -0
- package/dist/schemas/server-config.d.ts.map +1 -1
- package/dist/schemas/server-config.js +24 -0
- package/dist/schemas/server-config.js.map +1 -1
- package/dist/storage/adapters/index.d.ts +3 -1
- package/dist/storage/adapters/index.d.ts.map +1 -1
- package/dist/storage/adapters/index.js +2 -0
- package/dist/storage/adapters/index.js.map +1 -1
- package/dist/storage/adapters/interface.d.ts +18 -1
- package/dist/storage/adapters/interface.d.ts.map +1 -1
- package/dist/storage/adapters/interface.js +13 -1
- package/dist/storage/adapters/interface.js.map +1 -1
- package/dist/storage/adapters/sdk.d.ts +2 -1
- package/dist/storage/adapters/sdk.d.ts.map +1 -1
- package/dist/storage/adapters/sdk.js +21 -3
- package/dist/storage/adapters/sdk.js.map +1 -1
- package/dist/storage/adapters/vana-audience.d.ts +17 -5
- package/dist/storage/adapters/vana-audience.d.ts.map +1 -1
- package/dist/storage/adapters/vana-audience.js +24 -9
- package/dist/storage/adapters/vana-audience.js.map +1 -1
- package/dist/storage/adapters/vana.d.ts +2 -2
- package/dist/storage/adapters/vana.d.ts.map +1 -1
- package/dist/storage/adapters/vana.js +30 -22
- package/dist/storage/adapters/vana.js.map +1 -1
- package/dist/storage/canonical-legacy-projection.d.ts +1 -1
- package/dist/storage/canonical-legacy-projection.d.ts.map +1 -1
- package/dist/storage/canonical-legacy-projection.js +13 -15
- package/dist/storage/canonical-legacy-projection.js.map +1 -1
- package/dist/storage/legacy-projection.d.ts.map +1 -1
- package/dist/storage/legacy-projection.js +16 -1
- package/dist/storage/legacy-projection.js.map +1 -1
- package/dist/storage/legacy-scope-coverage-exceptions.d.ts +5 -0
- package/dist/storage/legacy-scope-coverage-exceptions.d.ts.map +1 -1
- package/dist/storage/legacy-scope-coverage-exceptions.js +4 -0
- package/dist/storage/legacy-scope-coverage-exceptions.js.map +1 -1
- package/dist/storage/legacy-scope-coverage.d.ts.map +1 -1
- package/dist/storage/legacy-scope-coverage.js +14 -1
- package/dist/storage/legacy-scope-coverage.js.map +1 -1
- package/dist/storage/legacy-scope-entity-keys.d.ts +14 -1
- package/dist/storage/legacy-scope-entity-keys.d.ts.map +1 -1
- package/dist/storage/legacy-scope-entity-keys.js +18 -1
- package/dist/storage/legacy-scope-entity-keys.js.map +1 -1
- package/dist/storage/legacy-scope-view.d.ts +57 -5
- package/dist/storage/legacy-scope-view.d.ts.map +1 -1
- package/dist/storage/legacy-scope-view.js +644 -318
- package/dist/storage/legacy-scope-view.js.map +1 -1
- package/dist/storage/pdpp-records/cursor.d.ts +47 -2
- package/dist/storage/pdpp-records/cursor.d.ts.map +1 -1
- package/dist/storage/pdpp-records/cursor.js +7 -0
- package/dist/storage/pdpp-records/cursor.js.map +1 -1
- package/dist/storage/pdpp-records/enforcement.d.ts +3 -16
- package/dist/storage/pdpp-records/enforcement.d.ts.map +1 -1
- package/dist/storage/pdpp-records/enforcement.js +40 -13
- package/dist/storage/pdpp-records/enforcement.js.map +1 -1
- package/dist/storage/pdpp-records/index.d.ts +2 -0
- package/dist/storage/pdpp-records/index.d.ts.map +1 -1
- package/dist/storage/pdpp-records/index.js +1 -0
- package/dist/storage/pdpp-records/index.js.map +1 -1
- package/dist/storage/pdpp-records/interface.d.ts +8 -1
- package/dist/storage/pdpp-records/interface.d.ts.map +1 -1
- package/dist/storage/pdpp-records/list-page.d.ts +35 -0
- package/dist/storage/pdpp-records/list-page.d.ts.map +1 -0
- package/dist/storage/pdpp-records/list-page.js +106 -0
- package/dist/storage/pdpp-records/list-page.js.map +1 -0
- package/dist/storage/pdpp-records/memory-store.d.ts.map +1 -1
- package/dist/storage/pdpp-records/memory-store.js +95 -99
- package/dist/storage/pdpp-records/memory-store.js.map +1 -1
- package/dist/storage/pdpp-records/portable.d.ts +3 -0
- package/dist/storage/pdpp-records/portable.d.ts.map +1 -1
- package/dist/storage/pdpp-records/portable.js +3 -0
- package/dist/storage/pdpp-records/portable.js.map +1 -1
- package/dist/storage/pdpp-records/replication-journal.d.ts +20 -0
- package/dist/storage/pdpp-records/replication-journal.d.ts.map +1 -0
- package/dist/storage/pdpp-records/replication-journal.js +2 -0
- package/dist/storage/pdpp-records/replication-journal.js.map +1 -0
- package/dist/storage/pdpp-records/stream-declaration.d.ts +0 -2
- package/dist/storage/pdpp-records/stream-declaration.d.ts.map +1 -1
- package/dist/storage/pdpp-records/stream-declaration.js +0 -9
- package/dist/storage/pdpp-records/stream-declaration.js.map +1 -1
- package/dist/storage/pdpp-records/sync-selection.d.ts +4 -0
- package/dist/storage/pdpp-records/sync-selection.d.ts.map +1 -0
- package/dist/storage/pdpp-records/sync-selection.js +37 -0
- package/dist/storage/pdpp-records/sync-selection.js.map +1 -0
- package/dist/storage/pdpp-records/types.d.ts +64 -0
- package/dist/storage/pdpp-records/types.d.ts.map +1 -1
- package/dist/storage/pdpp-records/types.js.map +1 -1
- package/dist/sync/delete-data-port.d.ts +15 -0
- package/dist/sync/delete-data-port.d.ts.map +1 -1
- package/dist/sync/delete-data-port.js +19 -7
- package/dist/sync/delete-data-port.js.map +1 -1
- package/dist/sync/index.d.ts +2 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +2 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/pending-blob-deletions.d.ts +18 -2
- package/dist/sync/pending-blob-deletions.d.ts.map +1 -1
- package/dist/sync/pending-blob-deletions.js +69 -23
- package/dist/sync/pending-blob-deletions.js.map +1 -1
- package/dist/sync/workers/delete.d.ts.map +1 -1
- package/dist/sync/workers/delete.js +316 -142
- package/dist/sync/workers/delete.js.map +1 -1
- package/dist/sync/workers/download.d.ts.map +1 -1
- package/dist/sync/workers/download.js +53 -5
- package/dist/sync/workers/download.js.map +1 -1
- package/dist/sync/workers/upload.d.ts +24 -5
- package/dist/sync/workers/upload.d.ts.map +1 -1
- package/dist/sync/workers/upload.js +160 -275
- package/dist/sync/workers/upload.js.map +1 -1
- package/dist/test-utils/memory-storage.d.ts.map +1 -1
- package/dist/test-utils/memory-storage.js +17 -2
- package/dist/test-utils/memory-storage.js.map +1 -1
- package/package.json +24 -2
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ReplicaOperation } from "./envelope.js";
|
|
2
|
+
type WithoutRevision<T> = T extends ReplicaOperation ? Omit<T, "revision"> : never;
|
|
3
|
+
type Declared = Extract<ReplicaOperation, {
|
|
4
|
+
declaration: unknown;
|
|
5
|
+
}>;
|
|
6
|
+
/** `upsert:<hex>` of a record body, as `replicaOperationEffect` names it. */
|
|
7
|
+
export declare function replicaUpsertEffect(data: unknown): string;
|
|
8
|
+
/** What a record or completion operation leaves in the canonical state. */
|
|
9
|
+
export declare function replicaOperationEffect(op: WithoutRevision<ReplicaOperation> | ReplicaOperation): string;
|
|
10
|
+
/**
|
|
11
|
+
* The revision and declaration a copy of `source` keeps: its counter, that
|
|
12
|
+
* operation (or its own origin) as origin, and its declaration, so after a
|
|
13
|
+
* rebinding the copy validates exactly where the original did.
|
|
14
|
+
*/
|
|
15
|
+
export declare function reissuedFrom(source: Declared): {
|
|
16
|
+
revision: {
|
|
17
|
+
counter: number;
|
|
18
|
+
origin: {
|
|
19
|
+
writerId: string;
|
|
20
|
+
operationId: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
declaration: {
|
|
24
|
+
digest: string;
|
|
25
|
+
version: string;
|
|
26
|
+
stream: string;
|
|
27
|
+
semantics: "append_only" | "mutable_state";
|
|
28
|
+
primaryKey: string[];
|
|
29
|
+
schemaDigest: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=rebaseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebaseline.d.ts","sourceRoot":"","sources":["../../src/replication/rebaseline.ts"],"names":[],"mappings":"AAcA,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAErE,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,gBAAgB,GAChD,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,GACnB,KAAK,CAAC;AACV,KAAK,QAAQ,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEpE,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAEzD;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,eAAe,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,GACvD,MAAM,CAIR;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ;;;;;;;;;;;;;;;;EAM5C"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rule a rebaseline re-issues canonical state by, shared by every host.
|
|
3
|
+
* A new writer identity re-captures the current state under its own writer
|
|
4
|
+
* before it publishes, so a peer that missed the old writer's batches still
|
|
5
|
+
* converges. Each host walks its own canonical state; this module names a
|
|
6
|
+
* state's effect and the order and binding its copy keeps.
|
|
7
|
+
*
|
|
8
|
+
* Only the operation the merge chose explains a state. A higher operation
|
|
9
|
+
* with the same effect may be one the merge rejected or keeps pending;
|
|
10
|
+
* copying its order or binding would publish a baseline that a peer with
|
|
11
|
+
* this device's trust refuses.
|
|
12
|
+
*/
|
|
13
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
14
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
15
|
+
import { canonicalJson } from "./envelope.js";
|
|
16
|
+
/** `upsert:<hex>` of a record body, as `replicaOperationEffect` names it. */
|
|
17
|
+
export function replicaUpsertEffect(data) {
|
|
18
|
+
return `upsert:${bytesToHex(sha256(new TextEncoder().encode(canonicalJson(data))))}`;
|
|
19
|
+
}
|
|
20
|
+
/** What a record or completion operation leaves in the canonical state. */
|
|
21
|
+
export function replicaOperationEffect(op) {
|
|
22
|
+
if (op.kind === "upsert")
|
|
23
|
+
return replicaUpsertEffect(op.data);
|
|
24
|
+
if (op.kind === "stream-complete")
|
|
25
|
+
return `complete:${op.snapshotSha256}`;
|
|
26
|
+
return op.kind;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The revision and declaration a copy of `source` keeps: its counter, that
|
|
30
|
+
* operation (or its own origin) as origin, and its declaration, so after a
|
|
31
|
+
* rebinding the copy validates exactly where the original did.
|
|
32
|
+
*/
|
|
33
|
+
export function reissuedFrom(source) {
|
|
34
|
+
const { counter, writerId, operationId, origin } = source.revision;
|
|
35
|
+
return {
|
|
36
|
+
revision: { counter, origin: origin ?? { writerId, operationId } },
|
|
37
|
+
declaration: source.declaration,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=rebaseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebaseline.js","sourceRoot":"","sources":["../../src/replication/rebaseline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAyB,MAAM,eAAe,CAAC;AAOrE,6EAA6E;AAC7E,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,OAAO,UAAU,UAAU,CAAC,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvF,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB,CACpC,EAAwD;IAExD,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAI,EAAE,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC;IAC1E,OAAO,EAAE,CAAC,IAAI,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAgB;IAC3C,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IACnE,OAAO;QACL,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE;QAClE,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declaration rebinding: what a changed set of retained declarations does to
|
|
3
|
+
* a replicating database (host contract §4.5).
|
|
4
|
+
*
|
|
5
|
+
* Every operation carries the exact declaration binding it was written
|
|
6
|
+
* under, so a binding is its own version tag. A rebinding therefore journals
|
|
7
|
+
* nothing. The database records a new binding generation, keeps trusting
|
|
8
|
+
* every binding it ever retained, and writes new operations under the new
|
|
9
|
+
* one. Older operations, own or received, in flight or retained, keep their
|
|
10
|
+
* binding and validate against its schema. Versions of one stream merge by
|
|
11
|
+
* revision (`declarationShape`), so devices that upgrade at different times
|
|
12
|
+
* converge once each trusts the bindings the other wrote.
|
|
13
|
+
*
|
|
14
|
+
* A changed shape (semantics or primary key) of a stream the database ever
|
|
15
|
+
* retained changes record identity. That is refused: the database keeps its
|
|
16
|
+
* current generation and the host reports the reason.
|
|
17
|
+
*/
|
|
18
|
+
import { type DeclarationBinding } from "./envelope.js";
|
|
19
|
+
export interface ReplicaBindingEntry {
|
|
20
|
+
sourceId: string;
|
|
21
|
+
binding: DeclarationBinding;
|
|
22
|
+
}
|
|
23
|
+
export type ReplicaRebinding = {
|
|
24
|
+
tag: "unchanged";
|
|
25
|
+
} | {
|
|
26
|
+
tag: "rebind";
|
|
27
|
+
/** Bindings no generation retained before. */
|
|
28
|
+
added: ReplicaBindingEntry[];
|
|
29
|
+
/** Bindings of the current generation the next one drops. Still trusted. */
|
|
30
|
+
retired: ReplicaBindingEntry[];
|
|
31
|
+
} | {
|
|
32
|
+
tag: "refused";
|
|
33
|
+
reason: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Decide the move from the current generation to `next`.
|
|
37
|
+
*
|
|
38
|
+
* @param current The bindings of the current generation.
|
|
39
|
+
* @param history Every binding any generation retained (`current` included).
|
|
40
|
+
* @param next The host's bindings for this boot.
|
|
41
|
+
*/
|
|
42
|
+
export declare function planReplicaRebinding(current: readonly ReplicaBindingEntry[], history: readonly ReplicaBindingEntry[], next: readonly ReplicaBindingEntry[]): ReplicaRebinding;
|
|
43
|
+
//# sourceMappingURL=rebinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebinding.d.ts","sourceRoot":"","sources":["../../src/replication/rebinding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,GAAG,EAAE,WAAW,CAAA;CAAE,GACpB;IACE,GAAG,EAAE,QAAQ,CAAC;IACd,8CAA8C;IAC9C,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC,GACD;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAOvC;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,IAAI,EAAE,SAAS,mBAAmB,EAAE,GACnC,gBAAgB,CAyBlB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declaration rebinding: what a changed set of retained declarations does to
|
|
3
|
+
* a replicating database (host contract §4.5).
|
|
4
|
+
*
|
|
5
|
+
* Every operation carries the exact declaration binding it was written
|
|
6
|
+
* under, so a binding is its own version tag. A rebinding therefore journals
|
|
7
|
+
* nothing. The database records a new binding generation, keeps trusting
|
|
8
|
+
* every binding it ever retained, and writes new operations under the new
|
|
9
|
+
* one. Older operations, own or received, in flight or retained, keep their
|
|
10
|
+
* binding and validate against its schema. Versions of one stream merge by
|
|
11
|
+
* revision (`declarationShape`), so devices that upgrade at different times
|
|
12
|
+
* converge once each trusts the bindings the other wrote.
|
|
13
|
+
*
|
|
14
|
+
* A changed shape (semantics or primary key) of a stream the database ever
|
|
15
|
+
* retained changes record identity. That is refused: the database keeps its
|
|
16
|
+
* current generation and the host reports the reason.
|
|
17
|
+
*/
|
|
18
|
+
import { canonicalJson, declarationShape, } from "./envelope.js";
|
|
19
|
+
const entryKey = (e) => canonicalJson([e.sourceId, e.binding]);
|
|
20
|
+
const streamKey = (e) => canonicalJson([e.sourceId, e.binding.stream]);
|
|
21
|
+
/**
|
|
22
|
+
* Decide the move from the current generation to `next`.
|
|
23
|
+
*
|
|
24
|
+
* @param current The bindings of the current generation.
|
|
25
|
+
* @param history Every binding any generation retained (`current` included).
|
|
26
|
+
* @param next The host's bindings for this boot.
|
|
27
|
+
*/
|
|
28
|
+
export function planReplicaRebinding(current, history, next) {
|
|
29
|
+
const nextKeys = new Set(next.map(entryKey));
|
|
30
|
+
const currentKeys = new Set(current.map(entryKey));
|
|
31
|
+
if (nextKeys.size === currentKeys.size &&
|
|
32
|
+
[...nextKeys].every((key) => currentKeys.has(key)))
|
|
33
|
+
return { tag: "unchanged" };
|
|
34
|
+
const shapes = new Map();
|
|
35
|
+
for (const entry of history)
|
|
36
|
+
shapes.set(streamKey(entry), declarationShape(entry.binding));
|
|
37
|
+
for (const entry of next) {
|
|
38
|
+
const prior = shapes.get(streamKey(entry));
|
|
39
|
+
if (prior !== undefined && prior !== declarationShape(entry.binding))
|
|
40
|
+
return {
|
|
41
|
+
tag: "refused",
|
|
42
|
+
reason: `replication rebinding refused: ${entry.sourceId} stream ${entry.binding.stream} changed its semantics or primary key`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const known = new Set(history.map(entryKey));
|
|
46
|
+
return {
|
|
47
|
+
tag: "rebind",
|
|
48
|
+
added: next.filter((entry) => !known.has(entryKey(entry))),
|
|
49
|
+
retired: current.filter((entry) => !nextKeys.has(entryKey(entry))),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=rebinding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebinding.js","sourceRoot":"","sources":["../../src/replication/rebinding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,aAAa,EACb,gBAAgB,GAEjB,MAAM,eAAe,CAAC;AAkBvB,MAAM,QAAQ,GAAG,CAAC,CAAsB,EAAE,EAAE,CAC1C,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACzC,MAAM,SAAS,GAAG,CAAC,CAAsB,EAAE,EAAE,CAC3C,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAuC,EACvC,OAAuC,EACvC,IAAoC;IAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,IACE,QAAQ,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI;QAClC,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElD,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,OAAO;QACzB,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC;YAClE,OAAO;gBACL,GAAG,EAAE,SAAS;gBACd,MAAM,EAAE,kCAAkC,KAAK,CAAC,QAAQ,WAAW,KAAK,CAAC,OAAO,CAAC,MAAM,uCAAuC;aAC/H,CAAC;IACN,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;KACnE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Hex } from "viem";
|
|
2
|
+
export { REPLICA_RECEIVE_TIMEOUT_MS } from "./dpv2.js";
|
|
3
|
+
import { ReplicaManifestRefused, type ReplicaManifest, type ReplicaFragment } from "./transport.js";
|
|
4
|
+
interface ReplicaObjectInput {
|
|
5
|
+
maxBytes: number;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
read(signal: AbortSignal): Promise<Uint8Array>;
|
|
8
|
+
decrypt(encrypted: Uint8Array): Promise<Uint8Array>;
|
|
9
|
+
}
|
|
10
|
+
export type ReplicaManifestReceipt = {
|
|
11
|
+
tag: "manifest";
|
|
12
|
+
manifest: ReplicaManifest;
|
|
13
|
+
dataHash: Hex;
|
|
14
|
+
metadataHash: Hex;
|
|
15
|
+
}
|
|
16
|
+
/** Terminal for the slot: the bytes can never be a valid manifest there. */
|
|
17
|
+
| {
|
|
18
|
+
tag: "refused";
|
|
19
|
+
reason: ReplicaManifestRefused["reason"];
|
|
20
|
+
}
|
|
21
|
+
/** The bytes are not the slot's finalized commitment; storage may repair them. */
|
|
22
|
+
| {
|
|
23
|
+
tag: "mismatch";
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The one decode boundary for a manifest a peer supplied, in this order: a
|
|
27
|
+
* read bounded by `maxBytes`, the transport's packet check and decryption, a
|
|
28
|
+
* bounded JSON parse, the finalized commitment, then decoding.
|
|
29
|
+
*
|
|
30
|
+
* Before the commitment, bytes that no writer makes (over the bound,
|
|
31
|
+
* compressed, outside the OpenPGP profile, JSON over its bounds) are refused
|
|
32
|
+
* as `manifest_invalid`: their cost is the attack, and the data hash is over
|
|
33
|
+
* plaintext they would have to produce. Other bytes that fail before it are
|
|
34
|
+
* a mismatch, or a thrown read or decrypt error, which the caller retries.
|
|
35
|
+
* After the commitment the bytes are authentic and do not change on retry,
|
|
36
|
+
* so every failure is a refusal.
|
|
37
|
+
*/
|
|
38
|
+
export declare function receiveReplicaManifest(input: ReplicaObjectInput & {
|
|
39
|
+
scope: string;
|
|
40
|
+
owner: string;
|
|
41
|
+
/** Whether this hash pair is the slot's finalized commitment. */
|
|
42
|
+
committed(dataHash: Hex, metadataHash: Hex): boolean;
|
|
43
|
+
}): Promise<ReplicaManifestReceipt>;
|
|
44
|
+
/** Same receive boundary, authenticated by the signed manifest's ciphertext entry. */
|
|
45
|
+
export declare function receiveReplicaFragment(input: ReplicaObjectInput & {
|
|
46
|
+
scope: string;
|
|
47
|
+
owner: string;
|
|
48
|
+
manifest: ReplicaManifest;
|
|
49
|
+
index: number;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
tag: "fragment";
|
|
52
|
+
fragment: ReplicaFragment;
|
|
53
|
+
} | {
|
|
54
|
+
tag: "refused";
|
|
55
|
+
reason: "fragment_mismatch";
|
|
56
|
+
}>;
|
|
57
|
+
//# sourceMappingURL=receive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/replication/receive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAML,sBAAsB,EAItB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAExB,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACrD;AAwDD,MAAM,MAAM,sBAAsB,GAC9B;IACE,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,GAAG,CAAC;IACd,YAAY,EAAE,GAAG,CAAC;CACnB;AACH,4EAA4E;GAC1E;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;CAAE;AAC9D,kFAAkF;GAChF;IAAE,GAAG,EAAE,UAAU,CAAA;CAAE,CAAC;AAExB;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,kBAAkB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,GAAG,OAAO,CAAC;CACtD,GACA,OAAO,CAAC,sBAAsB,CAAC,CAmCjC;AAED,sFAAsF;AACtF,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,kBAAkB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf,GACA,OAAO,CACN;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GAC9C;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAClD,CAuBA"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { keccak256 } from "viem";
|
|
2
|
+
import { ReplicaObjectRefused, REPLICA_RECEIVE_TIMEOUT_MS } from "./dpv2.js";
|
|
3
|
+
export { REPLICA_RECEIVE_TIMEOUT_MS } from "./dpv2.js";
|
|
4
|
+
import { abortable } from "./coordinator.js";
|
|
5
|
+
import { decodeParsedReplicaFragment, decodeParsedReplicaManifest, fragmentMatchesManifest, parseReplicaJson, ReplicaJsonRefused, ReplicaManifestRefused, replicaMetadataHash, replicaDigest, } from "./transport.js";
|
|
6
|
+
/**
|
|
7
|
+
* The shared boundary for every peer object. Fragments have a ciphertext
|
|
8
|
+
* commitment, which can be checked before decryption. Once it matches, any
|
|
9
|
+
* decrypt/parse failure is terminal. Manifest commitments need parsed JSON.
|
|
10
|
+
*/
|
|
11
|
+
async function receiveReplicaJson(input, ciphertextCommitted) {
|
|
12
|
+
const timeout = AbortSignal.timeout(REPLICA_RECEIVE_TIMEOUT_MS);
|
|
13
|
+
const signal = input.signal
|
|
14
|
+
? AbortSignal.any([input.signal, timeout])
|
|
15
|
+
: timeout;
|
|
16
|
+
let plaintext;
|
|
17
|
+
let committed = false;
|
|
18
|
+
try {
|
|
19
|
+
const encrypted = await abortable(signal, () => input.read(signal));
|
|
20
|
+
if (encrypted.length > input.maxBytes)
|
|
21
|
+
throw new ReplicaObjectRefused("oversize");
|
|
22
|
+
if (ciphertextCommitted) {
|
|
23
|
+
if (!ciphertextCommitted(encrypted))
|
|
24
|
+
return { tag: "mismatch" };
|
|
25
|
+
committed = true;
|
|
26
|
+
}
|
|
27
|
+
plaintext = await abortable(signal, () => input.decrypt(encrypted));
|
|
28
|
+
if (plaintext.length > input.maxBytes)
|
|
29
|
+
throw new ReplicaObjectRefused("oversize");
|
|
30
|
+
return {
|
|
31
|
+
tag: "parsed",
|
|
32
|
+
encrypted,
|
|
33
|
+
plaintext,
|
|
34
|
+
parsed: parseReplicaJson(plaintext),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
signal.throwIfAborted();
|
|
39
|
+
if (committed ||
|
|
40
|
+
error instanceof ReplicaObjectRefused ||
|
|
41
|
+
error instanceof ReplicaJsonRefused)
|
|
42
|
+
return { tag: "refused" };
|
|
43
|
+
if (plaintext !== undefined)
|
|
44
|
+
return { tag: "mismatch" };
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The one decode boundary for a manifest a peer supplied, in this order: a
|
|
50
|
+
* read bounded by `maxBytes`, the transport's packet check and decryption, a
|
|
51
|
+
* bounded JSON parse, the finalized commitment, then decoding.
|
|
52
|
+
*
|
|
53
|
+
* Before the commitment, bytes that no writer makes (over the bound,
|
|
54
|
+
* compressed, outside the OpenPGP profile, JSON over its bounds) are refused
|
|
55
|
+
* as `manifest_invalid`: their cost is the attack, and the data hash is over
|
|
56
|
+
* plaintext they would have to produce. Other bytes that fail before it are
|
|
57
|
+
* a mismatch, or a thrown read or decrypt error, which the caller retries.
|
|
58
|
+
* After the commitment the bytes are authentic and do not change on retry,
|
|
59
|
+
* so every failure is a refusal.
|
|
60
|
+
*/
|
|
61
|
+
export async function receiveReplicaManifest(input) {
|
|
62
|
+
const received = await receiveReplicaJson(input);
|
|
63
|
+
if (received.tag === "refused")
|
|
64
|
+
return { tag: "refused", reason: "manifest_invalid" };
|
|
65
|
+
if (received.tag === "mismatch")
|
|
66
|
+
return received;
|
|
67
|
+
const { encrypted, plaintext, parsed } = received;
|
|
68
|
+
const { value } = parsed;
|
|
69
|
+
const collectedAt = typeof value === "object" && value !== null
|
|
70
|
+
? value.collectedAt
|
|
71
|
+
: undefined;
|
|
72
|
+
if (typeof collectedAt !== "string")
|
|
73
|
+
return { tag: "mismatch" };
|
|
74
|
+
const dataHash = keccak256(plaintext);
|
|
75
|
+
const metadataHash = replicaMetadataHash(input.scope, collectedAt, encrypted.length);
|
|
76
|
+
if (!input.committed(dataHash, metadataHash))
|
|
77
|
+
return { tag: "mismatch" };
|
|
78
|
+
try {
|
|
79
|
+
return {
|
|
80
|
+
tag: "manifest",
|
|
81
|
+
manifest: decodeParsedReplicaManifest(parsed, input.scope, input.owner),
|
|
82
|
+
dataHash,
|
|
83
|
+
metadataHash,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
tag: "refused",
|
|
89
|
+
reason: error instanceof ReplicaManifestRefused
|
|
90
|
+
? error.reason
|
|
91
|
+
: "manifest_invalid",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Same receive boundary, authenticated by the signed manifest's ciphertext entry. */
|
|
96
|
+
export async function receiveReplicaFragment(input) {
|
|
97
|
+
const entry = input.manifest.fragments[input.index];
|
|
98
|
+
if (!entry)
|
|
99
|
+
return { tag: "refused", reason: "fragment_mismatch" };
|
|
100
|
+
const received = await receiveReplicaJson(input, (encrypted) => encrypted.length === entry.bytes &&
|
|
101
|
+
replicaDigest(encrypted) === entry.digest);
|
|
102
|
+
if (received.tag !== "parsed")
|
|
103
|
+
return { tag: "refused", reason: "fragment_mismatch" };
|
|
104
|
+
try {
|
|
105
|
+
const fragment = decodeParsedReplicaFragment(received.parsed, input.scope, input.owner);
|
|
106
|
+
if (!fragmentMatchesManifest(fragment, input.manifest, input.index))
|
|
107
|
+
return { tag: "refused", reason: "fragment_mismatch" };
|
|
108
|
+
return { tag: "fragment", fragment };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return { tag: "refused", reason: "fragment_mismatch" };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=receive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/replication/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReplicaOperation, type RecordOperation } from "./envelope.js";
|
|
2
|
+
import { type MergeContext, type MergedRecord } from "./merge-plan.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bounded materialization evidence for ONE key. Original operations, including
|
|
5
|
+
* losers, stay in the durable journal; this is not compaction. Every decision is
|
|
6
|
+
* made by planReplicaMerge. The reducer cannot see a cross-key or
|
|
7
|
+
* cross-connection operation-id collision or a binding conflict: the caller
|
|
8
|
+
* supplies those as `ConnectionFacts` and uses the reducer only while
|
|
9
|
+
* `connectionFromFacts` (visibility-engine.ts) says the connection is active.
|
|
10
|
+
* `lifecycle` must be that connection's globally unique lifecycle operations.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createReplicaRecordReducer(context: MergeContext, lifecycle: readonly ReplicaOperation[]): {
|
|
13
|
+
push(operation: RecordOperation): void;
|
|
14
|
+
readonly record: MergedRecord | undefined;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=record-reducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-reducer.d.ts","sourceRoot":"","sources":["../../src/replication/record-reducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,SAAS,gBAAgB,EAAE;oBAMpB,eAAe;;EAiClC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { canonicalJson, } from "./envelope.js";
|
|
2
|
+
import { planReplicaMerge, } from "./merge-plan.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bounded materialization evidence for ONE key. Original operations, including
|
|
5
|
+
* losers, stay in the durable journal; this is not compaction. Every decision is
|
|
6
|
+
* made by planReplicaMerge. The reducer cannot see a cross-key or
|
|
7
|
+
* cross-connection operation-id collision or a binding conflict: the caller
|
|
8
|
+
* supplies those as `ConnectionFacts` and uses the reducer only while
|
|
9
|
+
* `connectionFromFacts` (visibility-engine.ts) says the connection is active.
|
|
10
|
+
* `lifecycle` must be that connection's globally unique lifecycle operations.
|
|
11
|
+
*/
|
|
12
|
+
export function createReplicaRecordReducer(context, lifecycle) {
|
|
13
|
+
let identity;
|
|
14
|
+
let evidence = [];
|
|
15
|
+
let record;
|
|
16
|
+
return {
|
|
17
|
+
push(operation) {
|
|
18
|
+
const key = canonicalJson([
|
|
19
|
+
operation.owner,
|
|
20
|
+
operation.sourceId,
|
|
21
|
+
operation.connectionId,
|
|
22
|
+
operation.declaration.stream,
|
|
23
|
+
operation.recordKey,
|
|
24
|
+
]);
|
|
25
|
+
if (identity !== undefined && identity !== key)
|
|
26
|
+
throw new Error("mixed replica record partition");
|
|
27
|
+
identity = key;
|
|
28
|
+
const plan = planReplicaMerge(context, [
|
|
29
|
+
...lifecycle,
|
|
30
|
+
...evidence,
|
|
31
|
+
operation,
|
|
32
|
+
]);
|
|
33
|
+
record = plan.records[0];
|
|
34
|
+
if (record?.winner)
|
|
35
|
+
evidence = [record.winner];
|
|
36
|
+
else if (record?.quarantined) {
|
|
37
|
+
const first = record.losers[0];
|
|
38
|
+
const witness = record.losers.find((candidate) => planReplicaMerge(context, [...lifecycle, first, candidate])
|
|
39
|
+
.records[0]?.quarantined);
|
|
40
|
+
if (!witness)
|
|
41
|
+
throw new Error("missing replica conflict witness");
|
|
42
|
+
evidence = [first, witness];
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
evidence = [];
|
|
46
|
+
},
|
|
47
|
+
get record() {
|
|
48
|
+
return record;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=record-reducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-reducer.js","sourceRoot":"","sources":["../../src/replication/record-reducer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAGd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,GAGjB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAqB,EACrB,SAAsC;IAEtC,IAAI,QAA4B,CAAC;IACjC,IAAI,QAAQ,GAAsB,EAAE,CAAC;IACrC,IAAI,MAAgC,CAAC;IACrC,OAAO;QACL,IAAI,CAAC,SAA0B;YAC7B,MAAM,GAAG,GAAG,aAAa,CAAC;gBACxB,SAAS,CAAC,KAAK;gBACf,SAAS,CAAC,QAAQ;gBAClB,SAAS,CAAC,YAAY;gBACtB,SAAS,CAAC,WAAW,CAAC,MAAM;gBAC5B,SAAS,CAAC,SAAS;aACpB,CAAC,CAAC;YACH,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,GAAG;gBAC5C,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,QAAQ,GAAG,GAAG,CAAC;YACf,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE;gBACrC,GAAG,SAAS;gBACZ,GAAG,QAAQ;gBACX,SAAS;aACV,CAAC,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,MAAM,EAAE,MAAM;gBAAE,QAAQ,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC1C,IAAI,MAAM,EAAE,WAAW,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAChC,CAAC,SAAS,EAAE,EAAE,CACZ,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;qBACxD,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,CAC7B,CAAC;gBACF,IAAI,CAAC,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBAClE,QAAQ,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC9B,CAAC;;gBAAM,QAAQ,GAAG,EAAE,CAAC;QACvB,CAAC;QACD,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Persist with the mutation, never derive from a local query version or timestamp. */
|
|
2
|
+
export interface ReplicaRevision {
|
|
3
|
+
counter: number;
|
|
4
|
+
writerId: string;
|
|
5
|
+
operationId: string;
|
|
6
|
+
/**
|
|
7
|
+
* Set on an operation a new writer identity re-issues in its rebaseline:
|
|
8
|
+
* the original operation, whose counter it keeps. It orders as that
|
|
9
|
+
* operation, so a re-issue neither outranks a newer write nor loses a tie
|
|
10
|
+
* the original won.
|
|
11
|
+
*/
|
|
12
|
+
origin?: {
|
|
13
|
+
writerId: string;
|
|
14
|
+
operationId: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Counter, then the original writer and operation ids, then the operation's
|
|
19
|
+
* own. Code-unit ordering is independent of runtime locale.
|
|
20
|
+
*/
|
|
21
|
+
export declare function compareRevisions(a: ReplicaRevision, b: ReplicaRevision): number;
|
|
22
|
+
/** Caller must persist the result atomically with its new local operation. */
|
|
23
|
+
export declare function nextLamportCounter(local: number, observed: readonly number[]): number;
|
|
24
|
+
//# sourceMappingURL=revision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision.d.ts","sourceRoot":"","sources":["../../src/replication/revision.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,eAAe,EAClB,CAAC,EAAE,eAAe,GACjB,MAAM,CAeR;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,CAUR"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter, then the original writer and operation ids, then the operation's
|
|
3
|
+
* own. Code-unit ordering is independent of runtime locale.
|
|
4
|
+
*/
|
|
5
|
+
export function compareRevisions(a, b) {
|
|
6
|
+
for (const [left, right] of [
|
|
7
|
+
[a.counter, b.counter],
|
|
8
|
+
[a.origin?.writerId ?? a.writerId, b.origin?.writerId ?? b.writerId],
|
|
9
|
+
[
|
|
10
|
+
a.origin?.operationId ?? a.operationId,
|
|
11
|
+
b.origin?.operationId ?? b.operationId,
|
|
12
|
+
],
|
|
13
|
+
[a.writerId, b.writerId],
|
|
14
|
+
[a.operationId, b.operationId],
|
|
15
|
+
]) {
|
|
16
|
+
if (left < right)
|
|
17
|
+
return -1;
|
|
18
|
+
if (left > right)
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
/** Caller must persist the result atomically with its new local operation. */
|
|
24
|
+
export function nextLamportCounter(local, observed) {
|
|
25
|
+
let maximum = local;
|
|
26
|
+
for (const counter of [local, ...observed]) {
|
|
27
|
+
if (!Number.isSafeInteger(counter) || counter < 0)
|
|
28
|
+
throw new Error("invalid Lamport counter");
|
|
29
|
+
maximum = Math.max(maximum, counter);
|
|
30
|
+
}
|
|
31
|
+
if (maximum === Number.MAX_SAFE_INTEGER)
|
|
32
|
+
throw new Error("Lamport counter exhausted");
|
|
33
|
+
return maximum + 1;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=revision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision.js","sourceRoot":"","sources":["../../src/replication/revision.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,CAAkB,EAClB,CAAkB;IAElB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI;QAC1B,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC;QACtB,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC;QACpE;YACE,CAAC,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC,WAAW;YACtC,CAAC,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC,WAAW;SACvC;QACD,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC;QACxB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;KACtB,EAAE,CAAC;QACX,IAAI,IAAI,GAAG,KAAK;YAAE,OAAO,CAAC,CAAC,CAAC;QAC5B,IAAI,IAAI,GAAG,KAAK;YAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,kBAAkB,CAChC,KAAa,EACb,QAA2B;IAE3B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,CAAC,gBAAgB;QACrC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,OAAO,OAAO,GAAG,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replica membership: the owner's ServerRegistration roster at the gateway.
|
|
3
|
+
* A receiver imports only from servers that are registered now. It never
|
|
4
|
+
* accepts on an unknown roster: an unavailable answer is a Wait, not absence.
|
|
5
|
+
*/
|
|
6
|
+
/** The gateway record of one server, as membership reads it. */
|
|
7
|
+
export interface ReplicaRosterRecord {
|
|
8
|
+
/** The owner wallet the server is registered under. */
|
|
9
|
+
owner: string;
|
|
10
|
+
/** The gateway registration id (bytes32). A new id is a new incarnation. */
|
|
11
|
+
id: string;
|
|
12
|
+
revokedAt: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface ReplicaRosterCall {
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
export interface ReplicaRosterPort {
|
|
18
|
+
/** null only for a proven absent registration; unavailable answers throw. */
|
|
19
|
+
server(address: `0x${string}`, call?: ReplicaRosterCall): Promise<ReplicaRosterRecord | null>;
|
|
20
|
+
}
|
|
21
|
+
/** The roster could not be read and no fresh answer is cached. Never absence. */
|
|
22
|
+
export declare class ReplicaRosterUnavailableError extends Error {
|
|
23
|
+
readonly code = "replica_roster_unavailable";
|
|
24
|
+
constructor(options?: {
|
|
25
|
+
cause?: unknown;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** The longest a receiver acts on one roster answer. */
|
|
29
|
+
export declare const REPLICA_ROSTER_MAX_AGE_MS: number;
|
|
30
|
+
/**
|
|
31
|
+
* A bounded roster cache. An answer, including a proven absence, is served
|
|
32
|
+
* for at most `maxAgeMs` after it was read. After that the next lookup reads
|
|
33
|
+
* the port again; if that read fails, the lookup throws
|
|
34
|
+
* ReplicaRosterUnavailableError. An expired answer is never served, so a
|
|
35
|
+
* deregistration reaches every check within `maxAgeMs` plus the gateway CDN TTL.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createCachedReplicaRoster(port: ReplicaRosterPort, options?: {
|
|
38
|
+
maxAgeMs?: number;
|
|
39
|
+
maxEntries?: number;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
}): ReplicaRosterPort & {
|
|
42
|
+
invalidate(address?: string): void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* GET /v1/servers/:address. Only the gateway's JSON "Server not found" 404
|
|
46
|
+
* proves absence; any other status or shape is unavailable, so a generic
|
|
47
|
+
* route or CDN 404 cannot refuse a registered server.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createGatewayReplicaRoster(input: {
|
|
50
|
+
gatewayUrl: string;
|
|
51
|
+
fetch?: typeof fetch;
|
|
52
|
+
}): ReplicaRosterPort;
|
|
53
|
+
//# sourceMappingURL=roster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../../src/replication/roster.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gEAAgE;AAChE,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,MAAM,CACJ,OAAO,EAAE,KAAK,MAAM,EAAE,EACtB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;CACxC;AAED,iFAAiF;AACjF,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,gCAAgC;gBACjC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI1C;AAED,wDAAwD;AACxD,eAAO,MAAM,yBAAyB,QAAa,CAAC;AAGpD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC3E,iBAAiB,GAAG;IAAE,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA4C5D;AAID;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,GAAG,iBAAiB,CAyCpB"}
|