@opendatalabs/personal-server-ts-core 1.34.2 → 1.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +332 -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
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { withScopeLock } from "../../additions/scope-lock.js";
|
|
1
2
|
import { computeDataPointId } from "../data-point-id.js";
|
|
3
|
+
import { isGatewayReservedScope } from "../delete-data-port.js";
|
|
4
|
+
import { createMemoryPendingBlobDeletionStore } from "../pending-blob-deletions.js";
|
|
2
5
|
import { deletionTimestamp, isEntryCoveredByTombstone, tombstoneVersion, } from "../scope-deletions.js";
|
|
3
6
|
/**
|
|
4
7
|
* Exact blob deletes sent per pass. vana-storage allows 30 DELETE requests
|
|
@@ -38,6 +41,63 @@ export function planBlobDeletions(storage, scope, tombstoneVersionValue) {
|
|
|
38
41
|
range: last === null || last < 1n ? null : { from: "1", to: last.toString() },
|
|
39
42
|
};
|
|
40
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Snapshot matching rows synchronously. Owner-intent capture precedes remote
|
|
46
|
+
* work; tombstone capture precedes blob cleanup. Later rows stay outside each fence.
|
|
47
|
+
*/
|
|
48
|
+
function captureEntries(storage, scope, includes) {
|
|
49
|
+
const covered = [];
|
|
50
|
+
const PAGE_SIZE = 500;
|
|
51
|
+
for (let offset = 0;; offset += PAGE_SIZE) {
|
|
52
|
+
const entries = storage.listVersions(scope, { limit: PAGE_SIZE, offset });
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (includes(entry)) {
|
|
55
|
+
covered.push({
|
|
56
|
+
id: entry.id,
|
|
57
|
+
path: entry.path,
|
|
58
|
+
collectedAt: entry.collectedAt,
|
|
59
|
+
afterTombstoneVersion: entry.afterTombstoneVersion,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (entries.length < PAGE_SIZE)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
return covered;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Erase exactly the fenced versions, one at a time, each through the storage's
|
|
70
|
+
* fenced erase. The storage checks the row's id and path at the erase itself,
|
|
71
|
+
* under its own lock or transaction, so a replacement that took a fenced stamp
|
|
72
|
+
* after capture is left alone and reported as not erased. No snapshot is taken
|
|
73
|
+
* here, because a snapshot is stale by the time the erase runs.
|
|
74
|
+
*
|
|
75
|
+
* The scope's first-seen sidecar was derived from the fenced rows, so it is
|
|
76
|
+
* dropped after the erases, under the scope lock: a rebuild that read the old
|
|
77
|
+
* rows cannot write it back once this returns. The next read rebuilds it from
|
|
78
|
+
* the rows that survive (a re-add starts afresh there).
|
|
79
|
+
*/
|
|
80
|
+
async function eraseCoveredEntries(storage, scope, fence) {
|
|
81
|
+
if (fence.length === 0)
|
|
82
|
+
return 0;
|
|
83
|
+
let erased = 0;
|
|
84
|
+
try {
|
|
85
|
+
for (const captured of fence) {
|
|
86
|
+
const removed = await storage.deleteVersion(scope, captured.collectedAt, {
|
|
87
|
+
id: captured.id,
|
|
88
|
+
path: captured.path,
|
|
89
|
+
});
|
|
90
|
+
if (removed)
|
|
91
|
+
erased += 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await withScopeLock(scope, async () => {
|
|
96
|
+
await storage.deleteFirstSeenLedger?.(scope);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return erased;
|
|
100
|
+
}
|
|
41
101
|
/** Take up to `count` versions from the head of a range; `rest` is what remains. */
|
|
42
102
|
function takeFromRange(range, count) {
|
|
43
103
|
const from = BigInt(range.from);
|
|
@@ -113,6 +173,15 @@ export async function deleteScope(deps, scope) {
|
|
|
113
173
|
},
|
|
114
174
|
pendingBlobDeletion: false,
|
|
115
175
|
};
|
|
176
|
+
// A new owner request also covers already-acknowledged local re-adds. Capture
|
|
177
|
+
// them before remote work; background retries never get this owner-intent fence.
|
|
178
|
+
const requestedReadds = deleteData
|
|
179
|
+
? captureEntries(storage, scope, (entry) => entry.dataPointId === null &&
|
|
180
|
+
Number.isSafeInteger(entry.afterTombstoneVersion) &&
|
|
181
|
+
Number(entry.afterTombstoneVersion) > 0)
|
|
182
|
+
: [];
|
|
183
|
+
// Set only once a gateway tombstone has landed (see step 2).
|
|
184
|
+
let covered = null;
|
|
116
185
|
if (deleteData) {
|
|
117
186
|
// 1. Gateway tombstone: the durable fact. Nothing else happens if it
|
|
118
187
|
// fails, so the owner gets a clear "nothing was deleted" instead of a
|
|
@@ -176,31 +245,38 @@ export async function deleteScope(deps, scope) {
|
|
|
176
245
|
return result;
|
|
177
246
|
}
|
|
178
247
|
// 2. Storage blobs: exact keys, one pass of at most a batch, the rest
|
|
179
|
-
// queued. A
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
248
|
+
// queued. A repeated delete of a scope whose cleanup is still running
|
|
249
|
+
// resumes from the queue: only work not taken on before is recorded, and
|
|
250
|
+
// the pass drains the scope's queue head, so no confirmed key is re-sent
|
|
251
|
+
// and no queued key is dropped. A tombstone whose version the gateway did
|
|
252
|
+
// not report cannot be expanded into registry keys yet; a version-less
|
|
253
|
+
// marker asks the retry to expand it once the registry answers.
|
|
254
|
+
// Fence first: the covered entries as they stand before the remote await.
|
|
255
|
+
covered = captureEntries(storage, scope, (entry) => isEntryCoveredByTombstone(entry, { version: tombstoneVersionValue }));
|
|
256
|
+
if (tombstoneVersionValue !== null) {
|
|
257
|
+
const anchor = BigInt(tombstoneVersionValue);
|
|
258
|
+
const coveredIds = new Set(covered.map((entry) => entry.id));
|
|
259
|
+
for (const entry of requestedReadds) {
|
|
260
|
+
if (typeof entry.afterTombstoneVersion === "number" &&
|
|
261
|
+
BigInt(entry.afterTombstoneVersion) <= anchor &&
|
|
262
|
+
!coveredIds.has(entry.id))
|
|
263
|
+
covered.push(entry);
|
|
264
|
+
}
|
|
195
265
|
}
|
|
196
|
-
const
|
|
266
|
+
const plan = planBlobDeletions(storage, scope, tombstoneVersionValue);
|
|
267
|
+
const storageStep = await deleteScopeBlobs({ deleteData, pendingBlobDeletions, logger }, scope, plan, tombstoneKnown && tombstoneVersionValue === null);
|
|
197
268
|
result.steps.storage = storageStep.step;
|
|
198
269
|
result.pendingBlobDeletion = storageStep.pending > 0;
|
|
199
270
|
}
|
|
200
271
|
// 3. Local copy. Safe now: the registry row is a tombstone (or the point
|
|
201
|
-
// was never registered / sync is off), so nothing can re-pull it.
|
|
272
|
+
// was never registered / sync is off), so nothing can re-pull it. Only the
|
|
273
|
+
// versions fenced by the tombstone or this owner request are erased: a
|
|
274
|
+
// later re-add stays outside the owner fence. With no gateway
|
|
275
|
+
// there is no fence and the whole local copy goes.
|
|
202
276
|
try {
|
|
203
|
-
const deletedCount =
|
|
277
|
+
const deletedCount = covered
|
|
278
|
+
? await eraseCoveredEntries(storage, scope, covered)
|
|
279
|
+
: await storage.deleteScope(scope);
|
|
204
280
|
result.steps.local = { status: "ok", deletedCount };
|
|
205
281
|
}
|
|
206
282
|
catch (err) {
|
|
@@ -219,51 +295,206 @@ export async function deleteScope(deps, scope) {
|
|
|
219
295
|
return result;
|
|
220
296
|
}
|
|
221
297
|
/**
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
298
|
+
* Where a repeated delete of `scope` resumes: the highest tombstone version
|
|
299
|
+
* whose covered range was already taken on. The store's watermark says so
|
|
300
|
+
* directly; a queued range also proves its own upper bound was planned
|
|
301
|
+
* (which covers marker files written before the watermark existed).
|
|
225
302
|
*/
|
|
226
|
-
async function
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
303
|
+
async function resumePoint(store, scope, markers) {
|
|
304
|
+
const stored = store.plannedThrough
|
|
305
|
+
? await store.plannedThrough(scope)
|
|
306
|
+
: null;
|
|
307
|
+
let through = stored === null ? null : BigInt(stored);
|
|
308
|
+
for (const marker of markers) {
|
|
309
|
+
if (marker.scope !== scope || marker.version !== null || !marker.range) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const to = BigInt(marker.range.to);
|
|
313
|
+
if (through === null || to > through)
|
|
314
|
+
through = to;
|
|
234
315
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
316
|
+
return through;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The part of `plan` not taken on yet: its exact keys, and the registry range
|
|
320
|
+
* above `through`. Keys at or below `through` are already deleted or still
|
|
321
|
+
* queued, so planning them again would only re-send confirmed deletes.
|
|
322
|
+
*/
|
|
323
|
+
function unplannedWork(scope, plan, through) {
|
|
324
|
+
const work = plan.keys.map((version) => ({
|
|
325
|
+
scope,
|
|
326
|
+
version,
|
|
327
|
+
}));
|
|
328
|
+
if (plan.range) {
|
|
329
|
+
let from = BigInt(plan.range.from);
|
|
330
|
+
if (through !== null && through + 1n > from)
|
|
331
|
+
from = through + 1n;
|
|
332
|
+
if (from <= BigInt(plan.range.to)) {
|
|
333
|
+
work.push({
|
|
334
|
+
scope,
|
|
335
|
+
version: null,
|
|
336
|
+
range: { from: from.toString(), to: plan.range.to },
|
|
337
|
+
});
|
|
338
|
+
}
|
|
243
339
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
340
|
+
return work;
|
|
341
|
+
}
|
|
342
|
+
/** Record work and its watermark together when the store supports it. */
|
|
343
|
+
async function recordPlannedWork(store, scope, work, through) {
|
|
344
|
+
if (store.enqueue)
|
|
345
|
+
await store.enqueue(scope, work, through);
|
|
346
|
+
else
|
|
347
|
+
await store.add(work);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Send one rate-limited batch taken from `markers` (exact keys first, then
|
|
351
|
+
* range heads, in stored order) and reconcile the store: acknowledged exact
|
|
352
|
+
* markers (2xx or 404) leave it, a failed key taken from a range becomes an
|
|
353
|
+
* exact marker, and each consumed range is advanced in place. A key queued
|
|
354
|
+
* twice (an exact marker inside a range) is sent once.
|
|
355
|
+
*/
|
|
356
|
+
async function drainOnePass(deleteData, store, markers) {
|
|
357
|
+
let budget = BLOB_DELETE_BATCH_SIZE;
|
|
358
|
+
const byScope = new Map();
|
|
359
|
+
const queued = new Set();
|
|
360
|
+
const exactOrigin = new Set();
|
|
361
|
+
const advancedRanges = [];
|
|
362
|
+
const keyOf = (scope, version) => `${scope}\u0000${version}`;
|
|
363
|
+
const take = (scope, version) => {
|
|
364
|
+
const id = keyOf(scope, version);
|
|
365
|
+
if (queued.has(id))
|
|
366
|
+
return false;
|
|
367
|
+
queued.add(id);
|
|
368
|
+
const versions = byScope.get(scope) ?? [];
|
|
369
|
+
versions.push(version);
|
|
370
|
+
byScope.set(scope, versions);
|
|
371
|
+
return true;
|
|
372
|
+
};
|
|
373
|
+
for (const marker of markers) {
|
|
374
|
+
if (budget === 0)
|
|
375
|
+
break;
|
|
376
|
+
if (marker.version !== null) {
|
|
377
|
+
exactOrigin.add(keyOf(marker.scope, marker.version));
|
|
378
|
+
if (take(marker.scope, marker.version))
|
|
379
|
+
budget -= 1;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
for (const marker of markers) {
|
|
383
|
+
if (budget === 0)
|
|
384
|
+
break;
|
|
385
|
+
if (marker.version === null && marker.range) {
|
|
386
|
+
const taken = takeFromRange(marker.range, budget);
|
|
387
|
+
for (const version of taken.versions) {
|
|
388
|
+
if (take(marker.scope, version))
|
|
389
|
+
budget -= 1;
|
|
390
|
+
}
|
|
391
|
+
advancedRanges.push({
|
|
392
|
+
old: marker,
|
|
393
|
+
next: taken.rest
|
|
394
|
+
? { scope: marker.scope, version: null, range: taken.rest }
|
|
395
|
+
: null,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const outcomes = new Map();
|
|
400
|
+
for (const [scope, versions] of byScope) {
|
|
401
|
+
let outcome;
|
|
252
402
|
try {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
403
|
+
outcome = await deleteData.deleteBlobVersions(scope, versions);
|
|
404
|
+
}
|
|
405
|
+
catch (err) {
|
|
406
|
+
// The port reports per-key failures; a thrown error means none of the
|
|
407
|
+
// batch can be trusted as done.
|
|
408
|
+
const message = errorMessage(err);
|
|
409
|
+
outcome = {
|
|
410
|
+
deleted: [],
|
|
411
|
+
missing: [],
|
|
412
|
+
failed: versions.map((version) => ({ version, error: message })),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
outcomes.set(scope, outcome);
|
|
416
|
+
const completed = [...outcome.deleted, ...outcome.missing]
|
|
417
|
+
.filter((version) => exactOrigin.has(keyOf(scope, version)))
|
|
418
|
+
.map((version) => ({ scope, version }));
|
|
419
|
+
if (completed.length > 0)
|
|
420
|
+
await store.remove(completed);
|
|
421
|
+
// A failed key that came from a range becomes an exact marker; a failed
|
|
422
|
+
// exact marker simply stays.
|
|
423
|
+
const failedFromRange = outcome.failed
|
|
424
|
+
.filter(({ version }) => !exactOrigin.has(keyOf(scope, version)))
|
|
425
|
+
.map(({ version }) => ({ scope, version }));
|
|
426
|
+
if (failedFromRange.length > 0)
|
|
427
|
+
await store.add(failedFromRange);
|
|
428
|
+
}
|
|
429
|
+
// Advance the ranges only now: a crash mid-pass re-sends already-deleted
|
|
430
|
+
// keys (404, harmless) rather than skipping keys that were never sent. The
|
|
431
|
+
// successor is persisted before its predecessor is dropped, so a failed or
|
|
432
|
+
// interrupted write leaves the old range standing, never a gap.
|
|
433
|
+
for (const { old, next } of advancedRanges) {
|
|
434
|
+
if (next)
|
|
435
|
+
await store.add([next]);
|
|
436
|
+
await store.remove([old]);
|
|
437
|
+
}
|
|
438
|
+
return outcomes;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* The storage step of one DELETE call: record the work not taken on yet
|
|
442
|
+
* (with the scope's planned watermark), then send one batch from the head of
|
|
443
|
+
* the scope's queue and report what is still owed. A first delete and a
|
|
444
|
+
* repeat of it run the same path, so a repeat resumes where the queue stands.
|
|
445
|
+
*/
|
|
446
|
+
async function deleteScopeBlobs(deps, scope, plan, versionUnknown) {
|
|
447
|
+
const { deleteData, logger } = deps;
|
|
448
|
+
const withUnknown = (work) => versionUnknown ? [...work, { scope, version: null }] : work;
|
|
449
|
+
let work = withUnknown(unplannedWork(scope, plan, null));
|
|
450
|
+
let store = deps.pendingBlobDeletions ?? null;
|
|
451
|
+
// This scope's markers already in the durable store before this call.
|
|
452
|
+
let queuedBefore = [];
|
|
453
|
+
if (store) {
|
|
454
|
+
try {
|
|
455
|
+
const markers = await store.list();
|
|
456
|
+
queuedBefore = markers.filter((m) => m.scope === scope);
|
|
457
|
+
const through = await resumePoint(store, scope, markers);
|
|
458
|
+
work = withUnknown(unplannedWork(scope, plan, through));
|
|
459
|
+
await recordPlannedWork(store, scope, work, plan.range?.to ?? null);
|
|
257
460
|
}
|
|
258
461
|
catch (markerErr) {
|
|
259
|
-
|
|
260
|
-
|
|
462
|
+
logger.error({ scope, error: errorMessage(markerErr), keys: countPendingKeys(work) }, "Could not record pending blob deletion markers");
|
|
463
|
+
store = null;
|
|
261
464
|
}
|
|
262
465
|
}
|
|
263
|
-
|
|
264
|
-
|
|
466
|
+
// Without a usable marker store this pass still sends a batch, taken from
|
|
467
|
+
// the scope's queue as last read plus the new work. The new work it cannot
|
|
468
|
+
// send is reported, not recorded; the durable queue keeps its old markers
|
|
469
|
+
// untouched, so that work is still owed and reported as pending.
|
|
470
|
+
const recorded = store !== null;
|
|
471
|
+
const passStore = store ?? createMemoryPendingBlobDeletionStore();
|
|
472
|
+
if (!recorded)
|
|
473
|
+
await passStore.add([...queuedBefore, ...work]);
|
|
474
|
+
const durablyOwed = recorded ? 0 : countPendingKeys(queuedBefore);
|
|
475
|
+
let outcome;
|
|
476
|
+
let remainingKeys;
|
|
477
|
+
try {
|
|
478
|
+
const queued = (await passStore.list()).filter((m) => m.scope === scope);
|
|
479
|
+
outcome = (await drainOnePass(deleteData, passStore, queued)).get(scope) ?? { deleted: [], missing: [], failed: [] };
|
|
480
|
+
remainingKeys = countPendingKeys((await passStore.list()).filter((m) => m.scope === scope));
|
|
481
|
+
}
|
|
482
|
+
catch (markerErr) {
|
|
483
|
+
// A marker write failed mid-pass. The store never loses owed keys (see
|
|
484
|
+
// drainOnePass), so the queue still holds this scope's work.
|
|
485
|
+
const message = errorMessage(markerErr);
|
|
486
|
+
logger.error({ scope, error: message }, "Could not update pending blob deletion markers");
|
|
487
|
+
return {
|
|
488
|
+
step: { status: "failed", error: message },
|
|
489
|
+
pending: recorded || durablyOwed > 0 ? 1 : 0,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
if (!recorded && remainingKeys > durablyOwed) {
|
|
265
493
|
logger.error({ scope, keys: remainingKeys }, "Blob deletions left unfinished with no marker store to retry them");
|
|
266
494
|
}
|
|
495
|
+
if (!recorded)
|
|
496
|
+
remainingKeys = Math.max(remainingKeys, durablyOwed);
|
|
497
|
+
const pending = recorded ? remainingKeys : durablyOwed;
|
|
267
498
|
const counts = {
|
|
268
499
|
blobsDeleted: outcome.deleted.length,
|
|
269
500
|
blobsMissing: outcome.missing.length,
|
|
@@ -271,24 +502,19 @@ async function deleteBlobKeys(deps, scope, batch, leftovers) {
|
|
|
271
502
|
};
|
|
272
503
|
if (outcome.failed.length > 0) {
|
|
273
504
|
const first = outcome.failed[0];
|
|
274
|
-
logger.warn({
|
|
275
|
-
scope,
|
|
276
|
-
failed: outcome.failed.length,
|
|
277
|
-
pending: recorded,
|
|
278
|
-
error: first.error,
|
|
279
|
-
}, "Storage blob deletion failed for some keys after gateway tombstone; will retry");
|
|
505
|
+
logger.warn({ scope, failed: outcome.failed.length, pending, error: first.error }, "Storage blob deletion failed for some keys after gateway tombstone; will retry");
|
|
280
506
|
return {
|
|
281
507
|
step: {
|
|
282
508
|
status: "failed",
|
|
283
509
|
error: `${outcome.failed.length} blob delete(s) failed: ${first.error}`,
|
|
284
510
|
...counts,
|
|
285
511
|
},
|
|
286
|
-
pending
|
|
512
|
+
pending,
|
|
287
513
|
};
|
|
288
514
|
}
|
|
289
|
-
if (
|
|
515
|
+
if (remainingKeys > 0) {
|
|
290
516
|
logger.info({ scope, ...counts }, "Storage blob deletion continues on later sync cycles (rate-limited batch)");
|
|
291
|
-
return { step: { status: "deferred", ...counts }, pending
|
|
517
|
+
return { step: { status: "deferred", ...counts }, pending };
|
|
292
518
|
}
|
|
293
519
|
return { step: { status: "ok", ...counts }, pending: 0 };
|
|
294
520
|
}
|
|
@@ -332,85 +558,26 @@ export async function retryPendingBlobDeletions(deps) {
|
|
|
332
558
|
result.superseded.push(marker.scope);
|
|
333
559
|
logger.warn({
|
|
334
560
|
scope: marker.scope,
|
|
335
|
-
dataPointId: registry.
|
|
336
|
-
version: registry.
|
|
561
|
+
dataPointId: registry.id,
|
|
562
|
+
version: registry.expectedVersion,
|
|
337
563
|
}, "Scope was re-added after its tombstone; dropping the unexpanded blob deletion marker so the live version's ciphertext survives");
|
|
338
564
|
continue;
|
|
339
565
|
}
|
|
340
566
|
const plan = planBlobDeletions(deps.storage ?? { listVersions: () => [] }, marker.scope, registry.status === "deleted" ? registry.version : null);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
567
|
+
// Only the part not taken on yet: a repeated delete may already have
|
|
568
|
+
// queued (or finished) the same tombstone's range.
|
|
569
|
+
const expanded = unplannedWork(marker.scope, plan, await resumePoint(pendingBlobDeletions, marker.scope, markers));
|
|
570
|
+
// Persist the expansion before dropping the unexpanded marker: a failed or
|
|
571
|
+
// interrupted write leaves the marker to expand again (the same keys), and
|
|
572
|
+
// never drops keys that are still owed.
|
|
573
|
+
await recordPlannedWork(pendingBlobDeletions, marker.scope, expanded, plan.range?.to ?? null);
|
|
348
574
|
await pendingBlobDeletions.remove([marker]);
|
|
349
|
-
await pendingBlobDeletions.add(expanded);
|
|
350
575
|
}
|
|
351
576
|
markers = await pendingBlobDeletions.list();
|
|
352
577
|
// One rate-limited batch in stored order: exact keys, then range heads.
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
const exactOrigin = new Set();
|
|
356
|
-
const advancedRanges = [];
|
|
357
|
-
const enqueue = (scope, version) => {
|
|
358
|
-
const versions = byScope.get(scope) ?? [];
|
|
359
|
-
versions.push(version);
|
|
360
|
-
byScope.set(scope, versions);
|
|
361
|
-
};
|
|
362
|
-
for (const marker of markers) {
|
|
363
|
-
if (budget === 0)
|
|
364
|
-
break;
|
|
365
|
-
if (marker.version !== null) {
|
|
366
|
-
enqueue(marker.scope, marker.version);
|
|
367
|
-
exactOrigin.add(`${marker.scope}\u0000${marker.version}`);
|
|
368
|
-
budget -= 1;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
for (const marker of markers) {
|
|
372
|
-
if (budget === 0)
|
|
373
|
-
break;
|
|
374
|
-
if (marker.version === null && marker.range) {
|
|
375
|
-
const taken = takeFromRange(marker.range, budget);
|
|
376
|
-
for (const version of taken.versions)
|
|
377
|
-
enqueue(marker.scope, version);
|
|
378
|
-
budget -= taken.versions.length;
|
|
379
|
-
advancedRanges.push({
|
|
380
|
-
old: marker,
|
|
381
|
-
next: taken.rest
|
|
382
|
-
? { scope: marker.scope, version: null, range: taken.rest }
|
|
383
|
-
: null,
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
for (const [scope, versions] of byScope) {
|
|
388
|
-
let outcome;
|
|
389
|
-
try {
|
|
390
|
-
outcome = await deleteData.deleteBlobVersions(scope, versions);
|
|
391
|
-
}
|
|
392
|
-
catch (err) {
|
|
393
|
-
const message = errorMessage(err);
|
|
394
|
-
outcome = {
|
|
395
|
-
deleted: [],
|
|
396
|
-
missing: [],
|
|
397
|
-
failed: versions.map((version) => ({ version, error: message })),
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
const completed = [...outcome.deleted, ...outcome.missing]
|
|
401
|
-
.filter((version) => exactOrigin.has(`${scope}\u0000${version}`))
|
|
402
|
-
.map((version) => ({ scope, version }));
|
|
403
|
-
if (completed.length > 0)
|
|
404
|
-
await pendingBlobDeletions.remove(completed);
|
|
578
|
+
const outcomes = await drainOnePass(deleteData, pendingBlobDeletions, markers);
|
|
579
|
+
for (const [scope, outcome] of outcomes) {
|
|
405
580
|
result.completed.push(...[...outcome.deleted, ...outcome.missing].map((version) => ({ scope, version })));
|
|
406
|
-
// A failed key that came from a range becomes an exact marker; a failed
|
|
407
|
-
// exact marker simply stays.
|
|
408
|
-
const failedFromRange = outcome.failed
|
|
409
|
-
.filter(({ version }) => !exactOrigin.has(`${scope}\u0000${version}`))
|
|
410
|
-
.map(({ version }) => ({ scope, version }));
|
|
411
|
-
if (failedFromRange.length > 0) {
|
|
412
|
-
await pendingBlobDeletions.add(failedFromRange);
|
|
413
|
-
}
|
|
414
581
|
for (const failure of outcome.failed) {
|
|
415
582
|
result.failed.push({ scope, ...failure });
|
|
416
583
|
}
|
|
@@ -429,13 +596,6 @@ export async function retryPendingBlobDeletions(deps) {
|
|
|
429
596
|
}, "Pending blob deletion failed again");
|
|
430
597
|
}
|
|
431
598
|
}
|
|
432
|
-
// Advance the ranges only now: a crash mid-pass re-sends already-deleted
|
|
433
|
-
// keys (404, harmless) rather than skipping keys that were never sent.
|
|
434
|
-
for (const { old, next } of advancedRanges) {
|
|
435
|
-
await pendingBlobDeletions.remove([old]);
|
|
436
|
-
if (next)
|
|
437
|
-
await pendingBlobDeletions.add([next]);
|
|
438
|
-
}
|
|
439
599
|
result.remaining = (await pendingBlobDeletions.list()).length;
|
|
440
600
|
return result;
|
|
441
601
|
}
|
|
@@ -446,6 +606,31 @@ export async function retryPendingBlobDeletions(deps) {
|
|
|
446
606
|
* wired) or the row is gone.
|
|
447
607
|
*/
|
|
448
608
|
async function registryState(deps, scope) {
|
|
609
|
+
// The gateway refuses an unsigned read of a reserved point; ask the port.
|
|
610
|
+
if (isGatewayReservedScope(scope) &&
|
|
611
|
+
deps.deleteData?.head &&
|
|
612
|
+
deps.serverOwner) {
|
|
613
|
+
let head;
|
|
614
|
+
try {
|
|
615
|
+
head = await deps.deleteData.head(scope);
|
|
616
|
+
}
|
|
617
|
+
catch (err) {
|
|
618
|
+
return {
|
|
619
|
+
status: "unknown",
|
|
620
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
if (head === null)
|
|
624
|
+
return { status: "deleted-or-absent" };
|
|
625
|
+
if (head.deletedAt === null) {
|
|
626
|
+
return {
|
|
627
|
+
status: "live",
|
|
628
|
+
id: computeDataPointId(deps.serverOwner, scope),
|
|
629
|
+
expectedVersion: head.expectedVersion,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return { status: "deleted", version: tombstoneVersion(head) };
|
|
633
|
+
}
|
|
449
634
|
if (!deps.dataPointFeed || !deps.serverOwner) {
|
|
450
635
|
return { status: "deleted-or-absent" };
|
|
451
636
|
}
|
|
@@ -464,8 +649,13 @@ async function registryState(deps, scope) {
|
|
|
464
649
|
}
|
|
465
650
|
if (record === null)
|
|
466
651
|
return { status: "deleted-or-absent" };
|
|
467
|
-
if (deletionTimestamp(record) === null)
|
|
468
|
-
return {
|
|
652
|
+
if (deletionTimestamp(record) === null) {
|
|
653
|
+
return {
|
|
654
|
+
status: "live",
|
|
655
|
+
id: record.id,
|
|
656
|
+
expectedVersion: record.expectedVersion,
|
|
657
|
+
};
|
|
658
|
+
}
|
|
469
659
|
return { status: "deleted", version: tombstoneVersion(record) };
|
|
470
660
|
}
|
|
471
661
|
function errorMessage(err) {
|