ramosedb 0.0.0-stage → 0.4.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/LICENSE +202 -0
- package/NOTICE +17 -0
- package/README.md +57 -2
- package/dist/Auth.d.ts +55 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +50 -0
- package/dist/Auth.js.map +1 -0
- package/dist/Database.d.ts +40 -0
- package/dist/Database.d.ts.map +1 -0
- package/dist/Database.js +62 -0
- package/dist/Database.js.map +1 -0
- package/dist/Providers.d.ts +8 -0
- package/dist/Providers.d.ts.map +1 -0
- package/dist/Providers.js +9 -0
- package/dist/Providers.js.map +1 -0
- package/dist/RamoseEnv.d.ts +37 -0
- package/dist/RamoseEnv.d.ts.map +1 -0
- package/dist/RamoseEnv.js +2 -0
- package/dist/RamoseEnv.js.map +1 -0
- package/dist/Server.d.ts +100 -0
- package/dist/Server.d.ts.map +1 -0
- package/dist/Server.js +263 -0
- package/dist/Server.js.map +1 -0
- package/dist/ServerRuntime.d.ts +10 -0
- package/dist/ServerRuntime.d.ts.map +1 -0
- package/dist/ServerRuntime.js +11 -0
- package/dist/ServerRuntime.js.map +1 -0
- package/dist/better-auth/client.d.ts +19 -0
- package/dist/better-auth/client.d.ts.map +1 -0
- package/dist/better-auth/client.js +110 -0
- package/dist/better-auth/client.js.map +1 -0
- package/dist/better-auth/index.d.ts +140 -0
- package/dist/better-auth/index.d.ts.map +1 -0
- package/dist/better-auth/index.js +168 -0
- package/dist/better-auth/index.js.map +1 -0
- package/dist/client/activation.d.ts +2 -0
- package/dist/client/activation.d.ts.map +1 -0
- package/dist/client/activation.js +33 -0
- package/dist/client/activation.js.map +1 -0
- package/dist/client/catalog.d.ts +15 -0
- package/dist/client/catalog.d.ts.map +1 -0
- package/dist/client/catalog.js +48 -0
- package/dist/client/catalog.js.map +1 -0
- package/dist/client/changesets.d.ts +85 -0
- package/dist/client/changesets.d.ts.map +1 -0
- package/dist/client/changesets.js +160 -0
- package/dist/client/changesets.js.map +1 -0
- package/dist/client/client.d.ts +45 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +425 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/database.d.ts +163 -0
- package/dist/client/database.d.ts.map +1 -0
- package/dist/client/database.js +795 -0
- package/dist/client/database.js.map +1 -0
- package/dist/client/entity.d.ts +63 -0
- package/dist/client/entity.d.ts.map +1 -0
- package/dist/client/entity.js +141 -0
- package/dist/client/entity.js.map +1 -0
- package/dist/client/errors.d.ts +67 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +39 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/index.d.ts +13 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/mutation-schema.d.ts +92 -0
- package/dist/client/mutation-schema.d.ts.map +1 -0
- package/dist/client/mutation-schema.js +2 -0
- package/dist/client/mutation-schema.js.map +1 -0
- package/dist/client/mutation.d.ts +25 -0
- package/dist/client/mutation.d.ts.map +1 -0
- package/dist/client/mutation.js +75 -0
- package/dist/client/mutation.js.map +1 -0
- package/dist/client/operations.d.ts +39 -0
- package/dist/client/operations.d.ts.map +1 -0
- package/dist/client/operations.js +183 -0
- package/dist/client/operations.js.map +1 -0
- package/dist/client/query.d.ts +53 -0
- package/dist/client/query.d.ts.map +1 -0
- package/dist/client/query.js +85 -0
- package/dist/client/query.js.map +1 -0
- package/dist/client/receipt.d.ts +53 -0
- package/dist/client/receipt.d.ts.map +1 -0
- package/dist/client/receipt.js +79 -0
- package/dist/client/receipt.js.map +1 -0
- package/dist/client/submission.d.ts +44 -0
- package/dist/client/submission.d.ts.map +1 -0
- package/dist/client/submission.js +165 -0
- package/dist/client/submission.js.map +1 -0
- package/dist/client/subscription.d.ts +18 -0
- package/dist/client/subscription.d.ts.map +1 -0
- package/dist/client/subscription.js +75 -0
- package/dist/client/subscription.js.map +1 -0
- package/dist/client/sync.d.ts +32 -0
- package/dist/client/sync.d.ts.map +1 -0
- package/dist/client/sync.js +34 -0
- package/dist/client/sync.js.map +1 -0
- package/dist/client/view.d.ts +37 -0
- package/dist/client/view.d.ts.map +1 -0
- package/dist/client/view.js +112 -0
- package/dist/client/view.js.map +1 -0
- package/dist/db/Binding.d.ts +79 -0
- package/dist/db/Binding.d.ts.map +1 -0
- package/dist/db/Binding.js +138 -0
- package/dist/db/Binding.js.map +1 -0
- package/dist/db/Composer.d.ts +7 -0
- package/dist/db/Composer.d.ts.map +1 -0
- package/dist/db/Composer.js +6 -0
- package/dist/db/Composer.js.map +1 -0
- package/dist/db/DatabaseName.d.ts +7 -0
- package/dist/db/DatabaseName.d.ts.map +1 -0
- package/dist/db/DatabaseName.js +9 -0
- package/dist/db/DatabaseName.js.map +1 -0
- package/dist/db/Eid.d.ts +19 -0
- package/dist/db/Eid.d.ts.map +1 -0
- package/dist/db/Eid.js +2 -0
- package/dist/db/Eid.js.map +1 -0
- package/dist/db/Entity.d.ts +133 -0
- package/dist/db/Entity.d.ts.map +1 -0
- package/dist/db/Entity.js +104 -0
- package/dist/db/Entity.js.map +1 -0
- package/dist/db/Errors.d.ts +138 -0
- package/dist/db/Errors.d.ts.map +1 -0
- package/dist/db/Errors.js +171 -0
- package/dist/db/Errors.js.map +1 -0
- package/dist/db/Field.d.ts +170 -0
- package/dist/db/Field.d.ts.map +1 -0
- package/dist/db/Field.js +187 -0
- package/dist/db/Field.js.map +1 -0
- package/dist/db/IdentName.d.ts +94 -0
- package/dist/db/IdentName.d.ts.map +1 -0
- package/dist/db/IdentName.js +34 -0
- package/dist/db/IdentName.js.map +1 -0
- package/dist/db/Operation.d.ts +441 -0
- package/dist/db/Operation.d.ts.map +1 -0
- package/dist/db/Operation.js +237 -0
- package/dist/db/Operation.js.map +1 -0
- package/dist/db/Projection.d.ts +97 -0
- package/dist/db/Projection.d.ts.map +1 -0
- package/dist/db/Projection.js +183 -0
- package/dist/db/Projection.js.map +1 -0
- package/dist/db/Pull.d.ts +361 -0
- package/dist/db/Pull.d.ts.map +1 -0
- package/dist/db/Pull.js +547 -0
- package/dist/db/Pull.js.map +1 -0
- package/dist/db/Schema.d.ts +37 -0
- package/dist/db/Schema.d.ts.map +1 -0
- package/dist/db/Schema.js +94 -0
- package/dist/db/Schema.js.map +1 -0
- package/dist/db/Trait.d.ts +129 -0
- package/dist/db/Trait.d.ts.map +1 -0
- package/dist/db/Trait.js +65 -0
- package/dist/db/Trait.js.map +1 -0
- package/dist/db/Tx.d.ts +128 -0
- package/dist/db/Tx.d.ts.map +1 -0
- package/dist/db/Tx.js +248 -0
- package/dist/db/Tx.js.map +1 -0
- package/dist/db/allocations.d.ts +44 -0
- package/dist/db/allocations.d.ts.map +1 -0
- package/dist/db/allocations.js +70 -0
- package/dist/db/allocations.js.map +1 -0
- package/dist/db/attrRef.d.ts +5 -0
- package/dist/db/attrRef.d.ts.map +1 -0
- package/dist/db/attrRef.js +6 -0
- package/dist/db/attrRef.js.map +1 -0
- package/dist/db/compose.d.ts +26 -0
- package/dist/db/compose.d.ts.map +1 -0
- package/dist/db/compose.js +105 -0
- package/dist/db/compose.js.map +1 -0
- package/dist/db/composition.d.ts +4 -0
- package/dist/db/composition.d.ts.map +1 -0
- package/dist/db/composition.js +24 -0
- package/dist/db/composition.js.map +1 -0
- package/dist/db/creation.d.ts +102 -0
- package/dist/db/creation.d.ts.map +1 -0
- package/dist/db/creation.js +448 -0
- package/dist/db/creation.js.map +1 -0
- package/dist/db/deployedSchema.d.ts +12 -0
- package/dist/db/deployedSchema.d.ts.map +1 -0
- package/dist/db/deployedSchema.js +80 -0
- package/dist/db/deployedSchema.js.map +1 -0
- package/dist/db/documentation.d.ts +4 -0
- package/dist/db/documentation.d.ts.map +1 -0
- package/dist/db/documentation.js +4 -0
- package/dist/db/documentation.js.map +1 -0
- package/dist/db/ensure.d.ts +16 -0
- package/dist/db/ensure.d.ts.map +1 -0
- package/dist/db/ensure.js +48 -0
- package/dist/db/ensure.js.map +1 -0
- package/dist/db/entityArg.d.ts +15 -0
- package/dist/db/entityArg.d.ts.map +1 -0
- package/dist/db/entityArg.js +71 -0
- package/dist/db/entityArg.js.map +1 -0
- package/dist/db/equal.d.ts +4 -0
- package/dist/db/equal.d.ts.map +1 -0
- package/dist/db/equal.js +2 -0
- package/dist/db/equal.js.map +1 -0
- package/dist/db/idents.d.ts +90 -0
- package/dist/db/idents.d.ts.map +1 -0
- package/dist/db/idents.js +2 -0
- package/dist/db/idents.js.map +1 -0
- package/dist/db/index.d.ts +27 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +20 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/internal.d.ts +27 -0
- package/dist/db/internal.d.ts.map +1 -0
- package/dist/db/internal.js +27 -0
- package/dist/db/internal.js.map +1 -0
- package/dist/db/query/cursor.d.ts +13 -0
- package/dist/db/query/cursor.d.ts.map +1 -0
- package/dist/db/query/cursor.js +150 -0
- package/dist/db/query/cursor.js.map +1 -0
- package/dist/db/query/elemFilter.d.ts +7 -0
- package/dist/db/query/elemFilter.d.ts.map +1 -0
- package/dist/db/query/elemFilter.js +280 -0
- package/dist/db/query/elemFilter.js.map +1 -0
- package/dist/db/query/fluent.d.ts +92 -0
- package/dist/db/query/fluent.d.ts.map +1 -0
- package/dist/db/query/fluent.js +125 -0
- package/dist/db/query/fluent.js.map +1 -0
- package/dist/db/query/focus.d.ts +42 -0
- package/dist/db/query/focus.d.ts.map +1 -0
- package/dist/db/query/focus.js +2 -0
- package/dist/db/query/focus.js.map +1 -0
- package/dist/db/query/index.d.ts +7 -0
- package/dist/db/query/index.d.ts.map +1 -0
- package/dist/db/query/index.js +6 -0
- package/dist/db/query/index.js.map +1 -0
- package/dist/db/query/kernel.d.ts +215 -0
- package/dist/db/query/kernel.d.ts.map +1 -0
- package/dist/db/query/kernel.js +284 -0
- package/dist/db/query/kernel.js.map +1 -0
- package/dist/db/query/lib.d.ts +168 -0
- package/dist/db/query/lib.d.ts.map +1 -0
- package/dist/db/query/lib.js +175 -0
- package/dist/db/query/lib.js.map +1 -0
- package/dist/db/query/query.d.ts +209 -0
- package/dist/db/query/query.d.ts.map +1 -0
- package/dist/db/query/query.js +1536 -0
- package/dist/db/query/query.js.map +1 -0
- package/dist/db/query/stdlib/failures.d.ts +91 -0
- package/dist/db/query/stdlib/failures.d.ts.map +1 -0
- package/dist/db/query/stdlib/failures.js +57 -0
- package/dist/db/query/stdlib/failures.js.map +1 -0
- package/dist/db/query/stdlib/implementations.d.ts +5 -0
- package/dist/db/query/stdlib/implementations.d.ts.map +1 -0
- package/dist/db/query/stdlib/implementations.js +208 -0
- package/dist/db/query/stdlib/implementations.js.map +1 -0
- package/dist/db/query/stdlib/index.d.ts +6 -0
- package/dist/db/query/stdlib/index.d.ts.map +1 -0
- package/dist/db/query/stdlib/index.js +6 -0
- package/dist/db/query/stdlib/index.js.map +1 -0
- package/dist/db/query/stdlib/manifest.d.ts +3 -0
- package/dist/db/query/stdlib/manifest.d.ts.map +1 -0
- package/dist/db/query/stdlib/manifest.js +1067 -0
- package/dist/db/query/stdlib/manifest.js.map +1 -0
- package/dist/db/query/stdlib/registry.d.ts +22 -0
- package/dist/db/query/stdlib/registry.d.ts.map +1 -0
- package/dist/db/query/stdlib/registry.js +144 -0
- package/dist/db/query/stdlib/registry.js.map +1 -0
- package/dist/db/query/stdlib/types.d.ts +50 -0
- package/dist/db/query/stdlib/types.d.ts.map +1 -0
- package/dist/db/query/stdlib/types.js +17 -0
- package/dist/db/query/stdlib/types.js.map +1 -0
- package/dist/db/query/stdlib/values.d.ts +17 -0
- package/dist/db/query/stdlib/values.d.ts.map +1 -0
- package/dist/db/query/stdlib/values.js +200 -0
- package/dist/db/query/stdlib/values.js.map +1 -0
- package/dist/db/query/surface.d.ts +15 -0
- package/dist/db/query/surface.d.ts.map +1 -0
- package/dist/db/query/surface.js +14 -0
- package/dist/db/query/surface.js.map +1 -0
- package/dist/db/reachability.d.ts +40 -0
- package/dist/db/reachability.d.ts.map +1 -0
- package/dist/db/reachability.js +118 -0
- package/dist/db/reachability.js.map +1 -0
- package/dist/db/refs.d.ts +46 -0
- package/dist/db/refs.d.ts.map +1 -0
- package/dist/db/refs.js +69 -0
- package/dist/db/refs.js.map +1 -0
- package/dist/db/shapes.d.ts +227 -0
- package/dist/db/shapes.d.ts.map +1 -0
- package/dist/db/shapes.js +246 -0
- package/dist/db/shapes.js.map +1 -0
- package/dist/db/valueTypes.d.ts +92 -0
- package/dist/db/valueTypes.d.ts.map +1 -0
- package/dist/db/valueTypes.js +105 -0
- package/dist/db/valueTypes.js.map +1 -0
- package/dist/errorHttp.d.ts +27 -0
- package/dist/errorHttp.d.ts.map +1 -0
- package/dist/errorHttp.js +95 -0
- package/dist/errorHttp.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/authorization/authoring/compile.d.ts +132 -0
- package/dist/internal/authorization/authoring/compile.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/compile.js +634 -0
- package/dist/internal/authorization/authoring/compile.js.map +1 -0
- package/dist/internal/authorization/authoring/expr.d.ts +25 -0
- package/dist/internal/authorization/authoring/expr.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/expr.js +56 -0
- package/dist/internal/authorization/authoring/expr.js.map +1 -0
- package/dist/internal/authorization/authoring/index.d.ts +10 -0
- package/dist/internal/authorization/authoring/index.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/index.js +8 -0
- package/dist/internal/authorization/authoring/index.js.map +1 -0
- package/dist/internal/authorization/authoring/invoke.d.ts +8 -0
- package/dist/internal/authorization/authoring/invoke.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/invoke.js +7 -0
- package/dist/internal/authorization/authoring/invoke.js.map +1 -0
- package/dist/internal/authorization/authoring/operations.d.ts +81 -0
- package/dist/internal/authorization/authoring/operations.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/operations.js +591 -0
- package/dist/internal/authorization/authoring/operations.js.map +1 -0
- package/dist/internal/authorization/authoring/path.d.ts +20 -0
- package/dist/internal/authorization/authoring/path.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/path.js +109 -0
- package/dist/internal/authorization/authoring/path.js.map +1 -0
- package/dist/internal/authorization/authoring/policy.d.ts +120 -0
- package/dist/internal/authorization/authoring/policy.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/policy.js +218 -0
- package/dist/internal/authorization/authoring/policy.js.map +1 -0
- package/dist/internal/authorization/authoring/read.d.ts +13 -0
- package/dist/internal/authorization/authoring/read.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/read.js +27 -0
- package/dist/internal/authorization/authoring/read.js.map +1 -0
- package/dist/internal/authorization/authoring/types.d.ts +127 -0
- package/dist/internal/authorization/authoring/types.d.ts.map +1 -0
- package/dist/internal/authorization/authoring/types.js +43 -0
- package/dist/internal/authorization/authoring/types.js.map +1 -0
- package/dist/internal/authorization/bind.d.ts +687 -0
- package/dist/internal/authorization/bind.d.ts.map +1 -0
- package/dist/internal/authorization/bind.js +485 -0
- package/dist/internal/authorization/bind.js.map +1 -0
- package/dist/internal/authorization/bounds.d.ts +13 -0
- package/dist/internal/authorization/bounds.d.ts.map +1 -0
- package/dist/internal/authorization/bounds.js +9 -0
- package/dist/internal/authorization/bounds.js.map +1 -0
- package/dist/internal/authorization/canonical-json.d.ts +6 -0
- package/dist/internal/authorization/canonical-json.d.ts.map +1 -0
- package/dist/internal/authorization/canonical-json.js +65 -0
- package/dist/internal/authorization/canonical-json.js.map +1 -0
- package/dist/internal/authorization/catalog-unit.d.ts +1033 -0
- package/dist/internal/authorization/catalog-unit.d.ts.map +1 -0
- package/dist/internal/authorization/catalog-unit.js +303 -0
- package/dist/internal/authorization/catalog-unit.js.map +1 -0
- package/dist/internal/authorization/catalog.d.ts +472 -0
- package/dist/internal/authorization/catalog.d.ts.map +1 -0
- package/dist/internal/authorization/catalog.js +134 -0
- package/dist/internal/authorization/catalog.js.map +1 -0
- package/dist/internal/authorization/changesets.d.ts +54 -0
- package/dist/internal/authorization/changesets.d.ts.map +1 -0
- package/dist/internal/authorization/changesets.js +156 -0
- package/dist/internal/authorization/changesets.js.map +1 -0
- package/dist/internal/authorization/composition.d.ts +10 -0
- package/dist/internal/authorization/composition.d.ts.map +1 -0
- package/dist/internal/authorization/composition.js +28 -0
- package/dist/internal/authorization/composition.js.map +1 -0
- package/dist/internal/authorization/database-bindings.d.ts +48 -0
- package/dist/internal/authorization/database-bindings.d.ts.map +1 -0
- package/dist/internal/authorization/database-bindings.js +101 -0
- package/dist/internal/authorization/database-bindings.js.map +1 -0
- package/dist/internal/authorization/database-target.d.ts +75 -0
- package/dist/internal/authorization/database-target.d.ts.map +1 -0
- package/dist/internal/authorization/database-target.js +65 -0
- package/dist/internal/authorization/database-target.js.map +1 -0
- package/dist/internal/authorization/decode.d.ts +1704 -0
- package/dist/internal/authorization/decode.d.ts.map +1 -0
- package/dist/internal/authorization/decode.js +294 -0
- package/dist/internal/authorization/decode.js.map +1 -0
- package/dist/internal/authorization/definitions.d.ts +66 -0
- package/dist/internal/authorization/definitions.d.ts.map +1 -0
- package/dist/internal/authorization/definitions.js +335 -0
- package/dist/internal/authorization/definitions.js.map +1 -0
- package/dist/internal/authorization/deployed.d.ts +43 -0
- package/dist/internal/authorization/deployed.d.ts.map +1 -0
- package/dist/internal/authorization/deployed.js +184 -0
- package/dist/internal/authorization/deployed.js.map +1 -0
- package/dist/internal/authorization/entity-targets.d.ts +68 -0
- package/dist/internal/authorization/entity-targets.d.ts.map +1 -0
- package/dist/internal/authorization/entity-targets.js +244 -0
- package/dist/internal/authorization/entity-targets.js.map +1 -0
- package/dist/internal/authorization/expr.d.ts +259 -0
- package/dist/internal/authorization/expr.d.ts.map +1 -0
- package/dist/internal/authorization/expr.js +55 -0
- package/dist/internal/authorization/expr.js.map +1 -0
- package/dist/internal/authorization/failures.d.ts +78 -0
- package/dist/internal/authorization/failures.d.ts.map +1 -0
- package/dist/internal/authorization/failures.js +22 -0
- package/dist/internal/authorization/failures.js.map +1 -0
- package/dist/internal/authorization/identities.d.ts +207 -0
- package/dist/internal/authorization/identities.d.ts.map +1 -0
- package/dist/internal/authorization/identities.js +71 -0
- package/dist/internal/authorization/identities.js.map +1 -0
- package/dist/internal/authorization/index.d.ts +33 -0
- package/dist/internal/authorization/index.d.ts.map +1 -0
- package/dist/internal/authorization/index.js +33 -0
- package/dist/internal/authorization/index.js.map +1 -0
- package/dist/internal/authorization/install/normalize.d.ts +196 -0
- package/dist/internal/authorization/install/normalize.d.ts.map +1 -0
- package/dist/internal/authorization/install/normalize.js +168 -0
- package/dist/internal/authorization/install/normalize.js.map +1 -0
- package/dist/internal/authorization/install/plan.d.ts +8 -0
- package/dist/internal/authorization/install/plan.d.ts.map +1 -0
- package/dist/internal/authorization/install/plan.js +177 -0
- package/dist/internal/authorization/install/plan.js.map +1 -0
- package/dist/internal/authorization/install.d.ts +404 -0
- package/dist/internal/authorization/install.d.ts.map +1 -0
- package/dist/internal/authorization/install.js +103 -0
- package/dist/internal/authorization/install.js.map +1 -0
- package/dist/internal/authorization/invocation-codec.d.ts +10 -0
- package/dist/internal/authorization/invocation-codec.d.ts.map +1 -0
- package/dist/internal/authorization/invocation-codec.js +36 -0
- package/dist/internal/authorization/invocation-codec.js.map +1 -0
- package/dist/internal/authorization/invocation-receipts.d.ts +192 -0
- package/dist/internal/authorization/invocation-receipts.d.ts.map +1 -0
- package/dist/internal/authorization/invocation-receipts.js +546 -0
- package/dist/internal/authorization/invocation-receipts.js.map +1 -0
- package/dist/internal/authorization/ir.d.ts +1465 -0
- package/dist/internal/authorization/ir.d.ts.map +1 -0
- package/dist/internal/authorization/ir.js +131 -0
- package/dist/internal/authorization/ir.js.map +1 -0
- package/dist/internal/authorization/json.d.ts +8 -0
- package/dist/internal/authorization/json.d.ts.map +1 -0
- package/dist/internal/authorization/json.js +13 -0
- package/dist/internal/authorization/json.js.map +1 -0
- package/dist/internal/authorization/live.d.ts +38 -0
- package/dist/internal/authorization/live.d.ts.map +1 -0
- package/dist/internal/authorization/live.js +227 -0
- package/dist/internal/authorization/live.js.map +1 -0
- package/dist/internal/authorization/operation-grant.d.ts +16 -0
- package/dist/internal/authorization/operation-grant.d.ts.map +1 -0
- package/dist/internal/authorization/operation-grant.js +79 -0
- package/dist/internal/authorization/operation-grant.js.map +1 -0
- package/dist/internal/authorization/operation-version.d.ts +28 -0
- package/dist/internal/authorization/operation-version.d.ts.map +1 -0
- package/dist/internal/authorization/operation-version.js +206 -0
- package/dist/internal/authorization/operation-version.js.map +1 -0
- package/dist/internal/authorization/operations-runtime.d.ts +78 -0
- package/dist/internal/authorization/operations-runtime.d.ts.map +1 -0
- package/dist/internal/authorization/operations-runtime.js +1130 -0
- package/dist/internal/authorization/operations-runtime.js.map +1 -0
- package/dist/internal/authorization/principal.d.ts +95 -0
- package/dist/internal/authorization/principal.d.ts.map +1 -0
- package/dist/internal/authorization/principal.js +53 -0
- package/dist/internal/authorization/principal.js.map +1 -0
- package/dist/internal/authorization/query-view.d.ts +7 -0
- package/dist/internal/authorization/query-view.d.ts.map +1 -0
- package/dist/internal/authorization/query-view.js +17 -0
- package/dist/internal/authorization/query-view.js.map +1 -0
- package/dist/internal/authorization/read-compatibility.d.ts +185 -0
- package/dist/internal/authorization/read-compatibility.d.ts.map +1 -0
- package/dist/internal/authorization/read-compatibility.js +176 -0
- package/dist/internal/authorization/read-compatibility.js.map +1 -0
- package/dist/internal/authorization/read-filter.d.ts +48 -0
- package/dist/internal/authorization/read-filter.d.ts.map +1 -0
- package/dist/internal/authorization/read-filter.js +496 -0
- package/dist/internal/authorization/read-filter.js.map +1 -0
- package/dist/internal/authorization/read-tables.d.ts +9 -0
- package/dist/internal/authorization/read-tables.d.ts.map +1 -0
- package/dist/internal/authorization/read-tables.js +120 -0
- package/dist/internal/authorization/read-tables.js.map +1 -0
- package/dist/internal/authorization/reads.d.ts +36 -0
- package/dist/internal/authorization/reads.d.ts.map +1 -0
- package/dist/internal/authorization/reads.js +35 -0
- package/dist/internal/authorization/reads.js.map +1 -0
- package/dist/internal/authorization/request.d.ts +64 -0
- package/dist/internal/authorization/request.d.ts.map +1 -0
- package/dist/internal/authorization/request.js +210 -0
- package/dist/internal/authorization/request.js.map +1 -0
- package/dist/internal/authorization/truth.d.ts +51 -0
- package/dist/internal/authorization/truth.d.ts.map +1 -0
- package/dist/internal/authorization/truth.js +23 -0
- package/dist/internal/authorization/truth.js.map +1 -0
- package/dist/internal/authorization/validate.d.ts +3 -0
- package/dist/internal/authorization/validate.d.ts.map +1 -0
- package/dist/internal/authorization/validate.js +3 -0
- package/dist/internal/authorization/validate.js.map +1 -0
- package/dist/internal/authorization/validation/catalog.d.ts +32 -0
- package/dist/internal/authorization/validation/catalog.d.ts.map +1 -0
- package/dist/internal/authorization/validation/catalog.js +417 -0
- package/dist/internal/authorization/validation/catalog.js.map +1 -0
- package/dist/internal/authorization/validation/common.d.ts +20 -0
- package/dist/internal/authorization/validation/common.d.ts.map +1 -0
- package/dist/internal/authorization/validation/common.js +36 -0
- package/dist/internal/authorization/validation/common.js.map +1 -0
- package/dist/internal/authorization/validation/decisions.d.ts +7 -0
- package/dist/internal/authorization/validation/decisions.d.ts.map +1 -0
- package/dist/internal/authorization/validation/decisions.js +107 -0
- package/dist/internal/authorization/validation/decisions.js.map +1 -0
- package/dist/internal/authorization/validation/descriptors.d.ts +8 -0
- package/dist/internal/authorization/validation/descriptors.d.ts.map +1 -0
- package/dist/internal/authorization/validation/descriptors.js +24 -0
- package/dist/internal/authorization/validation/descriptors.js.map +1 -0
- package/dist/internal/authorization/validation/expression.d.ts +11 -0
- package/dist/internal/authorization/validation/expression.d.ts.map +1 -0
- package/dist/internal/authorization/validation/expression.js +114 -0
- package/dist/internal/authorization/validation/expression.js.map +1 -0
- package/dist/internal/authorization/validation/traversal.d.ts +19 -0
- package/dist/internal/authorization/validation/traversal.d.ts.map +1 -0
- package/dist/internal/authorization/validation/traversal.js +141 -0
- package/dist/internal/authorization/validation/traversal.js.map +1 -0
- package/dist/internal/authorization/validation/types.d.ts +55 -0
- package/dist/internal/authorization/validation/types.d.ts.map +1 -0
- package/dist/internal/authorization/validation/types.js +184 -0
- package/dist/internal/authorization/validation/types.js.map +1 -0
- package/dist/internal/authorization/validation/validate.d.ts +421 -0
- package/dist/internal/authorization/validation/validate.d.ts.map +1 -0
- package/dist/internal/authorization/validation/validate.js +95 -0
- package/dist/internal/authorization/validation/validate.js.map +1 -0
- package/dist/internal/authorization/version.d.ts +11 -0
- package/dist/internal/authorization/version.d.ts.map +1 -0
- package/dist/internal/authorization/version.js +10 -0
- package/dist/internal/authorization/version.js.map +1 -0
- package/dist/internal/changesets/protocol.d.ts +185 -0
- package/dist/internal/changesets/protocol.d.ts.map +1 -0
- package/dist/internal/changesets/protocol.js +39 -0
- package/dist/internal/changesets/protocol.js.map +1 -0
- package/dist/internal/changesets/service.d.ts +69 -0
- package/dist/internal/changesets/service.d.ts.map +1 -0
- package/dist/internal/changesets/service.js +298 -0
- package/dist/internal/changesets/service.js.map +1 -0
- package/dist/internal/core/bytes.d.ts +41 -0
- package/dist/internal/core/bytes.d.ts.map +1 -0
- package/dist/internal/core/bytes.js +215 -0
- package/dist/internal/core/bytes.js.map +1 -0
- package/dist/internal/core/composition.d.ts +20 -0
- package/dist/internal/core/composition.d.ts.map +1 -0
- package/dist/internal/core/composition.js +52 -0
- package/dist/internal/core/composition.js.map +1 -0
- package/dist/internal/core/conn.d.ts +64 -0
- package/dist/internal/core/conn.d.ts.map +1 -0
- package/dist/internal/core/conn.js +240 -0
- package/dist/internal/core/conn.js.map +1 -0
- package/dist/internal/core/datom.d.ts +73 -0
- package/dist/internal/core/datom.d.ts.map +1 -0
- package/dist/internal/core/datom.js +477 -0
- package/dist/internal/core/datom.js.map +1 -0
- package/dist/internal/core/db.d.ts +65 -0
- package/dist/internal/core/db.d.ts.map +1 -0
- package/dist/internal/core/db.js +261 -0
- package/dist/internal/core/db.js.map +1 -0
- package/dist/internal/core/index.d.ts +21 -0
- package/dist/internal/core/index.d.ts.map +1 -0
- package/dist/internal/core/index.js +21 -0
- package/dist/internal/core/index.js.map +1 -0
- package/dist/internal/core/json.d.ts +5 -0
- package/dist/internal/core/json.d.ts.map +1 -0
- package/dist/internal/core/json.js +56 -0
- package/dist/internal/core/json.js.map +1 -0
- package/dist/internal/core/log.d.ts +68 -0
- package/dist/internal/core/log.d.ts.map +1 -0
- package/dist/internal/core/log.js +76 -0
- package/dist/internal/core/log.js.map +1 -0
- package/dist/internal/core/novelty.d.ts +38 -0
- package/dist/internal/core/novelty.d.ts.map +1 -0
- package/dist/internal/core/novelty.js +300 -0
- package/dist/internal/core/novelty.js.map +1 -0
- package/dist/internal/core/query/ast.d.ts +174 -0
- package/dist/internal/core/query/ast.d.ts.map +1 -0
- package/dist/internal/core/query/ast.js +37 -0
- package/dist/internal/core/query/ast.js.map +1 -0
- package/dist/internal/core/query/builtins.d.ts +19 -0
- package/dist/internal/core/query/builtins.d.ts.map +1 -0
- package/dist/internal/core/query/builtins.js +242 -0
- package/dist/internal/core/query/builtins.js.map +1 -0
- package/dist/internal/core/query/edn.d.ts +19 -0
- package/dist/internal/core/query/edn.d.ts.map +1 -0
- package/dist/internal/core/query/edn.js +248 -0
- package/dist/internal/core/query/edn.js.map +1 -0
- package/dist/internal/core/query/engine.d.ts +56 -0
- package/dist/internal/core/query/engine.d.ts.map +1 -0
- package/dist/internal/core/query/engine.js +0 -0
- package/dist/internal/core/query/engine.js.map +1 -0
- package/dist/internal/core/query/parse.d.ts +8 -0
- package/dist/internal/core/query/parse.d.ts.map +1 -0
- package/dist/internal/core/query/parse.js +606 -0
- package/dist/internal/core/query/parse.js.map +1 -0
- package/dist/internal/core/query/pull.d.ts +7 -0
- package/dist/internal/core/query/pull.d.ts.map +1 -0
- package/dist/internal/core/query/pull.js +304 -0
- package/dist/internal/core/query/pull.js.map +1 -0
- package/dist/internal/core/query/value.d.ts +10 -0
- package/dist/internal/core/query/value.d.ts.map +1 -0
- package/dist/internal/core/query/value.js +21 -0
- package/dist/internal/core/query/value.js.map +1 -0
- package/dist/internal/core/revision.d.ts +19 -0
- package/dist/internal/core/revision.d.ts.map +1 -0
- package/dist/internal/core/revision.js +13 -0
- package/dist/internal/core/revision.js.map +1 -0
- package/dist/internal/core/schema.d.ts +63 -0
- package/dist/internal/core/schema.d.ts.map +1 -0
- package/dist/internal/core/schema.js +228 -0
- package/dist/internal/core/schema.js.map +1 -0
- package/dist/internal/core/segment.d.ts +16 -0
- package/dist/internal/core/segment.d.ts.map +1 -0
- package/dist/internal/core/segment.js +149 -0
- package/dist/internal/core/segment.js.map +1 -0
- package/dist/internal/core/store.d.ts +35 -0
- package/dist/internal/core/store.d.ts.map +1 -0
- package/dist/internal/core/store.js +88 -0
- package/dist/internal/core/store.js.map +1 -0
- package/dist/internal/core/telemetry.d.ts +53 -0
- package/dist/internal/core/telemetry.d.ts.map +1 -0
- package/dist/internal/core/telemetry.js +103 -0
- package/dist/internal/core/telemetry.js.map +1 -0
- package/dist/internal/core/tree.d.ts +60 -0
- package/dist/internal/core/tree.d.ts.map +1 -0
- package/dist/internal/core/tree.js +625 -0
- package/dist/internal/core/tree.js.map +1 -0
- package/dist/internal/core/tx-provenance.d.ts +7 -0
- package/dist/internal/core/tx-provenance.d.ts.map +1 -0
- package/dist/internal/core/tx-provenance.js +16 -0
- package/dist/internal/core/tx-provenance.js.map +1 -0
- package/dist/internal/core/tx.d.ts +51 -0
- package/dist/internal/core/tx.d.ts.map +1 -0
- package/dist/internal/core/tx.js +1029 -0
- package/dist/internal/core/tx.js.map +1 -0
- package/dist/internal/replica/basis.d.ts +15 -0
- package/dist/internal/replica/basis.d.ts.map +1 -0
- package/dist/internal/replica/basis.js +32 -0
- package/dist/internal/replica/basis.js.map +1 -0
- package/dist/internal/replica/errors.d.ts +32 -0
- package/dist/internal/replica/errors.d.ts.map +1 -0
- package/dist/internal/replica/errors.js +30 -0
- package/dist/internal/replica/errors.js.map +1 -0
- package/dist/internal/replica/index.d.ts +4 -0
- package/dist/internal/replica/index.d.ts.map +1 -0
- package/dist/internal/replica/index.js +4 -0
- package/dist/internal/replica/index.js.map +1 -0
- package/dist/internal/replica/replica-do-testing.d.ts +11 -0
- package/dist/internal/replica/replica-do-testing.d.ts.map +1 -0
- package/dist/internal/replica/replica-do-testing.js +340 -0
- package/dist/internal/replica/replica-do-testing.js.map +1 -0
- package/dist/internal/replica/replica-do.d.ts +87 -0
- package/dist/internal/replica/replica-do.d.ts.map +1 -0
- package/dist/internal/replica/replica-do.js +735 -0
- package/dist/internal/replica/replica-do.js.map +1 -0
- package/dist/internal/replica/revision-retention.d.ts +29 -0
- package/dist/internal/replica/revision-retention.d.ts.map +1 -0
- package/dist/internal/replica/revision-retention.js +39 -0
- package/dist/internal/replica/revision-retention.js.map +1 -0
- package/dist/internal/replication/activation-fence.d.ts +40 -0
- package/dist/internal/replication/activation-fence.d.ts.map +1 -0
- package/dist/internal/replication/activation-fence.js +85 -0
- package/dist/internal/replication/activation-fence.js.map +1 -0
- package/dist/internal/replication/digest.d.ts +2 -0
- package/dist/internal/replication/digest.d.ts.map +1 -0
- package/dist/internal/replication/digest.js +12 -0
- package/dist/internal/replication/digest.js.map +1 -0
- package/dist/internal/replication/entity-id.d.ts +23 -0
- package/dist/internal/replication/entity-id.d.ts.map +1 -0
- package/dist/internal/replication/entity-id.js +161 -0
- package/dist/internal/replication/entity-id.js.map +1 -0
- package/dist/internal/replication/idb.d.ts +9 -0
- package/dist/internal/replication/idb.d.ts.map +1 -0
- package/dist/internal/replication/idb.js +46 -0
- package/dist/internal/replication/idb.js.map +1 -0
- package/dist/internal/replication/identity-root.d.ts +11 -0
- package/dist/internal/replication/identity-root.d.ts.map +1 -0
- package/dist/internal/replication/identity-root.js +48 -0
- package/dist/internal/replication/identity-root.js.map +1 -0
- package/dist/internal/replication/identity.d.ts +40 -0
- package/dist/internal/replication/identity.d.ts.map +1 -0
- package/dist/internal/replication/identity.js +95 -0
- package/dist/internal/replication/identity.js.map +1 -0
- package/dist/internal/replication/index.d.ts +13 -0
- package/dist/internal/replication/index.d.ts.map +1 -0
- package/dist/internal/replication/index.js +13 -0
- package/dist/internal/replication/index.js.map +1 -0
- package/dist/internal/replication/indexeddb.d.ts +171 -0
- package/dist/internal/replication/indexeddb.d.ts.map +1 -0
- package/dist/internal/replication/indexeddb.js +1809 -0
- package/dist/internal/replication/indexeddb.js.map +1 -0
- package/dist/internal/replication/leadership.d.ts +36 -0
- package/dist/internal/replication/leadership.d.ts.map +1 -0
- package/dist/internal/replication/leadership.js +108 -0
- package/dist/internal/replication/leadership.js.map +1 -0
- package/dist/internal/replication/logical.d.ts +40 -0
- package/dist/internal/replication/logical.d.ts.map +1 -0
- package/dist/internal/replication/logical.js +375 -0
- package/dist/internal/replication/logical.js.map +1 -0
- package/dist/internal/replication/notices.d.ts +32 -0
- package/dist/internal/replication/notices.d.ts.map +1 -0
- package/dist/internal/replication/notices.js +92 -0
- package/dist/internal/replication/notices.js.map +1 -0
- package/dist/internal/replication/outbox-storage.d.ts +98 -0
- package/dist/internal/replication/outbox-storage.d.ts.map +1 -0
- package/dist/internal/replication/outbox-storage.js +826 -0
- package/dist/internal/replication/outbox-storage.js.map +1 -0
- package/dist/internal/replication/outbox.d.ts +200 -0
- package/dist/internal/replication/outbox.d.ts.map +1 -0
- package/dist/internal/replication/outbox.js +744 -0
- package/dist/internal/replication/outbox.js.map +1 -0
- package/dist/internal/replication/overlay-layers.d.ts +14 -0
- package/dist/internal/replication/overlay-layers.d.ts.map +1 -0
- package/dist/internal/replication/overlay-layers.js +2 -0
- package/dist/internal/replication/overlay-layers.js.map +1 -0
- package/dist/internal/replication/overlay-records.d.ts +61 -0
- package/dist/internal/replication/overlay-records.d.ts.map +1 -0
- package/dist/internal/replication/overlay-records.js +328 -0
- package/dist/internal/replication/overlay-records.js.map +1 -0
- package/dist/internal/replication/overlay.d.ts +20 -0
- package/dist/internal/replication/overlay.d.ts.map +1 -0
- package/dist/internal/replication/overlay.js +159 -0
- package/dist/internal/replication/overlay.js.map +1 -0
- package/dist/internal/replication/projection-binding.d.ts +39 -0
- package/dist/internal/replication/projection-binding.d.ts.map +1 -0
- package/dist/internal/replication/projection-binding.js +76 -0
- package/dist/internal/replication/projection-binding.js.map +1 -0
- package/dist/internal/replication/protocol.d.ts +633 -0
- package/dist/internal/replication/protocol.d.ts.map +1 -0
- package/dist/internal/replication/protocol.js +263 -0
- package/dist/internal/replication/protocol.js.map +1 -0
- package/dist/internal/replication/reconciliation.d.ts +64 -0
- package/dist/internal/replication/reconciliation.d.ts.map +1 -0
- package/dist/internal/replication/reconciliation.js +184 -0
- package/dist/internal/replication/reconciliation.js.map +1 -0
- package/dist/internal/replication/replica-gc.d.ts +42 -0
- package/dist/internal/replication/replica-gc.d.ts.map +1 -0
- package/dist/internal/replication/replica-gc.js +91 -0
- package/dist/internal/replication/replica-gc.js.map +1 -0
- package/dist/internal/replication/replica-integrity.d.ts +107 -0
- package/dist/internal/replication/replica-integrity.d.ts.map +1 -0
- package/dist/internal/replication/replica-integrity.js +418 -0
- package/dist/internal/replication/replica-integrity.js.map +1 -0
- package/dist/internal/replication/replica-lifecycle.d.ts +72 -0
- package/dist/internal/replication/replica-lifecycle.d.ts.map +1 -0
- package/dist/internal/replication/replica-lifecycle.js +126 -0
- package/dist/internal/replication/replica-lifecycle.js.map +1 -0
- package/dist/internal/replication/replica-schema.d.ts +27 -0
- package/dist/internal/replication/replica-schema.d.ts.map +1 -0
- package/dist/internal/replication/replica-schema.js +130 -0
- package/dist/internal/replication/replica-schema.js.map +1 -0
- package/dist/internal/replication/route-slot.d.ts +9 -0
- package/dist/internal/replication/route-slot.d.ts.map +1 -0
- package/dist/internal/replication/route-slot.js +8 -0
- package/dist/internal/replication/route-slot.js.map +1 -0
- package/dist/internal/replication/server-identity.d.ts +54 -0
- package/dist/internal/replication/server-identity.d.ts.map +1 -0
- package/dist/internal/replication/server-identity.js +68 -0
- package/dist/internal/replication/server-identity.js.map +1 -0
- package/dist/internal/replication/session.d.ts +91 -0
- package/dist/internal/replication/session.d.ts.map +1 -0
- package/dist/internal/replication/session.js +673 -0
- package/dist/internal/replication/session.js.map +1 -0
- package/dist/internal/replication/state.d.ts +34 -0
- package/dist/internal/replication/state.d.ts.map +1 -0
- package/dist/internal/replication/state.js +344 -0
- package/dist/internal/replication/state.js.map +1 -0
- package/dist/internal/replication/submission.d.ts +115 -0
- package/dist/internal/replication/submission.d.ts.map +1 -0
- package/dist/internal/replication/submission.js +266 -0
- package/dist/internal/replication/submission.js.map +1 -0
- package/dist/internal/replication/transport.d.ts +34 -0
- package/dist/internal/replication/transport.d.ts.map +1 -0
- package/dist/internal/replication/transport.js +215 -0
- package/dist/internal/replication/transport.js.map +1 -0
- package/dist/internal/runtime-boundaries.d.ts +8 -0
- package/dist/internal/runtime-boundaries.d.ts.map +1 -0
- package/dist/internal/runtime-boundaries.js +7 -0
- package/dist/internal/runtime-boundaries.js.map +1 -0
- package/dist/internal/storage/index.d.ts +111 -0
- package/dist/internal/storage/index.d.ts.map +1 -0
- package/dist/internal/storage/index.js +288 -0
- package/dist/internal/storage/index.js.map +1 -0
- package/dist/internal/storage/memory.d.ts +31 -0
- package/dist/internal/storage/memory.d.ts.map +1 -0
- package/dist/internal/storage/memory.js +46 -0
- package/dist/internal/storage/memory.js.map +1 -0
- package/dist/internal/storage/revisions.d.ts +24 -0
- package/dist/internal/storage/revisions.d.ts.map +1 -0
- package/dist/internal/storage/revisions.js +74 -0
- package/dist/internal/storage/revisions.js.map +1 -0
- package/dist/internal/test-hooks.d.ts +47 -0
- package/dist/internal/test-hooks.d.ts.map +1 -0
- package/dist/internal/test-hooks.js +256 -0
- package/dist/internal/test-hooks.js.map +1 -0
- package/dist/internal/transactor/env.d.ts +3 -0
- package/dist/internal/transactor/env.d.ts.map +1 -0
- package/dist/internal/transactor/env.js +5 -0
- package/dist/internal/transactor/env.js.map +1 -0
- package/dist/internal/transactor/errors.d.ts +47 -0
- package/dist/internal/transactor/errors.d.ts.map +1 -0
- package/dist/internal/transactor/errors.js +66 -0
- package/dist/internal/transactor/errors.js.map +1 -0
- package/dist/internal/transactor/host.d.ts +37 -0
- package/dist/internal/transactor/host.d.ts.map +1 -0
- package/dist/internal/transactor/host.js +11 -0
- package/dist/internal/transactor/host.js.map +1 -0
- package/dist/internal/transactor/index.d.ts +8 -0
- package/dist/internal/transactor/index.d.ts.map +1 -0
- package/dist/internal/transactor/index.js +8 -0
- package/dist/internal/transactor/index.js.map +1 -0
- package/dist/internal/transactor/indexer.d.ts +53 -0
- package/dist/internal/transactor/indexer.d.ts.map +1 -0
- package/dist/internal/transactor/indexer.js +125 -0
- package/dist/internal/transactor/indexer.js.map +1 -0
- package/dist/internal/transactor/internal.d.ts +8 -0
- package/dist/internal/transactor/internal.d.ts.map +1 -0
- package/dist/internal/transactor/internal.js +28 -0
- package/dist/internal/transactor/internal.js.map +1 -0
- package/dist/internal/transactor/observability.d.ts +44 -0
- package/dist/internal/transactor/observability.d.ts.map +1 -0
- package/dist/internal/transactor/observability.js +39 -0
- package/dist/internal/transactor/observability.js.map +1 -0
- package/dist/internal/transactor/transactor-do.d.ts +35 -0
- package/dist/internal/transactor/transactor-do.d.ts.map +1 -0
- package/dist/internal/transactor/transactor-do.js +198 -0
- package/dist/internal/transactor/transactor-do.js.map +1 -0
- package/dist/internal/transactor/transactor.d.ts +209 -0
- package/dist/internal/transactor/transactor.d.ts.map +1 -0
- package/dist/internal/transactor/transactor.js +1166 -0
- package/dist/internal/transactor/transactor.js.map +1 -0
- package/dist/mcp/contract.d.ts +49 -0
- package/dist/mcp/contract.d.ts.map +1 -0
- package/dist/mcp/contract.js +199 -0
- package/dist/mcp/contract.js.map +1 -0
- package/dist/mcp/kernel.d.ts +56 -0
- package/dist/mcp/kernel.d.ts.map +1 -0
- package/dist/mcp/kernel.js +344 -0
- package/dist/mcp/kernel.js.map +1 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +182 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/peer.d.ts +175 -0
- package/dist/peer.d.ts.map +1 -0
- package/dist/peer.js +200 -0
- package/dist/peer.js.map +1 -0
- package/dist/react/hooks.d.ts +157 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +130 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/query-state.d.ts +60 -0
- package/dist/react/query-state.d.ts.map +1 -0
- package/dist/react/query-state.js +48 -0
- package/dist/react/query-state.js.map +1 -0
- package/dist/react/receipt-state.d.ts +27 -0
- package/dist/react/receipt-state.d.ts.map +1 -0
- package/dist/react/receipt-state.js +2 -0
- package/dist/react/receipt-state.js.map +1 -0
- package/dist/react/store.d.ts +30 -0
- package/dist/react/store.d.ts.map +1 -0
- package/dist/react/store.js +118 -0
- package/dist/react/store.js.map +1 -0
- package/dist/react/suspense.d.ts +6 -0
- package/dist/react/suspense.d.ts.map +1 -0
- package/dist/react/suspense.js +111 -0
- package/dist/react/suspense.js.map +1 -0
- package/dist/worker/admit.d.ts +9 -0
- package/dist/worker/admit.d.ts.map +1 -0
- package/dist/worker/admit.js +43 -0
- package/dist/worker/admit.js.map +1 -0
- package/dist/worker/analytics.d.ts +39 -0
- package/dist/worker/analytics.d.ts.map +1 -0
- package/dist/worker/analytics.js +54 -0
- package/dist/worker/analytics.js.map +1 -0
- package/dist/worker/auth.d.ts +26 -0
- package/dist/worker/auth.d.ts.map +1 -0
- package/dist/worker/auth.js +2 -0
- package/dist/worker/auth.js.map +1 -0
- package/dist/worker/authorized-live.d.ts +15 -0
- package/dist/worker/authorized-live.d.ts.map +1 -0
- package/dist/worker/authorized-live.js +30 -0
- package/dist/worker/authorized-live.js.map +1 -0
- package/dist/worker/authorized-operation.d.ts +30 -0
- package/dist/worker/authorized-operation.d.ts.map +1 -0
- package/dist/worker/authorized-operation.js +304 -0
- package/dist/worker/authorized-operation.js.map +1 -0
- package/dist/worker/authorized-read.d.ts +32 -0
- package/dist/worker/authorized-read.d.ts.map +1 -0
- package/dist/worker/authorized-read.js +194 -0
- package/dist/worker/authorized-read.js.map +1 -0
- package/dist/worker/authorized-replication.d.ts +21 -0
- package/dist/worker/authorized-replication.d.ts.map +1 -0
- package/dist/worker/authorized-replication.js +593 -0
- package/dist/worker/authorized-replication.js.map +1 -0
- package/dist/worker/changesets.d.ts +9 -0
- package/dist/worker/changesets.d.ts.map +1 -0
- package/dist/worker/changesets.js +105 -0
- package/dist/worker/changesets.js.map +1 -0
- package/dist/worker/demo.d.ts +2 -0
- package/dist/worker/demo.d.ts.map +1 -0
- package/dist/worker/demo.js +85 -0
- package/dist/worker/demo.js.map +1 -0
- package/dist/worker/errors.d.ts +53 -0
- package/dist/worker/errors.d.ts.map +1 -0
- package/dist/worker/errors.js +107 -0
- package/dist/worker/errors.js.map +1 -0
- package/dist/worker/handle.d.ts +21 -0
- package/dist/worker/handle.d.ts.map +1 -0
- package/dist/worker/handle.js +386 -0
- package/dist/worker/handle.js.map +1 -0
- package/dist/worker/index.d.ts +27 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +24 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/jwt.d.ts +23 -0
- package/dist/worker/jwt.d.ts.map +1 -0
- package/dist/worker/jwt.js +288 -0
- package/dist/worker/jwt.js.map +1 -0
- package/dist/worker/mcp.d.ts +17 -0
- package/dist/worker/mcp.d.ts.map +1 -0
- package/dist/worker/mcp.js +151 -0
- package/dist/worker/mcp.js.map +1 -0
- package/dist/worker/operation-catalogs.d.ts +38 -0
- package/dist/worker/operation-catalogs.d.ts.map +1 -0
- package/dist/worker/operation-catalogs.js +114 -0
- package/dist/worker/operation-catalogs.js.map +1 -0
- package/dist/worker/peer.d.ts +70 -0
- package/dist/worker/peer.d.ts.map +1 -0
- package/dist/worker/peer.js +330 -0
- package/dist/worker/peer.js.map +1 -0
- package/dist/worker/public-observation.d.ts +15 -0
- package/dist/worker/public-observation.d.ts.map +1 -0
- package/dist/worker/public-observation.js +111 -0
- package/dist/worker/public-observation.js.map +1 -0
- package/dist/worker/server-identity.d.ts +2 -0
- package/dist/worker/server-identity.d.ts.map +1 -0
- package/dist/worker/server-identity.js +2 -0
- package/dist/worker/server-identity.js.map +1 -0
- package/dist/worker/session-sync.d.ts +27 -0
- package/dist/worker/session-sync.d.ts.map +1 -0
- package/dist/worker/session-sync.js +4 -0
- package/dist/worker/session-sync.js.map +1 -0
- package/dist/worker/session.d.ts +144 -0
- package/dist/worker/session.d.ts.map +1 -0
- package/dist/worker/session.js +408 -0
- package/dist/worker/session.js.map +1 -0
- package/dist/worker/storage-test-admin.d.ts +3 -0
- package/dist/worker/storage-test-admin.d.ts.map +1 -0
- package/dist/worker/storage-test-admin.js +277 -0
- package/dist/worker/storage-test-admin.js.map +1 -0
- package/dist/worker/test-admin.d.ts +11 -0
- package/dist/worker/test-admin.d.ts.map +1 -0
- package/dist/worker/test-admin.js +432 -0
- package/dist/worker/test-admin.js.map +1 -0
- package/dist/worker/testing.d.ts +14 -0
- package/dist/worker/testing.d.ts.map +1 -0
- package/dist/worker/testing.js +71 -0
- package/dist/worker/testing.js.map +1 -0
- package/dist/workerEntry.d.ts +2 -0
- package/dist/workerEntry.d.ts.map +1 -0
- package/dist/workerEntry.js +10 -0
- package/dist/workerEntry.js.map +1 -0
- package/dist/writes.d.ts +8 -0
- package/dist/writes.d.ts.map +1 -0
- package/dist/writes.js +11 -0
- package/dist/writes.js.map +1 -0
- package/package.json +104 -4
|
@@ -0,0 +1,1809 @@
|
|
|
1
|
+
import * as Result from "effect/Result";
|
|
2
|
+
import { ALL_INDEXES } from "../core/datom.js";
|
|
3
|
+
import { buildRoots } from "../core/conn.js";
|
|
4
|
+
import { sha256Hex } from "../core/bytes.js";
|
|
5
|
+
import { Db, rootFor } from "../core/db.js";
|
|
6
|
+
import { Novelty } from "../core/novelty.js";
|
|
7
|
+
import { FIRST_USER_EID, Schema } from "../core/schema.js";
|
|
8
|
+
import { deserializeNode, gzipCodec, serializeNode } from "../core/store.js";
|
|
9
|
+
import { decodeNode, NodeKind, } from "../core/tree.js";
|
|
10
|
+
import { inertRuntimeBoundaries, } from "../runtime-boundaries.js";
|
|
11
|
+
import { isReplicationOrdinal, REPLICA_STORAGE_VERSION, REPLICATION_PROTOCOL_VERSION, } from "./protocol.js";
|
|
12
|
+
import { replicaAttributeDatoms, replicaAttributes, replicaBootstrapDatoms, replicaFactDatom, sameReplicaAttributes, } from "./replica-schema.js";
|
|
13
|
+
import { abortTransaction, abortWithSignal, commitTransaction, compoundPrefixRange, prefixRange, requestResult, transactionDone, } from "./idb.js";
|
|
14
|
+
import { clearMutationScope, createMutationStores, IndexedDbOutbox, MUTATION_STORE_FAMILIES, } from "./outbox-storage.js";
|
|
15
|
+
import { classifyReplicaStorageFailure, replicaQuotaRecovery, replicaSweepKey, replicaSweepPrefix, ReplicaQuotaExhaustedError, ReplicaReachability, stagingIsSweepable, supersededPartitions, unreachableNodeHashes, } from "./replica-gc.js";
|
|
16
|
+
import { identityNotice, platformBroadcast, replicaNotice, replicaNoticeChannelName, ReplicaNoticeChannel, } from "./notices.js";
|
|
17
|
+
import { identityInDatabase, identityInScope, REPLICA_CLEAR_BARRIER_KEY, REPLICA_COMMITTED_HEADS_STORE, REPLICA_GENERATIONS_STORE, replicaDatabaseKey, replicaDatabasePartitionPrefix, replicaDatabaseScopeOf, replicaPartitionKey, replicaPartitionScopeKey, replicaScopeKey, replicaScopeOf, replicaScopePartitionPrefix, withConfirmedScope, withoutConfirmedScope, ReplicaDatabaseActiveError, ReplicaFencedError, ReplicaLease, ReplicaScopeClearedError, ReplicaScopeUnconfirmedError, } from "./replica-lifecycle.js";
|
|
18
|
+
import { digestReplicaDatoms, emptyReplicaIndexDigest, expectedReplicaContents, replicaAbsent, replicaContended, ReplicaSupersededError, replicaManifestFingerprint, replicaManifestIdentity, replicaRestored, replicaUnusable, restoredReplica, validateReplicaContents, validateReplicaManifest, validateReplicaNode, } from "./replica-integrity.js";
|
|
19
|
+
import { applyReplicationFrame, emptyClientReplicationState, ReplicationTransitionError, sameReplicationIdentity, } from "./state.js";
|
|
20
|
+
const STORAGE_V2_DATABASE_VERSION = 5;
|
|
21
|
+
const LIFECYCLE_DATABASE_VERSION = 6;
|
|
22
|
+
const MUTATION_INDEX_DATABASE_VERSION = 9;
|
|
23
|
+
const OPTIMISTIC_LAYER_DATABASE_VERSION = 10;
|
|
24
|
+
export const REPLICA_MANIFEST_STORAGE_VERSION = OPTIMISTIC_LAYER_DATABASE_VERSION + 1;
|
|
25
|
+
const MANIFEST_V3_DATABASE_VERSION = REPLICA_MANIFEST_STORAGE_VERSION;
|
|
26
|
+
const DATABASE_ROUTE_DATABASE_VERSION = MANIFEST_V3_DATABASE_VERSION + 1;
|
|
27
|
+
const MANIFEST_V4_DATABASE_VERSION = DATABASE_ROUTE_DATABASE_VERSION + 1;
|
|
28
|
+
const MANIFEST_V5_DATABASE_VERSION = MANIFEST_V4_DATABASE_VERSION + 1;
|
|
29
|
+
export const REPLICA_DATABASE_VERSION = MANIFEST_V5_DATABASE_VERSION;
|
|
30
|
+
const DATABASE_VERSION = REPLICA_DATABASE_VERSION;
|
|
31
|
+
const COMMITTED = "replica-committed-v1";
|
|
32
|
+
const COMMITTED_HEADS = REPLICA_COMMITTED_HEADS_STORE;
|
|
33
|
+
const STAGING = "replica-staging-v1";
|
|
34
|
+
const STAGING_CHUNKS = "replica-staging-chunks-v1";
|
|
35
|
+
const NODES = "replica-nodes-v1";
|
|
36
|
+
const CREDENTIAL_BINDINGS = "replica-credential-bindings-v1";
|
|
37
|
+
const CACHE_CANDIDATES = "replica-cache-candidates-v1";
|
|
38
|
+
const ROUTE_SLOTS = "replica-route-slots-v1";
|
|
39
|
+
const GENERATIONS = REPLICA_GENERATIONS_STORE;
|
|
40
|
+
const USER_T = 2;
|
|
41
|
+
const REPLICA_STORE_FAMILIES = [
|
|
42
|
+
COMMITTED,
|
|
43
|
+
COMMITTED_HEADS,
|
|
44
|
+
STAGING,
|
|
45
|
+
STAGING_CHUNKS,
|
|
46
|
+
NODES,
|
|
47
|
+
CREDENTIAL_BINDINGS,
|
|
48
|
+
CACHE_CANDIDATES,
|
|
49
|
+
ROUTE_SLOTS,
|
|
50
|
+
GENERATIONS,
|
|
51
|
+
];
|
|
52
|
+
const REPLICA_VALUE_FAMILIES = REPLICA_STORE_FAMILIES.filter((family) => family !== GENERATIONS);
|
|
53
|
+
const STORAGE_V2_SWEEP_PREFIX = "ramose-replica-sweep-v2:";
|
|
54
|
+
const PARTITION_KEYED_FAMILIES = [COMMITTED, COMMITTED_HEADS, STAGING];
|
|
55
|
+
const PARTITION_PREFIXED_FAMILIES = [STAGING_CHUNKS, NODES];
|
|
56
|
+
const IDENTITY_KEYED_FAMILIES = [CREDENTIAL_BINDINGS, CACHE_CANDIDATES];
|
|
57
|
+
export const DEFAULT_REPLICA_DATABASE_NAME = "ramose-replicas";
|
|
58
|
+
export { replicaPartitionKey } from "./replica-lifecycle.js";
|
|
59
|
+
export { ReplicaQuotaExhaustedError, replicaSweepKey, } from "./replica-gc.js";
|
|
60
|
+
class WriteMeter {
|
|
61
|
+
nodes = 0;
|
|
62
|
+
manifests = 0;
|
|
63
|
+
heads = 0;
|
|
64
|
+
staging = 0;
|
|
65
|
+
stagingChunks = 0;
|
|
66
|
+
counts() {
|
|
67
|
+
return Object.freeze({
|
|
68
|
+
nodes: this.nodes,
|
|
69
|
+
manifests: this.manifests,
|
|
70
|
+
heads: this.heads,
|
|
71
|
+
staging: this.staging,
|
|
72
|
+
stagingChunks: this.stagingChunks,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
reset() {
|
|
76
|
+
this.nodes = 0;
|
|
77
|
+
this.manifests = 0;
|
|
78
|
+
this.heads = 0;
|
|
79
|
+
this.staging = 0;
|
|
80
|
+
this.stagingChunks = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const committedHead = (record) => ({
|
|
84
|
+
partition: record.partition,
|
|
85
|
+
storageVersion: record.storageVersion,
|
|
86
|
+
identity: record.identity,
|
|
87
|
+
readCompatibilityHash: record.readCompatibilityHash,
|
|
88
|
+
revision: record.revision,
|
|
89
|
+
ordinal: record.ordinal,
|
|
90
|
+
});
|
|
91
|
+
const recordOrdinal = (record) => {
|
|
92
|
+
const ordinal = record?.ordinal;
|
|
93
|
+
return isReplicationOrdinal(ordinal) ? ordinal : undefined;
|
|
94
|
+
};
|
|
95
|
+
const storedOrdinal = (head, manifest) => recordOrdinal(head) ?? recordOrdinal(manifest);
|
|
96
|
+
const supersedesStoredHead = (stored, candidate) => stored === undefined || candidate.ordinal >= stored;
|
|
97
|
+
const LIFECYCLE_REGISTRIES = new Map();
|
|
98
|
+
const confirmationRecords = (identity, confirmedAt) => {
|
|
99
|
+
const scope = replicaScopeKey(replicaScopeOf(identity));
|
|
100
|
+
return [
|
|
101
|
+
{ key: scope, kind: "scope", scope, generation: 1, confirmedAt, fencedAt: null },
|
|
102
|
+
{
|
|
103
|
+
key: replicaDatabaseKey(replicaDatabaseScopeOf(identity)),
|
|
104
|
+
kind: "database",
|
|
105
|
+
scope,
|
|
106
|
+
generation: 1,
|
|
107
|
+
confirmedAt,
|
|
108
|
+
fencedAt: null,
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
};
|
|
112
|
+
const seedConfirmedGenerations = (upgrade) => {
|
|
113
|
+
const generations = upgrade.objectStore(GENERATIONS);
|
|
114
|
+
const confirmedAt = Date.now();
|
|
115
|
+
const scopes = new Set();
|
|
116
|
+
for (const family of [COMMITTED, ...IDENTITY_KEYED_FAMILIES]) {
|
|
117
|
+
const request = upgrade.objectStore(family).getAll();
|
|
118
|
+
request.addEventListener("success", () => {
|
|
119
|
+
const records = request.result;
|
|
120
|
+
for (const record of records) {
|
|
121
|
+
scopes.add(replicaScopeKey(replicaScopeOf(record.identity)));
|
|
122
|
+
for (const seeded of confirmationRecords(record.identity, confirmedAt)) {
|
|
123
|
+
generations.put(seeded);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}, { once: true });
|
|
127
|
+
}
|
|
128
|
+
const routes = upgrade.objectStore(ROUTE_SLOTS);
|
|
129
|
+
const observed = routes.getAll();
|
|
130
|
+
observed.addEventListener("success", () => {
|
|
131
|
+
const owners = [...scopes].sort();
|
|
132
|
+
for (const record of observed.result) {
|
|
133
|
+
if (record.replicaScopes !== undefined)
|
|
134
|
+
continue;
|
|
135
|
+
if (owners.length === 0)
|
|
136
|
+
routes.delete([record.scope, record.pathKey]);
|
|
137
|
+
else
|
|
138
|
+
routes.put({ ...record, replicaScopes: owners });
|
|
139
|
+
}
|
|
140
|
+
}, { once: true });
|
|
141
|
+
};
|
|
142
|
+
const lifecycleRegistry = (name) => {
|
|
143
|
+
const existing = LIFECYCLE_REGISTRIES.get(name);
|
|
144
|
+
if (existing !== undefined)
|
|
145
|
+
return existing;
|
|
146
|
+
const created = {
|
|
147
|
+
pins: new Map(),
|
|
148
|
+
participants: new Set(),
|
|
149
|
+
retained: new Map(),
|
|
150
|
+
materializing: new Map(),
|
|
151
|
+
};
|
|
152
|
+
LIFECYCLE_REGISTRIES.set(name, created);
|
|
153
|
+
return created;
|
|
154
|
+
};
|
|
155
|
+
const chunkRange = (partition) => IDBKeyRange.bound([partition, 0], [partition, Number.MAX_SAFE_INTEGER]);
|
|
156
|
+
const sameJson = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
157
|
+
const transition = (state, frame) => {
|
|
158
|
+
const result = applyReplicationFrame(state, frame);
|
|
159
|
+
if (Result.isFailure(result))
|
|
160
|
+
throw result.failure;
|
|
161
|
+
return result.success;
|
|
162
|
+
};
|
|
163
|
+
const rootHashes = (roots) => ALL_INDEXES.map((index) => rootFor(roots, index).hash);
|
|
164
|
+
const replicaFence = (lease, identity) => lease === undefined ? undefined : {
|
|
165
|
+
lease,
|
|
166
|
+
scopeKey: replicaScopeKey(replicaScopeOf(identity)),
|
|
167
|
+
databaseKey: replicaDatabaseKey(replicaDatabaseScopeOf(identity)),
|
|
168
|
+
};
|
|
169
|
+
const enforceFence = async (transaction, fence) => {
|
|
170
|
+
if (fence === undefined)
|
|
171
|
+
return;
|
|
172
|
+
const generations = transaction.objectStore(GENERATIONS);
|
|
173
|
+
const [scope, database] = await Promise.all([
|
|
174
|
+
requestResult(generations.get(fence.scopeKey)),
|
|
175
|
+
requestResult(generations.get(fence.databaseKey)),
|
|
176
|
+
]);
|
|
177
|
+
try {
|
|
178
|
+
fence.lease.observe(fence.scopeKey, scope?.generation ?? 0);
|
|
179
|
+
fence.lease.observe(fence.databaseKey, database?.generation ?? 0);
|
|
180
|
+
fence.lease.admit(fence.scopeKey, scope?.clearedAt ?? 0);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
await abortTransaction(transaction);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
class IndexedDbNodeStore {
|
|
188
|
+
database;
|
|
189
|
+
partition;
|
|
190
|
+
signal;
|
|
191
|
+
fence;
|
|
192
|
+
meter;
|
|
193
|
+
constructor(database, partition, signal, fence, meter) {
|
|
194
|
+
this.database = database;
|
|
195
|
+
this.partition = partition;
|
|
196
|
+
this.signal = signal;
|
|
197
|
+
this.fence = fence;
|
|
198
|
+
this.meter = meter;
|
|
199
|
+
}
|
|
200
|
+
peek(_hash) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
async load(ref) {
|
|
204
|
+
this.signal?.throwIfAborted();
|
|
205
|
+
const transaction = this.database.transaction(NODES, "readonly");
|
|
206
|
+
const record = await requestResult(transaction.objectStore(NODES).get([this.partition, ref.hash]));
|
|
207
|
+
await transactionDone(transaction);
|
|
208
|
+
if (record === undefined)
|
|
209
|
+
throw new Error(`missing replica node ${ref.hash}`);
|
|
210
|
+
return deserializeNode(record.body, gzipCodec);
|
|
211
|
+
}
|
|
212
|
+
async put(index, node) {
|
|
213
|
+
this.signal?.throwIfAborted();
|
|
214
|
+
const { ref, body } = await serializeNode(index, node, gzipCodec);
|
|
215
|
+
this.signal?.throwIfAborted();
|
|
216
|
+
const transaction = this.database.transaction(this.fence === undefined ? [NODES] : [NODES, GENERATIONS], "readwrite");
|
|
217
|
+
await enforceFence(transaction, this.fence);
|
|
218
|
+
transaction.objectStore(NODES).put({
|
|
219
|
+
partition: this.partition,
|
|
220
|
+
hash: ref.hash,
|
|
221
|
+
body,
|
|
222
|
+
});
|
|
223
|
+
await commitTransaction(transaction);
|
|
224
|
+
if (this.meter !== undefined)
|
|
225
|
+
this.meter.nodes++;
|
|
226
|
+
return ref;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const newInstallId = () => {
|
|
230
|
+
const bytes = new Uint8Array(16);
|
|
231
|
+
crypto.getRandomValues(bytes);
|
|
232
|
+
let hex = "";
|
|
233
|
+
for (const byte of bytes)
|
|
234
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
235
|
+
return hex;
|
|
236
|
+
};
|
|
237
|
+
const materialize = async (database, identity, committed, attributes, prior, signal, fence, meter) => {
|
|
238
|
+
signal?.throwIfAborted();
|
|
239
|
+
const partition = replicaPartitionKey(identity);
|
|
240
|
+
const specs = replicaAttributes(attributes);
|
|
241
|
+
if (prior !== undefined && !sameReplicaAttributes(prior.attributes, specs)) {
|
|
242
|
+
throw new Error("replica attribute metadata changed within one committed read view");
|
|
243
|
+
}
|
|
244
|
+
const attributeIds = new Map(prior?.attributeIds ?? []);
|
|
245
|
+
const entities = new Map(prior?.entityIds ?? []);
|
|
246
|
+
let nextLocalId = prior?.nextLocalId ?? FIRST_USER_EID;
|
|
247
|
+
const schemaDatoms = [];
|
|
248
|
+
const bootstrap = Schema.bootstrap();
|
|
249
|
+
for (const spec of specs) {
|
|
250
|
+
const builtIn = bootstrap.attr(spec.ident);
|
|
251
|
+
let id = builtIn?.id ?? attributeIds.get(spec.ident);
|
|
252
|
+
if (id === undefined) {
|
|
253
|
+
id = nextLocalId++;
|
|
254
|
+
attributeIds.set(spec.ident, id);
|
|
255
|
+
}
|
|
256
|
+
if (builtIn === undefined)
|
|
257
|
+
schemaDatoms.push(...replicaAttributeDatoms(id, spec, USER_T));
|
|
258
|
+
}
|
|
259
|
+
const logicalEntities = new Set();
|
|
260
|
+
for (const datom of committed.datoms) {
|
|
261
|
+
logicalEntities.add(datom.entity);
|
|
262
|
+
if (datom.value.type === "ref")
|
|
263
|
+
logicalEntities.add(datom.value.value);
|
|
264
|
+
}
|
|
265
|
+
for (const entity of [...logicalEntities].sort()) {
|
|
266
|
+
if (!entities.has(entity))
|
|
267
|
+
entities.set(entity, nextLocalId++);
|
|
268
|
+
}
|
|
269
|
+
const facts = [];
|
|
270
|
+
const schema = bootstrap.clone().apply(schemaDatoms);
|
|
271
|
+
for (const logical of committed.datoms) {
|
|
272
|
+
const fact = replicaFactDatom(logical, schema, entities);
|
|
273
|
+
if (typeof fact === "string") {
|
|
274
|
+
throw new Error(fact === "value-type"
|
|
275
|
+
? `logical value type disagrees with ${logical.field}`
|
|
276
|
+
: `logical fact references unknown field ${logical.field}`);
|
|
277
|
+
}
|
|
278
|
+
facts.push(fact);
|
|
279
|
+
}
|
|
280
|
+
const store = new IndexedDbNodeStore(database, partition, signal, fence, meter);
|
|
281
|
+
const roots = await buildRoots(store, schema, replicaBootstrapDatoms().concat(schemaDatoms, facts));
|
|
282
|
+
signal?.throwIfAborted();
|
|
283
|
+
const record = {
|
|
284
|
+
partition,
|
|
285
|
+
storageVersion: REPLICA_STORAGE_VERSION,
|
|
286
|
+
identity,
|
|
287
|
+
readCompatibilityHash: identity.readCompatibilityHash,
|
|
288
|
+
revision: committed.revision,
|
|
289
|
+
ordinal: committed.ordinal,
|
|
290
|
+
datoms: Object.freeze([...committed.datoms]),
|
|
291
|
+
attributes: Object.freeze(specs),
|
|
292
|
+
entityIds: Object.freeze([...entities]),
|
|
293
|
+
entityHandles: Object.freeze([...entities.keys()].flatMap((entity) => {
|
|
294
|
+
const handle = committed.handles.get(entity);
|
|
295
|
+
return handle === undefined
|
|
296
|
+
? []
|
|
297
|
+
: [Object.freeze([entity, handle])];
|
|
298
|
+
})),
|
|
299
|
+
attributeIds: Object.freeze([...attributeIds]),
|
|
300
|
+
roots,
|
|
301
|
+
nextLocalId,
|
|
302
|
+
installId: newInstallId(),
|
|
303
|
+
};
|
|
304
|
+
return {
|
|
305
|
+
record,
|
|
306
|
+
db: new Db({
|
|
307
|
+
store: new IndexedDbNodeStore(database, partition),
|
|
308
|
+
roots,
|
|
309
|
+
novelty: new Novelty(),
|
|
310
|
+
basisT: roots.t,
|
|
311
|
+
schema,
|
|
312
|
+
nextEid: nextLocalId,
|
|
313
|
+
}),
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
const recordHandles = (record) => {
|
|
317
|
+
const entities = new Map(record.entityIds);
|
|
318
|
+
const handles = new Map();
|
|
319
|
+
for (const [identity, handle] of record.entityHandles) {
|
|
320
|
+
const eid = entities.get(identity);
|
|
321
|
+
if (eid !== undefined)
|
|
322
|
+
handles.set(handle, eid);
|
|
323
|
+
}
|
|
324
|
+
return handles;
|
|
325
|
+
};
|
|
326
|
+
const dbFromRecord = (database, record, expected) => {
|
|
327
|
+
if (record.readCompatibilityHash !== expected ||
|
|
328
|
+
record.identity.readCompatibilityHash !== expected) {
|
|
329
|
+
throw new Error("replica read compatibility is not confirmed for this client");
|
|
330
|
+
}
|
|
331
|
+
const schemaDatoms = [];
|
|
332
|
+
const bootstrap = Schema.bootstrap();
|
|
333
|
+
const attributeIds = new Map(record.attributeIds);
|
|
334
|
+
for (const spec of record.attributes) {
|
|
335
|
+
const builtIn = bootstrap.attr(spec.ident);
|
|
336
|
+
const id = builtIn?.id ?? attributeIds.get(spec.ident);
|
|
337
|
+
if (id === undefined)
|
|
338
|
+
throw new Error(`missing local attribute id for ${spec.ident}`);
|
|
339
|
+
if (builtIn === undefined)
|
|
340
|
+
schemaDatoms.push(...replicaAttributeDatoms(id, spec, USER_T));
|
|
341
|
+
}
|
|
342
|
+
const schema = bootstrap.clone().apply(schemaDatoms);
|
|
343
|
+
return new Db({
|
|
344
|
+
store: new IndexedDbNodeStore(database, record.partition),
|
|
345
|
+
roots: record.roots,
|
|
346
|
+
novelty: new Novelty(),
|
|
347
|
+
basisT: record.roots.t,
|
|
348
|
+
schema,
|
|
349
|
+
nextEid: record.nextLocalId,
|
|
350
|
+
});
|
|
351
|
+
};
|
|
352
|
+
const VALIDATION_BATCH = 32;
|
|
353
|
+
const readNodeRecords = async (database, partition, hashes) => {
|
|
354
|
+
const transaction = database.transaction(NODES, "readonly");
|
|
355
|
+
const store = transaction.objectStore(NODES);
|
|
356
|
+
const pending = hashes.map((hash) => requestResult(store.get([partition, hash])));
|
|
357
|
+
const records = await Promise.all(pending);
|
|
358
|
+
await transactionDone(transaction);
|
|
359
|
+
return records;
|
|
360
|
+
};
|
|
361
|
+
const verifyNodeRecord = async (index, ref, record, expectedKey) => {
|
|
362
|
+
const located = { index, hash: ref.hash };
|
|
363
|
+
if (record === undefined) {
|
|
364
|
+
return { reason: "node-missing", detail: "referenced node is not stored", ...located };
|
|
365
|
+
}
|
|
366
|
+
if (!(record.body instanceof Uint8Array)) {
|
|
367
|
+
return { reason: "node-undecodable", detail: "node record carries no body", ...located };
|
|
368
|
+
}
|
|
369
|
+
if (await sha256Hex(record.body) !== ref.hash) {
|
|
370
|
+
return { reason: "node-hash", detail: "node body does not hash to its address", ...located };
|
|
371
|
+
}
|
|
372
|
+
let decoded;
|
|
373
|
+
try {
|
|
374
|
+
decoded = decodeNode(await gzipCodec.decompress(record.body));
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return { reason: "node-undecodable", detail: "node body cannot be decoded", ...located };
|
|
378
|
+
}
|
|
379
|
+
return validateReplicaNode(index, ref, decoded, expectedKey) ?? decoded;
|
|
380
|
+
};
|
|
381
|
+
const validateReachableNodes = async (database, manifest, reached) => {
|
|
382
|
+
const seen = reached ?? new Set();
|
|
383
|
+
const expected = expectedReplicaContents(manifest);
|
|
384
|
+
if (Result.isFailure(expected))
|
|
385
|
+
return expected.failure;
|
|
386
|
+
const digests = {
|
|
387
|
+
0: emptyReplicaIndexDigest(),
|
|
388
|
+
1: emptyReplicaIndexDigest(),
|
|
389
|
+
2: emptyReplicaIndexDigest(),
|
|
390
|
+
3: emptyReplicaIndexDigest(),
|
|
391
|
+
};
|
|
392
|
+
for (const index of ALL_INDEXES) {
|
|
393
|
+
const digest = digests[index];
|
|
394
|
+
const frontier = [{ ref: rootFor(manifest.roots, index) }];
|
|
395
|
+
while (frontier.length > 0) {
|
|
396
|
+
const batch = [];
|
|
397
|
+
while (batch.length < VALIDATION_BATCH && frontier.length > 0) {
|
|
398
|
+
const pending = frontier.pop();
|
|
399
|
+
if (seen.has(pending.ref.hash)) {
|
|
400
|
+
return {
|
|
401
|
+
reason: "node-invariant",
|
|
402
|
+
detail: "one node is linked from more than one place",
|
|
403
|
+
index,
|
|
404
|
+
hash: pending.ref.hash,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
seen.add(pending.ref.hash);
|
|
408
|
+
batch.push(pending);
|
|
409
|
+
}
|
|
410
|
+
const records = await readNodeRecords(database, manifest.partition, batch.map((pending) => pending.ref.hash));
|
|
411
|
+
for (let i = 0; i < batch.length; i++) {
|
|
412
|
+
const { ref, key } = batch[i];
|
|
413
|
+
const node = await verifyNodeRecord(index, ref, records[i], key);
|
|
414
|
+
if ("reason" in node)
|
|
415
|
+
return node;
|
|
416
|
+
if (node.node.kind === NodeKind.Leaf)
|
|
417
|
+
digestReplicaDatoms(digest, node.node.datoms);
|
|
418
|
+
else {
|
|
419
|
+
for (let child = 0; child < node.node.refs.length; child++) {
|
|
420
|
+
frontier.push({ ref: node.node.refs[child], key: node.node.keys[child] });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return validateReplicaContents(manifest.roots, digests, expected.success);
|
|
427
|
+
};
|
|
428
|
+
const reachableFromRoots = async (database, partition, roots) => {
|
|
429
|
+
const walk = new ReplicaReachability(roots);
|
|
430
|
+
while (walk.pending) {
|
|
431
|
+
const batch = walk.next(VALIDATION_BATCH);
|
|
432
|
+
const records = await readNodeRecords(database, partition, batch);
|
|
433
|
+
for (let i = 0; i < batch.length; i++) {
|
|
434
|
+
const record = records[i];
|
|
435
|
+
if (record === undefined || !(record.body instanceof Uint8Array)) {
|
|
436
|
+
walk.fail();
|
|
437
|
+
return walk;
|
|
438
|
+
}
|
|
439
|
+
if (await sha256Hex(record.body) !== batch[i]) {
|
|
440
|
+
walk.fail();
|
|
441
|
+
return walk;
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const decoded = decodeNode(await gzipCodec.decompress(record.body));
|
|
445
|
+
walk.expand(decoded.node.kind === NodeKind.Leaf
|
|
446
|
+
? []
|
|
447
|
+
: decoded.node.refs.map((ref) => ref.hash));
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
walk.fail();
|
|
451
|
+
return walk;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return walk;
|
|
456
|
+
};
|
|
457
|
+
const storedReadCompatibilityHash = (record) => typeof record === "object" && record !== null &&
|
|
458
|
+
typeof record
|
|
459
|
+
.readCompatibilityHash === "string"
|
|
460
|
+
? record
|
|
461
|
+
.readCompatibilityHash
|
|
462
|
+
: undefined;
|
|
463
|
+
const storedRevision = (record) => typeof record === "object" && record !== null &&
|
|
464
|
+
typeof record.revision === "string"
|
|
465
|
+
? record.revision
|
|
466
|
+
: null;
|
|
467
|
+
const referencedPartitions = (families) => {
|
|
468
|
+
const referenced = new Set();
|
|
469
|
+
for (const family of families) {
|
|
470
|
+
for (const record of family)
|
|
471
|
+
referenced.add(replicaPartitionKey(record.identity));
|
|
472
|
+
}
|
|
473
|
+
return referenced;
|
|
474
|
+
};
|
|
475
|
+
const readReferences = async (transaction) => {
|
|
476
|
+
const [bindings, candidates] = await Promise.all([
|
|
477
|
+
requestResult(transaction.objectStore(CREDENTIAL_BINDINGS).getAll()),
|
|
478
|
+
requestResult(transaction.objectStore(CACHE_CANDIDATES).getAll()),
|
|
479
|
+
]);
|
|
480
|
+
return referencedPartitions([bindings, candidates]);
|
|
481
|
+
};
|
|
482
|
+
let retentionToken = 0;
|
|
483
|
+
const RECORD_MOVED = Symbol("replica.record-moved");
|
|
484
|
+
const REPLICA_SWEEP_RESTORE_ATTEMPTS = 3;
|
|
485
|
+
export class IndexedDbReplicaStorage {
|
|
486
|
+
name;
|
|
487
|
+
database;
|
|
488
|
+
boundaries;
|
|
489
|
+
channel;
|
|
490
|
+
clearedScopes = new Set();
|
|
491
|
+
registry;
|
|
492
|
+
registrations = new Set();
|
|
493
|
+
invalidations = new Set();
|
|
494
|
+
meter = new WriteMeter();
|
|
495
|
+
constructor(name, database, boundaries, channel) {
|
|
496
|
+
this.name = name;
|
|
497
|
+
this.database = database;
|
|
498
|
+
this.boundaries = boundaries;
|
|
499
|
+
this.channel = channel;
|
|
500
|
+
this.registry = lifecycleRegistry(name);
|
|
501
|
+
}
|
|
502
|
+
static async open(name = DEFAULT_REPLICA_DATABASE_NAME, boundaries = inertRuntimeBoundaries) {
|
|
503
|
+
const request = indexedDB.open(name, DATABASE_VERSION);
|
|
504
|
+
request.addEventListener("upgradeneeded", (event) => {
|
|
505
|
+
const database = request.result;
|
|
506
|
+
if (!database.objectStoreNames.contains(COMMITTED)) {
|
|
507
|
+
database.createObjectStore(COMMITTED, { keyPath: "partition" });
|
|
508
|
+
}
|
|
509
|
+
if (!database.objectStoreNames.contains(COMMITTED_HEADS)) {
|
|
510
|
+
database.createObjectStore(COMMITTED_HEADS, { keyPath: "partition" });
|
|
511
|
+
}
|
|
512
|
+
if (!database.objectStoreNames.contains(STAGING)) {
|
|
513
|
+
database.createObjectStore(STAGING, { keyPath: "partition" });
|
|
514
|
+
}
|
|
515
|
+
if (!database.objectStoreNames.contains(STAGING_CHUNKS)) {
|
|
516
|
+
database.createObjectStore(STAGING_CHUNKS, { keyPath: ["partition", "index"] });
|
|
517
|
+
}
|
|
518
|
+
if (!database.objectStoreNames.contains(NODES)) {
|
|
519
|
+
database.createObjectStore(NODES, { keyPath: ["partition", "hash"] });
|
|
520
|
+
}
|
|
521
|
+
if (!database.objectStoreNames.contains(CREDENTIAL_BINDINGS)) {
|
|
522
|
+
database.createObjectStore(CREDENTIAL_BINDINGS, { keyPath: "fingerprint" });
|
|
523
|
+
}
|
|
524
|
+
if (!database.objectStoreNames.contains(CACHE_CANDIDATES)) {
|
|
525
|
+
database.createObjectStore(CACHE_CANDIDATES, {
|
|
526
|
+
keyPath: ["selector", "routeSlot"],
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
if (!database.objectStoreNames.contains(ROUTE_SLOTS)) {
|
|
530
|
+
database.createObjectStore(ROUTE_SLOTS, { keyPath: ["scope", "pathKey"] });
|
|
531
|
+
}
|
|
532
|
+
if (!database.objectStoreNames.contains(GENERATIONS)) {
|
|
533
|
+
database.createObjectStore(GENERATIONS, { keyPath: "key" });
|
|
534
|
+
}
|
|
535
|
+
const oldVersion = event.oldVersion;
|
|
536
|
+
if (request.transaction !== null) {
|
|
537
|
+
createMutationStores(database, request.transaction, oldVersion > 0 && oldVersion < MUTATION_INDEX_DATABASE_VERSION);
|
|
538
|
+
}
|
|
539
|
+
if (oldVersion > 0 && oldVersion < STORAGE_V2_DATABASE_VERSION && request.transaction !== null) {
|
|
540
|
+
const upgrade = request.transaction;
|
|
541
|
+
for (const store of REPLICA_STORE_FAMILIES)
|
|
542
|
+
upgrade.objectStore(store).clear();
|
|
543
|
+
}
|
|
544
|
+
else if (oldVersion >= STORAGE_V2_DATABASE_VERSION &&
|
|
545
|
+
oldVersion < LIFECYCLE_DATABASE_VERSION && request.transaction !== null) {
|
|
546
|
+
seedConfirmedGenerations(request.transaction);
|
|
547
|
+
}
|
|
548
|
+
if (oldVersion > 0 && oldVersion < MANIFEST_V5_DATABASE_VERSION &&
|
|
549
|
+
request.transaction !== null) {
|
|
550
|
+
const upgrade = request.transaction;
|
|
551
|
+
for (const store of REPLICA_VALUE_FAMILIES)
|
|
552
|
+
upgrade.objectStore(store).clear();
|
|
553
|
+
upgrade.objectStore(GENERATIONS).delete(prefixRange(STORAGE_V2_SWEEP_PREFIX));
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
const database = await requestResult(request);
|
|
557
|
+
const storage = new IndexedDbReplicaStorage(name, database, boundaries, ReplicaNoticeChannel.begin({
|
|
558
|
+
name: replicaNoticeChannelName(name),
|
|
559
|
+
broadcast: platformBroadcast(),
|
|
560
|
+
}));
|
|
561
|
+
database.addEventListener("versionchange", () => {
|
|
562
|
+
database.close();
|
|
563
|
+
storage.invalidated();
|
|
564
|
+
});
|
|
565
|
+
return storage;
|
|
566
|
+
}
|
|
567
|
+
notices(listener) {
|
|
568
|
+
return this.register(this.channel.subscribe(listener));
|
|
569
|
+
}
|
|
570
|
+
announces() {
|
|
571
|
+
return this.channel.announces();
|
|
572
|
+
}
|
|
573
|
+
announce(notice) {
|
|
574
|
+
this.channel.post(notice);
|
|
575
|
+
}
|
|
576
|
+
onInvalidated(listener) {
|
|
577
|
+
this.invalidations.add(listener);
|
|
578
|
+
return this.register(() => {
|
|
579
|
+
this.invalidations.delete(listener);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
invalidated() {
|
|
583
|
+
for (const listener of [...this.invalidations])
|
|
584
|
+
listener();
|
|
585
|
+
}
|
|
586
|
+
close() {
|
|
587
|
+
for (const release of [...this.registrations])
|
|
588
|
+
release();
|
|
589
|
+
this.channel.close();
|
|
590
|
+
this.database.close();
|
|
591
|
+
}
|
|
592
|
+
writeCounts() {
|
|
593
|
+
return this.meter.counts();
|
|
594
|
+
}
|
|
595
|
+
resetWriteCounts() {
|
|
596
|
+
this.meter.reset();
|
|
597
|
+
}
|
|
598
|
+
register(release) {
|
|
599
|
+
let released = false;
|
|
600
|
+
const once = () => {
|
|
601
|
+
if (released)
|
|
602
|
+
return;
|
|
603
|
+
released = true;
|
|
604
|
+
this.registrations.delete(once);
|
|
605
|
+
release();
|
|
606
|
+
};
|
|
607
|
+
this.registrations.add(once);
|
|
608
|
+
return once;
|
|
609
|
+
}
|
|
610
|
+
outbox(leader) {
|
|
611
|
+
return new IndexedDbOutbox(this.database, this.boundaries, (scope) => void this.assertScopeLive(scope), leader, (notice) => this.announce(notice));
|
|
612
|
+
}
|
|
613
|
+
async claimLeadership(key, scope) {
|
|
614
|
+
const scopeKey = this.assertScopeLive(scope);
|
|
615
|
+
const transaction = this.database.transaction(GENERATIONS, "readwrite");
|
|
616
|
+
const store = transaction.objectStore(GENERATIONS);
|
|
617
|
+
const held = await requestResult(store.get(key));
|
|
618
|
+
const generation = (held?.generation ?? 0) + 1;
|
|
619
|
+
store.put({
|
|
620
|
+
key,
|
|
621
|
+
kind: "leader",
|
|
622
|
+
scope: scopeKey,
|
|
623
|
+
generation,
|
|
624
|
+
confirmedAt: Date.now(),
|
|
625
|
+
fencedAt: null,
|
|
626
|
+
});
|
|
627
|
+
await commitTransaction(transaction);
|
|
628
|
+
return generation;
|
|
629
|
+
}
|
|
630
|
+
async admission() {
|
|
631
|
+
const transaction = this.database.transaction(GENERATIONS, "readonly");
|
|
632
|
+
const record = await requestResult(transaction.objectStore(GENERATIONS).get(REPLICA_CLEAR_BARRIER_KEY));
|
|
633
|
+
await transactionDone(transaction);
|
|
634
|
+
return record?.generation ?? 0;
|
|
635
|
+
}
|
|
636
|
+
async lease() {
|
|
637
|
+
return new ReplicaLease(await this.admission());
|
|
638
|
+
}
|
|
639
|
+
async confirmLease(lease, identity) {
|
|
640
|
+
this.assertScopeLive(replicaScopeOf(identity));
|
|
641
|
+
const transaction = this.database.transaction(GENERATIONS, "readonly");
|
|
642
|
+
await enforceFence(transaction, replicaFence(lease, identity));
|
|
643
|
+
await transactionDone(transaction);
|
|
644
|
+
}
|
|
645
|
+
async leaseFor(identity) {
|
|
646
|
+
const lease = await this.lease();
|
|
647
|
+
await this.confirmLease(lease, identity);
|
|
648
|
+
return lease;
|
|
649
|
+
}
|
|
650
|
+
pinDatabase(scope) {
|
|
651
|
+
const key = replicaDatabaseKey(scope);
|
|
652
|
+
const pins = this.registry.pins;
|
|
653
|
+
pins.set(key, (pins.get(key) ?? 0) + 1);
|
|
654
|
+
return this.register(() => {
|
|
655
|
+
const held = (pins.get(key) ?? 1) - 1;
|
|
656
|
+
if (held > 0)
|
|
657
|
+
pins.set(key, held);
|
|
658
|
+
else
|
|
659
|
+
pins.delete(key);
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
retainRoots(identity, roots) {
|
|
663
|
+
const partition = replicaPartitionKey(identity);
|
|
664
|
+
const held = this.registry.retained;
|
|
665
|
+
const entries = held.get(partition) ?? new Map();
|
|
666
|
+
held.set(partition, entries);
|
|
667
|
+
const token = ++retentionToken;
|
|
668
|
+
entries.set(token, rootHashes(roots));
|
|
669
|
+
return this.register(() => {
|
|
670
|
+
entries.delete(token);
|
|
671
|
+
if (entries.size === 0)
|
|
672
|
+
held.delete(partition);
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
markMaterializing(partition) {
|
|
676
|
+
const marks = this.registry.materializing;
|
|
677
|
+
marks.set(partition, (marks.get(partition) ?? 0) + 1);
|
|
678
|
+
let released = false;
|
|
679
|
+
return () => {
|
|
680
|
+
if (released)
|
|
681
|
+
return;
|
|
682
|
+
released = true;
|
|
683
|
+
const held = (marks.get(partition) ?? 1) - 1;
|
|
684
|
+
if (held > 0)
|
|
685
|
+
marks.set(partition, held);
|
|
686
|
+
else
|
|
687
|
+
marks.delete(partition);
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
enroll(participant) {
|
|
691
|
+
this.registry.participants.add(participant);
|
|
692
|
+
return this.register(() => {
|
|
693
|
+
this.registry.participants.delete(participant);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
assertScopeLive(scope) {
|
|
697
|
+
const key = replicaScopeKey(scope);
|
|
698
|
+
if (this.clearedScopes.has(key))
|
|
699
|
+
throw new ReplicaScopeClearedError({ scope: key });
|
|
700
|
+
return key;
|
|
701
|
+
}
|
|
702
|
+
async closeMatching(match) {
|
|
703
|
+
for (const participant of [...this.registry.participants]) {
|
|
704
|
+
if (!match(participant))
|
|
705
|
+
continue;
|
|
706
|
+
this.registry.participants.delete(participant);
|
|
707
|
+
await participant.close();
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
async clearScope(scope) {
|
|
711
|
+
const scopeKey = this.assertScopeLive(scope);
|
|
712
|
+
const prefix = replicaScopePartitionPrefix(scope);
|
|
713
|
+
this.clearedScopes.add(scopeKey);
|
|
714
|
+
const transaction = this.database.transaction([...REPLICA_STORE_FAMILIES, ...MUTATION_STORE_FAMILIES], "readwrite");
|
|
715
|
+
let outcome;
|
|
716
|
+
try {
|
|
717
|
+
outcome = await this.stageClear(transaction, scope, scopeKey, prefix);
|
|
718
|
+
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
this.clearedScopes.delete(scopeKey);
|
|
721
|
+
await abortTransaction(transaction);
|
|
722
|
+
throw error;
|
|
723
|
+
}
|
|
724
|
+
await commitTransaction(transaction);
|
|
725
|
+
this.announce(replicaNotice("reset", scope));
|
|
726
|
+
await this.closeMatching((participant) => replicaScopeKey(participant.scope) === scopeKey);
|
|
727
|
+
return outcome;
|
|
728
|
+
}
|
|
729
|
+
async stageClear(transaction, scope, scopeKey, prefix) {
|
|
730
|
+
const generations = transaction.objectStore(GENERATIONS);
|
|
731
|
+
const confirmed = await requestResult(generations.get(scopeKey));
|
|
732
|
+
if (confirmed === undefined) {
|
|
733
|
+
throw new ReplicaScopeUnconfirmedError({ scope: scopeKey });
|
|
734
|
+
}
|
|
735
|
+
const [partitions, nodes] = await Promise.all([
|
|
736
|
+
requestResult(transaction.objectStore(COMMITTED).count(prefixRange(prefix))),
|
|
737
|
+
requestResult(transaction.objectStore(NODES).count(compoundPrefixRange(prefix))),
|
|
738
|
+
]);
|
|
739
|
+
for (const family of PARTITION_KEYED_FAMILIES) {
|
|
740
|
+
transaction.objectStore(family).delete(prefixRange(prefix));
|
|
741
|
+
}
|
|
742
|
+
for (const family of PARTITION_PREFIXED_FAMILIES) {
|
|
743
|
+
transaction.objectStore(family).delete(compoundPrefixRange(prefix));
|
|
744
|
+
}
|
|
745
|
+
generations.delete(prefixRange(replicaSweepPrefix(prefix)));
|
|
746
|
+
const bindingStore = transaction.objectStore(CREDENTIAL_BINDINGS);
|
|
747
|
+
const candidateStore = transaction.objectStore(CACHE_CANDIDATES);
|
|
748
|
+
const routeStore = transaction.objectStore(ROUTE_SLOTS);
|
|
749
|
+
const [bindingRecords, candidateRecords, routeRecords] = await Promise.all([
|
|
750
|
+
requestResult(bindingStore.getAll()),
|
|
751
|
+
requestResult(candidateStore.getAll()),
|
|
752
|
+
requestResult(routeStore.getAll()),
|
|
753
|
+
]);
|
|
754
|
+
let bindings = 0;
|
|
755
|
+
for (const binding of bindingRecords) {
|
|
756
|
+
if (!identityInScope(binding.identity, scope))
|
|
757
|
+
continue;
|
|
758
|
+
bindingStore.delete(binding.fingerprint);
|
|
759
|
+
bindings++;
|
|
760
|
+
}
|
|
761
|
+
let candidates = 0;
|
|
762
|
+
for (const candidate of candidateRecords) {
|
|
763
|
+
if (!identityInScope(candidate.identity, scope))
|
|
764
|
+
continue;
|
|
765
|
+
candidateStore.delete([candidate.selector, candidate.routeSlot]);
|
|
766
|
+
candidates++;
|
|
767
|
+
}
|
|
768
|
+
let routeObservations = 0;
|
|
769
|
+
for (const observation of routeRecords) {
|
|
770
|
+
if (!(observation.replicaScopes ?? []).includes(scopeKey))
|
|
771
|
+
continue;
|
|
772
|
+
routeObservations++;
|
|
773
|
+
const remaining = withoutConfirmedScope(observation.replicaScopes, scopeKey);
|
|
774
|
+
if (remaining.length === 0) {
|
|
775
|
+
routeStore.delete([observation.scope, observation.pathKey]);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
routeStore.put({ ...observation, replicaScopes: remaining });
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
const mutations = await clearMutationScope(transaction, scope);
|
|
782
|
+
const generation = confirmed.generation + 1;
|
|
783
|
+
const clearedAt = await this.advanceBarrier(generations);
|
|
784
|
+
generations.put({
|
|
785
|
+
...confirmed,
|
|
786
|
+
generation,
|
|
787
|
+
fencedAt: Date.now(),
|
|
788
|
+
clearedAt,
|
|
789
|
+
});
|
|
790
|
+
await this.boundaries.checkpoint("replica.clear");
|
|
791
|
+
return Object.freeze({
|
|
792
|
+
scope: scopeKey,
|
|
793
|
+
generation,
|
|
794
|
+
partitions,
|
|
795
|
+
nodes,
|
|
796
|
+
bindings,
|
|
797
|
+
candidates,
|
|
798
|
+
routeObservations,
|
|
799
|
+
queued: mutations.queued,
|
|
800
|
+
clientRefs: mutations.clientRefs,
|
|
801
|
+
layers: mutations.layers,
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
async evictDatabase(scope) {
|
|
805
|
+
const scopeKey = this.assertScopeLive(scope);
|
|
806
|
+
const databaseKey = replicaDatabaseKey(scope);
|
|
807
|
+
const pins = this.registry.pins.get(databaseKey) ?? 0;
|
|
808
|
+
if (pins > 0)
|
|
809
|
+
throw new ReplicaDatabaseActiveError({ database: databaseKey, pins });
|
|
810
|
+
const prefix = replicaDatabasePartitionPrefix(scope);
|
|
811
|
+
const transaction = this.database.transaction([
|
|
812
|
+
...PARTITION_KEYED_FAMILIES,
|
|
813
|
+
...PARTITION_PREFIXED_FAMILIES,
|
|
814
|
+
...IDENTITY_KEYED_FAMILIES,
|
|
815
|
+
GENERATIONS,
|
|
816
|
+
], "readwrite");
|
|
817
|
+
let outcome;
|
|
818
|
+
try {
|
|
819
|
+
outcome = await this.stageEviction(transaction, scope, scopeKey, databaseKey, prefix);
|
|
820
|
+
}
|
|
821
|
+
catch (error) {
|
|
822
|
+
await abortTransaction(transaction);
|
|
823
|
+
throw error;
|
|
824
|
+
}
|
|
825
|
+
await commitTransaction(transaction);
|
|
826
|
+
this.announce(replicaNotice("reset", scope, scope));
|
|
827
|
+
await this.closeMatching((participant) => participant.database !== undefined &&
|
|
828
|
+
replicaDatabaseKey(participant.database) === databaseKey);
|
|
829
|
+
return outcome;
|
|
830
|
+
}
|
|
831
|
+
async stageEviction(transaction, scope, scopeKey, databaseKey, prefix) {
|
|
832
|
+
const generations = transaction.objectStore(GENERATIONS);
|
|
833
|
+
const [confirmed, current] = await Promise.all([
|
|
834
|
+
requestResult(generations.get(scopeKey)),
|
|
835
|
+
requestResult(generations.get(databaseKey)),
|
|
836
|
+
]);
|
|
837
|
+
if (confirmed === undefined) {
|
|
838
|
+
throw new ReplicaScopeUnconfirmedError({ scope: scopeKey });
|
|
839
|
+
}
|
|
840
|
+
const [partitions, nodes] = await Promise.all([
|
|
841
|
+
requestResult(transaction.objectStore(COMMITTED).count(prefixRange(prefix))),
|
|
842
|
+
requestResult(transaction.objectStore(NODES).count(compoundPrefixRange(prefix))),
|
|
843
|
+
]);
|
|
844
|
+
for (const family of PARTITION_KEYED_FAMILIES) {
|
|
845
|
+
transaction.objectStore(family).delete(prefixRange(prefix));
|
|
846
|
+
}
|
|
847
|
+
for (const family of PARTITION_PREFIXED_FAMILIES) {
|
|
848
|
+
transaction.objectStore(family).delete(compoundPrefixRange(prefix));
|
|
849
|
+
}
|
|
850
|
+
generations.delete(prefixRange(replicaSweepPrefix(prefix)));
|
|
851
|
+
const bindingStore = transaction.objectStore(CREDENTIAL_BINDINGS);
|
|
852
|
+
const candidateStore = transaction.objectStore(CACHE_CANDIDATES);
|
|
853
|
+
const [bindingRecords, candidateRecords] = await Promise.all([
|
|
854
|
+
requestResult(bindingStore.getAll()),
|
|
855
|
+
requestResult(candidateStore.getAll()),
|
|
856
|
+
]);
|
|
857
|
+
let bindings = 0;
|
|
858
|
+
for (const binding of bindingRecords) {
|
|
859
|
+
if (!identityInDatabase(binding.identity, scope))
|
|
860
|
+
continue;
|
|
861
|
+
bindingStore.delete(binding.fingerprint);
|
|
862
|
+
bindings++;
|
|
863
|
+
}
|
|
864
|
+
let candidates = 0;
|
|
865
|
+
for (const candidate of candidateRecords) {
|
|
866
|
+
if (!identityInDatabase(candidate.identity, scope))
|
|
867
|
+
continue;
|
|
868
|
+
candidateStore.delete([candidate.selector, candidate.routeSlot]);
|
|
869
|
+
candidates++;
|
|
870
|
+
}
|
|
871
|
+
const generation = (current?.generation ?? 0) + 1;
|
|
872
|
+
generations.put({
|
|
873
|
+
key: databaseKey,
|
|
874
|
+
kind: "database",
|
|
875
|
+
scope: scopeKey,
|
|
876
|
+
generation,
|
|
877
|
+
confirmedAt: current?.confirmedAt ?? Date.now(),
|
|
878
|
+
fencedAt: Date.now(),
|
|
879
|
+
});
|
|
880
|
+
await this.boundaries.checkpoint("replica.evict");
|
|
881
|
+
return Object.freeze({
|
|
882
|
+
database: databaseKey,
|
|
883
|
+
generation,
|
|
884
|
+
partitions,
|
|
885
|
+
nodes,
|
|
886
|
+
bindings,
|
|
887
|
+
candidates,
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
async collectGarbage(options = {}) {
|
|
891
|
+
let prefix;
|
|
892
|
+
if (options.scope !== undefined) {
|
|
893
|
+
this.assertScopeLive(options.scope);
|
|
894
|
+
prefix = replicaScopePartitionPrefix(options.scope);
|
|
895
|
+
}
|
|
896
|
+
const survey = await this.surveyPartitions(prefix);
|
|
897
|
+
const superseded = supersededPartitions(survey.keys(), await this.surveyReferences());
|
|
898
|
+
let partitions = 0;
|
|
899
|
+
let swept = 0;
|
|
900
|
+
let skipped = 0;
|
|
901
|
+
let nodes = 0;
|
|
902
|
+
let retained = 0;
|
|
903
|
+
let staging = 0;
|
|
904
|
+
for (const [partition, hashes] of survey) {
|
|
905
|
+
const scopeKey = replicaPartitionScopeKey(partition);
|
|
906
|
+
if (scopeKey !== undefined && this.clearedScopes.has(scopeKey))
|
|
907
|
+
continue;
|
|
908
|
+
partitions++;
|
|
909
|
+
const discard = superseded.has(partition);
|
|
910
|
+
const stored = await this.surveyManifest(partition, hashes);
|
|
911
|
+
const live = await this.liveNodeHashes(partition, stored, discard);
|
|
912
|
+
if (live === undefined) {
|
|
913
|
+
skipped++;
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const garbage = unreachableNodeHashes(stored.hashes, live);
|
|
917
|
+
await this.boundaries.checkpoint("replica.gc.planned");
|
|
918
|
+
const outcome = await this.sweepPartition(partition, stored, garbage, live, discard);
|
|
919
|
+
if (outcome === undefined) {
|
|
920
|
+
skipped++;
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
retained += stored.hashes.length - outcome.nodes;
|
|
924
|
+
nodes += outcome.nodes;
|
|
925
|
+
staging += outcome.staging;
|
|
926
|
+
if (outcome.nodes > 0 || outcome.staging > 0 || outcome.discarded)
|
|
927
|
+
swept++;
|
|
928
|
+
if (!outcome.discarded)
|
|
929
|
+
continue;
|
|
930
|
+
const discarded = replicaManifestIdentity(stored.record);
|
|
931
|
+
if (discarded !== undefined)
|
|
932
|
+
this.announce(identityNotice("reset", discarded));
|
|
933
|
+
}
|
|
934
|
+
return Object.freeze({ partitions, swept, skipped, nodes, retained, staging });
|
|
935
|
+
}
|
|
936
|
+
async surveyPartitions(prefix) {
|
|
937
|
+
const transaction = this.database.transaction([COMMITTED, NODES, STAGING], "readonly");
|
|
938
|
+
const keysOf = (store, compound) => requestResult(prefix === undefined
|
|
939
|
+
? transaction.objectStore(store).getAllKeys()
|
|
940
|
+
: transaction.objectStore(store).getAllKeys(compound ? compoundPrefixRange(prefix) : prefixRange(prefix)));
|
|
941
|
+
const [manifestKeys, nodeKeys, stagingKeys] = await Promise.all([
|
|
942
|
+
keysOf(COMMITTED, false),
|
|
943
|
+
keysOf(NODES, true),
|
|
944
|
+
keysOf(STAGING, false),
|
|
945
|
+
]);
|
|
946
|
+
await transactionDone(transaction);
|
|
947
|
+
const survey = new Map();
|
|
948
|
+
const at = (partition) => {
|
|
949
|
+
const existing = survey.get(partition);
|
|
950
|
+
if (existing !== undefined)
|
|
951
|
+
return existing;
|
|
952
|
+
const created = [];
|
|
953
|
+
survey.set(partition, created);
|
|
954
|
+
return created;
|
|
955
|
+
};
|
|
956
|
+
for (const key of nodeKeys) {
|
|
957
|
+
if (!Array.isArray(key) || typeof key[0] !== "string" || typeof key[1] !== "string") {
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
at(key[0]).push(key[1]);
|
|
961
|
+
}
|
|
962
|
+
for (const keys of [stagingKeys, manifestKeys]) {
|
|
963
|
+
for (const key of keys)
|
|
964
|
+
if (typeof key === "string")
|
|
965
|
+
at(key);
|
|
966
|
+
}
|
|
967
|
+
return survey;
|
|
968
|
+
}
|
|
969
|
+
async surveyReferences() {
|
|
970
|
+
const transaction = this.database.transaction([...IDENTITY_KEYED_FAMILIES], "readonly");
|
|
971
|
+
const referenced = await readReferences(transaction);
|
|
972
|
+
await transactionDone(transaction);
|
|
973
|
+
return referenced;
|
|
974
|
+
}
|
|
975
|
+
async surveyManifest(partition, hashes) {
|
|
976
|
+
const transaction = this.database.transaction(COMMITTED, "readonly");
|
|
977
|
+
const record = await requestResult(transaction.objectStore(COMMITTED).get(partition));
|
|
978
|
+
await transactionDone(transaction);
|
|
979
|
+
return { hashes, fingerprint: replicaManifestFingerprint(record), record };
|
|
980
|
+
}
|
|
981
|
+
async liveNodeHashes(partition, stored, discard) {
|
|
982
|
+
const live = new Set();
|
|
983
|
+
if (!discard && stored.record !== undefined) {
|
|
984
|
+
const expected = storedReadCompatibilityHash(stored.record);
|
|
985
|
+
if (expected === undefined)
|
|
986
|
+
return undefined;
|
|
987
|
+
const manifest = validateReplicaManifest(stored.record, {
|
|
988
|
+
partition,
|
|
989
|
+
readCompatibilityHash: expected,
|
|
990
|
+
});
|
|
991
|
+
if (Result.isFailure(manifest))
|
|
992
|
+
return undefined;
|
|
993
|
+
if (await validateReachableNodes(this.database, manifest.success, live) !== undefined) {
|
|
994
|
+
return undefined;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
const retained = this.retainedRoots(partition);
|
|
998
|
+
if (retained.length > 0) {
|
|
999
|
+
const walk = await reachableFromRoots(this.database, partition, retained);
|
|
1000
|
+
if (!walk.complete)
|
|
1001
|
+
return undefined;
|
|
1002
|
+
for (const hash of walk.reachable)
|
|
1003
|
+
live.add(hash);
|
|
1004
|
+
}
|
|
1005
|
+
return live;
|
|
1006
|
+
}
|
|
1007
|
+
retainedRoots(partition) {
|
|
1008
|
+
const roots = [];
|
|
1009
|
+
for (const held of this.registry.retained.get(partition)?.values() ?? []) {
|
|
1010
|
+
roots.push(...held);
|
|
1011
|
+
}
|
|
1012
|
+
return roots;
|
|
1013
|
+
}
|
|
1014
|
+
async sweepPartition(partition, stored, garbage, live, discard) {
|
|
1015
|
+
if (this.registry.materializing.has(partition))
|
|
1016
|
+
return undefined;
|
|
1017
|
+
if (this.retainedRoots(partition).some((hash) => !live.has(hash)))
|
|
1018
|
+
return undefined;
|
|
1019
|
+
if (discard && this.retainedRoots(partition).length > 0)
|
|
1020
|
+
return undefined;
|
|
1021
|
+
const transaction = this.database.transaction(discard
|
|
1022
|
+
? [
|
|
1023
|
+
COMMITTED,
|
|
1024
|
+
COMMITTED_HEADS,
|
|
1025
|
+
NODES,
|
|
1026
|
+
STAGING,
|
|
1027
|
+
STAGING_CHUNKS,
|
|
1028
|
+
GENERATIONS,
|
|
1029
|
+
...IDENTITY_KEYED_FAMILIES,
|
|
1030
|
+
]
|
|
1031
|
+
: [COMMITTED, NODES, STAGING, STAGING_CHUNKS, GENERATIONS], "readwrite");
|
|
1032
|
+
let sweptStaging = false;
|
|
1033
|
+
try {
|
|
1034
|
+
const sweepKey = replicaSweepKey(partition);
|
|
1035
|
+
const [current, staged, sweep] = await Promise.all([
|
|
1036
|
+
requestResult(transaction.objectStore(COMMITTED).get(partition)),
|
|
1037
|
+
requestResult(transaction.objectStore(STAGING).get(partition)),
|
|
1038
|
+
requestResult(transaction.objectStore(GENERATIONS).get(sweepKey)),
|
|
1039
|
+
]);
|
|
1040
|
+
if (replicaManifestFingerprint(current) !== stored.fingerprint) {
|
|
1041
|
+
await abortTransaction(transaction);
|
|
1042
|
+
return undefined;
|
|
1043
|
+
}
|
|
1044
|
+
if (discard &&
|
|
1045
|
+
!supersededPartitions([partition], await readReferences(transaction)).has(partition)) {
|
|
1046
|
+
await abortTransaction(transaction);
|
|
1047
|
+
return undefined;
|
|
1048
|
+
}
|
|
1049
|
+
sweptStaging = staged !== undefined &&
|
|
1050
|
+
(discard || stagingIsSweepable(staged, storedRevision(current)));
|
|
1051
|
+
if (garbage.length === 0 && !sweptStaging && !discard) {
|
|
1052
|
+
await transactionDone(transaction);
|
|
1053
|
+
return { nodes: 0, staging: 0, discarded: false };
|
|
1054
|
+
}
|
|
1055
|
+
const nodes = transaction.objectStore(NODES);
|
|
1056
|
+
for (const hash of garbage)
|
|
1057
|
+
nodes.delete([partition, hash]);
|
|
1058
|
+
if (sweptStaging) {
|
|
1059
|
+
transaction.objectStore(STAGING).delete(partition);
|
|
1060
|
+
transaction.objectStore(STAGING_CHUNKS).delete(chunkRange(partition));
|
|
1061
|
+
}
|
|
1062
|
+
if (discard) {
|
|
1063
|
+
transaction.objectStore(COMMITTED).delete(partition);
|
|
1064
|
+
transaction.objectStore(COMMITTED_HEADS).delete(partition);
|
|
1065
|
+
}
|
|
1066
|
+
if (garbage.length > 0 || discard) {
|
|
1067
|
+
transaction.objectStore(GENERATIONS).put({
|
|
1068
|
+
key: sweepKey,
|
|
1069
|
+
kind: "partition",
|
|
1070
|
+
scope: replicaPartitionScopeKey(partition) ?? "",
|
|
1071
|
+
generation: (sweep?.generation ?? 0) + 1,
|
|
1072
|
+
confirmedAt: sweep?.confirmedAt ?? Date.now(),
|
|
1073
|
+
fencedAt: Date.now(),
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
await this.boundaries.checkpoint("replica.sweep");
|
|
1077
|
+
}
|
|
1078
|
+
catch (error) {
|
|
1079
|
+
await abortTransaction(transaction);
|
|
1080
|
+
throw error;
|
|
1081
|
+
}
|
|
1082
|
+
await commitTransaction(transaction);
|
|
1083
|
+
return { nodes: garbage.length, staging: sweptStaging ? 1 : 0, discarded: discard };
|
|
1084
|
+
}
|
|
1085
|
+
async committed(identity) {
|
|
1086
|
+
const transaction = this.database.transaction(COMMITTED, "readonly");
|
|
1087
|
+
const record = await requestResult(transaction.objectStore(COMMITTED).get(replicaPartitionKey(identity)));
|
|
1088
|
+
await transactionDone(transaction);
|
|
1089
|
+
return record;
|
|
1090
|
+
}
|
|
1091
|
+
async priorManifest(identity) {
|
|
1092
|
+
return await this.committed(identity);
|
|
1093
|
+
}
|
|
1094
|
+
async quarantinePartition(identity, options) {
|
|
1095
|
+
const partition = replicaPartitionKey(identity);
|
|
1096
|
+
const fence = replicaFence(options.lease ?? await this.leaseFor(identity), identity);
|
|
1097
|
+
const transaction = this.database.transaction([COMMITTED, COMMITTED_HEADS, CREDENTIAL_BINDINGS, CACHE_CANDIDATES, GENERATIONS], "readwrite");
|
|
1098
|
+
try {
|
|
1099
|
+
await enforceFence(transaction, fence);
|
|
1100
|
+
const current = await requestResult(transaction.objectStore(COMMITTED).get(partition));
|
|
1101
|
+
if (replicaManifestFingerprint(current) !== options.expect) {
|
|
1102
|
+
await abortTransaction(transaction);
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
transaction.objectStore(COMMITTED).delete(partition);
|
|
1106
|
+
transaction.objectStore(COMMITTED_HEADS).delete(partition);
|
|
1107
|
+
const bindings = transaction.objectStore(CREDENTIAL_BINDINGS);
|
|
1108
|
+
if (options.fingerprint !== undefined) {
|
|
1109
|
+
bindings.delete(options.fingerprint);
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
const records = await requestResult(bindings.getAll());
|
|
1113
|
+
for (const binding of records) {
|
|
1114
|
+
if (sameReplicationIdentity(binding.identity, identity)) {
|
|
1115
|
+
bindings.delete(binding.fingerprint);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
const candidates = transaction.objectStore(CACHE_CANDIDATES);
|
|
1120
|
+
const candidateRecords = await requestResult(candidates.getAll());
|
|
1121
|
+
for (const candidate of candidateRecords) {
|
|
1122
|
+
if (sameReplicationIdentity(candidate.identity, identity)) {
|
|
1123
|
+
candidates.delete([candidate.selector, candidate.routeSlot]);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
await this.boundaries.checkpoint("replica.quarantine");
|
|
1127
|
+
}
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
await abortTransaction(transaction);
|
|
1130
|
+
throw error;
|
|
1131
|
+
}
|
|
1132
|
+
await commitTransaction(transaction);
|
|
1133
|
+
return true;
|
|
1134
|
+
}
|
|
1135
|
+
async validated(record, identity, attributes, readCompatibilityHash, fingerprint) {
|
|
1136
|
+
let current = record;
|
|
1137
|
+
for (let attempt = 1; attempt <= REPLICA_SWEEP_RESTORE_ATTEMPTS; attempt++) {
|
|
1138
|
+
const outcome = await this.validatedOnce(current, identity, attributes, readCompatibilityHash, fingerprint);
|
|
1139
|
+
if (outcome !== RECORD_MOVED)
|
|
1140
|
+
return outcome;
|
|
1141
|
+
current = await this.committed(identity);
|
|
1142
|
+
if (current === undefined)
|
|
1143
|
+
return replicaAbsent();
|
|
1144
|
+
const stored = replicaManifestIdentity(current);
|
|
1145
|
+
if (stored !== undefined && !sameReplicationIdentity(stored, identity)) {
|
|
1146
|
+
return replicaAbsent();
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
return replicaContended(replicaPartitionKey(identity), REPLICA_SWEEP_RESTORE_ATTEMPTS);
|
|
1150
|
+
}
|
|
1151
|
+
async validatedOnce(record, identity, attributes, readCompatibilityHash, fingerprint) {
|
|
1152
|
+
const partition = replicaPartitionKey(identity);
|
|
1153
|
+
const expect = replicaManifestFingerprint(record);
|
|
1154
|
+
const lease = await this.leaseFor(identity);
|
|
1155
|
+
const sweep = await this.sweepGeneration(partition);
|
|
1156
|
+
const quarantine = async (reason, detail) => {
|
|
1157
|
+
await this.boundaries.checkpoint("replica.refused");
|
|
1158
|
+
const removed = await this.quarantinePartition(identity, {
|
|
1159
|
+
expect,
|
|
1160
|
+
lease,
|
|
1161
|
+
...(fingerprint === undefined ? {} : { fingerprint }),
|
|
1162
|
+
});
|
|
1163
|
+
return removed
|
|
1164
|
+
? replicaUnusable(partition, reason, detail)
|
|
1165
|
+
: RECORD_MOVED;
|
|
1166
|
+
};
|
|
1167
|
+
if (identity.readCompatibilityHash !== readCompatibilityHash) {
|
|
1168
|
+
return quarantine("read-compatibility", "the selected identity does not confirm this client's read compatibility");
|
|
1169
|
+
}
|
|
1170
|
+
const manifest = validateReplicaManifest(record, { partition, readCompatibilityHash });
|
|
1171
|
+
if (Result.isFailure(manifest)) {
|
|
1172
|
+
return quarantine(manifest.failure.reason, manifest.failure.detail);
|
|
1173
|
+
}
|
|
1174
|
+
if (!sameReplicaAttributes(manifest.success.attributes, replicaAttributes(attributes))) {
|
|
1175
|
+
return quarantine("schema-metadata", "replica attribute metadata is incompatible with the committed read view");
|
|
1176
|
+
}
|
|
1177
|
+
const invalid = await validateReachableNodes(this.database, manifest.success);
|
|
1178
|
+
if (invalid !== undefined)
|
|
1179
|
+
return quarantine(invalid.reason, invalid.detail);
|
|
1180
|
+
await this.boundaries.checkpoint("replica.validated");
|
|
1181
|
+
const retention = this.retainRoots(identity, manifest.success.roots);
|
|
1182
|
+
if (!await this.confirmGuardingGenerations(lease, identity, sweep)) {
|
|
1183
|
+
retention();
|
|
1184
|
+
return RECORD_MOVED;
|
|
1185
|
+
}
|
|
1186
|
+
return replicaRestored({ record: manifest.success, release: retention });
|
|
1187
|
+
}
|
|
1188
|
+
async confirmNoSweep(transaction, partition, observed) {
|
|
1189
|
+
const key = replicaSweepKey(partition);
|
|
1190
|
+
const record = await requestResult(transaction.objectStore(GENERATIONS).get(key));
|
|
1191
|
+
const current = record?.generation ?? 0;
|
|
1192
|
+
if (current === observed)
|
|
1193
|
+
return;
|
|
1194
|
+
await abortTransaction(transaction);
|
|
1195
|
+
throw new ReplicaFencedError({ key, expected: observed, observed: current });
|
|
1196
|
+
}
|
|
1197
|
+
async sweepGeneration(partition) {
|
|
1198
|
+
const transaction = this.database.transaction(GENERATIONS, "readonly");
|
|
1199
|
+
const record = await requestResult(transaction.objectStore(GENERATIONS).get(replicaSweepKey(partition)));
|
|
1200
|
+
await transactionDone(transaction);
|
|
1201
|
+
return record?.generation ?? 0;
|
|
1202
|
+
}
|
|
1203
|
+
async confirmGuardingGenerations(lease, identity, sweep) {
|
|
1204
|
+
const transaction = this.database.transaction(GENERATIONS, "readonly");
|
|
1205
|
+
await enforceFence(transaction, replicaFence(lease, identity));
|
|
1206
|
+
const record = await requestResult(transaction.objectStore(GENERATIONS).get(replicaSweepKey(replicaPartitionKey(identity))));
|
|
1207
|
+
await transactionDone(transaction);
|
|
1208
|
+
return (record?.generation ?? 0) === sweep;
|
|
1209
|
+
}
|
|
1210
|
+
async boundIdentity(fingerprint) {
|
|
1211
|
+
const transaction = this.database.transaction(CREDENTIAL_BINDINGS, "readonly");
|
|
1212
|
+
const record = await requestResult(transaction.objectStore(CREDENTIAL_BINDINGS).get(fingerprint));
|
|
1213
|
+
await transactionDone(transaction);
|
|
1214
|
+
return record?.identity;
|
|
1215
|
+
}
|
|
1216
|
+
async unbindCredential(fingerprint) {
|
|
1217
|
+
const transaction = this.database.transaction(CREDENTIAL_BINDINGS, "readwrite");
|
|
1218
|
+
transaction.objectStore(CREDENTIAL_BINDINGS).delete(fingerprint);
|
|
1219
|
+
await commitTransaction(transaction);
|
|
1220
|
+
}
|
|
1221
|
+
async restoreOutcome(identity, attributes, readCompatibilityHash) {
|
|
1222
|
+
this.assertScopeLive(replicaScopeOf(identity));
|
|
1223
|
+
const record = await this.committed(identity);
|
|
1224
|
+
if (record === undefined)
|
|
1225
|
+
return replicaAbsent();
|
|
1226
|
+
const stored = replicaManifestIdentity(record);
|
|
1227
|
+
if (stored !== undefined && !sameReplicationIdentity(stored, identity)) {
|
|
1228
|
+
return replicaAbsent();
|
|
1229
|
+
}
|
|
1230
|
+
const validated = await this.validated(record, identity, attributes, readCompatibilityHash);
|
|
1231
|
+
if (validated._tag !== "restored")
|
|
1232
|
+
return validated;
|
|
1233
|
+
return replicaRestored({
|
|
1234
|
+
db: dbFromRecord(this.database, validated.replica.record, readCompatibilityHash),
|
|
1235
|
+
revision: validated.replica.record.revision,
|
|
1236
|
+
ordinal: validated.replica.record.ordinal,
|
|
1237
|
+
handles: recordHandles(validated.replica.record),
|
|
1238
|
+
release: validated.replica.release,
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
async restore(identity, attributes, readCompatibilityHash) {
|
|
1242
|
+
return restoredReplica(await this.restoreOutcome(identity, attributes, readCompatibilityHash));
|
|
1243
|
+
}
|
|
1244
|
+
async selectCacheCandidate(key, readCompatibilityHash) {
|
|
1245
|
+
const transaction = this.database.transaction([CACHE_CANDIDATES, COMMITTED_HEADS], "readonly");
|
|
1246
|
+
const binding = await requestResult(transaction.objectStore(CACHE_CANDIDATES).get([key.selector, key.routeSlot]));
|
|
1247
|
+
if (binding === undefined ||
|
|
1248
|
+
binding.identity.readCompatibilityHash !== readCompatibilityHash) {
|
|
1249
|
+
await transactionDone(transaction);
|
|
1250
|
+
return undefined;
|
|
1251
|
+
}
|
|
1252
|
+
const head = await requestResult(transaction.objectStore(COMMITTED_HEADS).get(replicaPartitionKey(binding.identity)));
|
|
1253
|
+
await transactionDone(transaction);
|
|
1254
|
+
if (head === undefined ||
|
|
1255
|
+
head.storageVersion !== REPLICA_STORAGE_VERSION ||
|
|
1256
|
+
head.partition !== replicaPartitionKey(binding.identity) ||
|
|
1257
|
+
head.readCompatibilityHash !== readCompatibilityHash ||
|
|
1258
|
+
head.identity.readCompatibilityHash !== readCompatibilityHash ||
|
|
1259
|
+
!isReplicationOrdinal(head.ordinal) ||
|
|
1260
|
+
!sameReplicationIdentity(head.identity, binding.identity)) {
|
|
1261
|
+
return undefined;
|
|
1262
|
+
}
|
|
1263
|
+
return Object.freeze({
|
|
1264
|
+
identity: binding.identity,
|
|
1265
|
+
revision: head.revision,
|
|
1266
|
+
ordinal: head.ordinal,
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
async restoreCandidateOutcome(candidate, attributes, readCompatibilityHash) {
|
|
1270
|
+
this.assertScopeLive(replicaScopeOf(candidate.identity));
|
|
1271
|
+
const record = await this.committed(candidate.identity);
|
|
1272
|
+
if (record === undefined)
|
|
1273
|
+
return replicaAbsent();
|
|
1274
|
+
const stored = replicaManifestIdentity(record);
|
|
1275
|
+
if (stored !== undefined && !sameReplicationIdentity(stored, candidate.identity)) {
|
|
1276
|
+
return replicaAbsent();
|
|
1277
|
+
}
|
|
1278
|
+
const validated = await this.validated(record, candidate.identity, attributes, readCompatibilityHash);
|
|
1279
|
+
if (validated._tag !== "restored")
|
|
1280
|
+
return validated;
|
|
1281
|
+
if (validated.replica.record.revision !== candidate.revision) {
|
|
1282
|
+
validated.replica.release();
|
|
1283
|
+
return replicaAbsent();
|
|
1284
|
+
}
|
|
1285
|
+
return replicaRestored({
|
|
1286
|
+
identity: candidate.identity,
|
|
1287
|
+
db: dbFromRecord(this.database, validated.replica.record, readCompatibilityHash),
|
|
1288
|
+
revision: validated.replica.record.revision,
|
|
1289
|
+
ordinal: validated.replica.record.ordinal,
|
|
1290
|
+
handles: recordHandles(validated.replica.record),
|
|
1291
|
+
release: validated.replica.release,
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
async restoreConfirmedCandidate(candidate, attributes, readCompatibilityHash) {
|
|
1295
|
+
return restoredReplica(await this.restoreCandidateOutcome(candidate, attributes, readCompatibilityHash));
|
|
1296
|
+
}
|
|
1297
|
+
async observedRouteSlot(observation) {
|
|
1298
|
+
const transaction = this.database.transaction(ROUTE_SLOTS, "readonly");
|
|
1299
|
+
const record = await requestResult(transaction.objectStore(ROUTE_SLOTS).get([observation.scope, observation.pathKey]));
|
|
1300
|
+
await transactionDone(transaction);
|
|
1301
|
+
return record?.slot;
|
|
1302
|
+
}
|
|
1303
|
+
async bindAuthenticated(binding, options = {}) {
|
|
1304
|
+
const scopeKey = this.assertScopeLive(replicaScopeOf(binding.identity));
|
|
1305
|
+
const databaseKey = replicaDatabaseKey(replicaDatabaseScopeOf(binding.identity));
|
|
1306
|
+
const transaction = this.database.transaction([CREDENTIAL_BINDINGS, CACHE_CANDIDATES, ROUTE_SLOTS, GENERATIONS], "readwrite");
|
|
1307
|
+
const removeAbort = abortWithSignal(transaction, options.signal);
|
|
1308
|
+
try {
|
|
1309
|
+
const generations = transaction.objectStore(GENERATIONS);
|
|
1310
|
+
const candidates = transaction.objectStore(CACHE_CANDIDATES);
|
|
1311
|
+
const [scopeRecord, databaseRecord, existingRoute] = await Promise.all([
|
|
1312
|
+
requestResult(generations.get(scopeKey)),
|
|
1313
|
+
requestResult(generations.get(databaseKey)),
|
|
1314
|
+
binding.route === undefined
|
|
1315
|
+
? undefined
|
|
1316
|
+
: requestResult(transaction.objectStore(ROUTE_SLOTS).get([binding.route.scope, binding.route.pathKey])),
|
|
1317
|
+
]);
|
|
1318
|
+
for (const seeded of confirmationRecords(binding.identity, Date.now())) {
|
|
1319
|
+
const existing = seeded.kind === "scope" ? scopeRecord : databaseRecord;
|
|
1320
|
+
if (existing === undefined)
|
|
1321
|
+
generations.put(seeded);
|
|
1322
|
+
}
|
|
1323
|
+
if (options.lease !== undefined) {
|
|
1324
|
+
try {
|
|
1325
|
+
options.lease.observe(scopeKey, scopeRecord?.generation ?? 1);
|
|
1326
|
+
options.lease.observe(databaseKey, databaseRecord?.generation ?? 1);
|
|
1327
|
+
options.lease.admit(scopeKey, scopeRecord?.clearedAt ?? 0);
|
|
1328
|
+
}
|
|
1329
|
+
catch (error) {
|
|
1330
|
+
await abortTransaction(transaction);
|
|
1331
|
+
throw error;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
const replaced = await this.stageReplacedPrincipals(transaction, binding.identity, binding.candidateKey?.selector);
|
|
1335
|
+
transaction.objectStore(CREDENTIAL_BINDINGS).put({
|
|
1336
|
+
fingerprint: binding.fingerprint,
|
|
1337
|
+
identity: binding.identity,
|
|
1338
|
+
});
|
|
1339
|
+
if (binding.candidateKey !== undefined) {
|
|
1340
|
+
candidates.put({
|
|
1341
|
+
selector: binding.candidateKey.selector,
|
|
1342
|
+
routeSlot: binding.candidateKey.routeSlot,
|
|
1343
|
+
identity: binding.identity,
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
if (binding.route !== undefined) {
|
|
1347
|
+
transaction.objectStore(ROUTE_SLOTS).put({
|
|
1348
|
+
scope: binding.route.scope,
|
|
1349
|
+
pathKey: binding.route.pathKey,
|
|
1350
|
+
slot: binding.route.slot,
|
|
1351
|
+
replicaScopes: withConfirmedScope(existingRoute?.slot === binding.route.slot
|
|
1352
|
+
? existingRoute.replicaScopes
|
|
1353
|
+
: undefined, scopeKey),
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
await commitTransaction(transaction);
|
|
1357
|
+
for (const scope of replaced)
|
|
1358
|
+
this.announce(replicaNotice("reset", scope));
|
|
1359
|
+
this.announce(identityNotice("selector", binding.identity));
|
|
1360
|
+
}
|
|
1361
|
+
finally {
|
|
1362
|
+
removeAbort();
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
async stageReplacedPrincipals(transaction, confirmed, selector) {
|
|
1366
|
+
if (selector === undefined)
|
|
1367
|
+
return [];
|
|
1368
|
+
const candidates = transaction.objectStore(CACHE_CANDIDATES);
|
|
1369
|
+
const held = await requestResult(candidates.getAll(compoundPrefixRange(selector)));
|
|
1370
|
+
const replaced = new Map();
|
|
1371
|
+
for (const candidate of held) {
|
|
1372
|
+
const previous = replicaScopeOf(candidate.identity);
|
|
1373
|
+
if (identityInScope(confirmed, previous))
|
|
1374
|
+
continue;
|
|
1375
|
+
candidates.delete([candidate.selector, candidate.routeSlot]);
|
|
1376
|
+
replaced.set(replicaScopeKey(previous), previous);
|
|
1377
|
+
}
|
|
1378
|
+
if (replaced.size === 0)
|
|
1379
|
+
return [];
|
|
1380
|
+
const generations = transaction.objectStore(GENERATIONS);
|
|
1381
|
+
const clearedAt = await this.advanceBarrier(generations);
|
|
1382
|
+
for (const key of replaced.keys()) {
|
|
1383
|
+
const record = await requestResult(generations.get(key));
|
|
1384
|
+
generations.put({
|
|
1385
|
+
key,
|
|
1386
|
+
kind: "scope",
|
|
1387
|
+
scope: key,
|
|
1388
|
+
generation: (record?.generation ?? 0) + 1,
|
|
1389
|
+
confirmedAt: record?.confirmedAt ?? Date.now(),
|
|
1390
|
+
fencedAt: Date.now(),
|
|
1391
|
+
clearedAt,
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
return Object.freeze([...replaced.values()]);
|
|
1395
|
+
}
|
|
1396
|
+
async advanceBarrier(generations, held) {
|
|
1397
|
+
const barrier = held ?? await requestResult(generations.get(REPLICA_CLEAR_BARRIER_KEY));
|
|
1398
|
+
const generation = (barrier?.generation ?? 0) + 1;
|
|
1399
|
+
generations.put({
|
|
1400
|
+
key: REPLICA_CLEAR_BARRIER_KEY,
|
|
1401
|
+
kind: "barrier",
|
|
1402
|
+
scope: REPLICA_CLEAR_BARRIER_KEY,
|
|
1403
|
+
generation,
|
|
1404
|
+
confirmedAt: barrier?.confirmedAt ?? Date.now(),
|
|
1405
|
+
fencedAt: Date.now(),
|
|
1406
|
+
});
|
|
1407
|
+
return generation;
|
|
1408
|
+
}
|
|
1409
|
+
async bindCredential(fingerprint, identity, options = {}) {
|
|
1410
|
+
await this.bindAuthenticated({ fingerprint, identity }, options);
|
|
1411
|
+
}
|
|
1412
|
+
async restoreBoundOutcome(fingerprint, attributes, readCompatibilityHash) {
|
|
1413
|
+
const transaction = this.database.transaction([CREDENTIAL_BINDINGS, COMMITTED], "readonly");
|
|
1414
|
+
const binding = await requestResult(transaction.objectStore(CREDENTIAL_BINDINGS).get(fingerprint));
|
|
1415
|
+
if (binding === undefined) {
|
|
1416
|
+
await transactionDone(transaction);
|
|
1417
|
+
return replicaAbsent();
|
|
1418
|
+
}
|
|
1419
|
+
const record = await requestResult(transaction.objectStore(COMMITTED).get(replicaPartitionKey(binding.identity)));
|
|
1420
|
+
await transactionDone(transaction);
|
|
1421
|
+
if (record === undefined)
|
|
1422
|
+
return replicaAbsent();
|
|
1423
|
+
const stored = replicaManifestIdentity(record);
|
|
1424
|
+
if (stored !== undefined && !sameReplicationIdentity(stored, binding.identity)) {
|
|
1425
|
+
await this.unbindCredential(fingerprint);
|
|
1426
|
+
return replicaAbsent();
|
|
1427
|
+
}
|
|
1428
|
+
const validated = await this.validated(record, binding.identity, attributes, readCompatibilityHash, fingerprint);
|
|
1429
|
+
if (validated._tag !== "restored")
|
|
1430
|
+
return validated;
|
|
1431
|
+
return replicaRestored({
|
|
1432
|
+
identity: binding.identity,
|
|
1433
|
+
db: dbFromRecord(this.database, validated.replica.record, readCompatibilityHash),
|
|
1434
|
+
revision: validated.replica.record.revision,
|
|
1435
|
+
ordinal: validated.replica.record.ordinal,
|
|
1436
|
+
handles: recordHandles(validated.replica.record),
|
|
1437
|
+
release: validated.replica.release,
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
async restoreBound(fingerprint, attributes, readCompatibilityHash) {
|
|
1441
|
+
return restoredReplica(await this.restoreBoundOutcome(fingerprint, attributes, readCompatibilityHash));
|
|
1442
|
+
}
|
|
1443
|
+
async resetStaging(identity, options = {}) {
|
|
1444
|
+
this.assertScopeLive(replicaScopeOf(identity));
|
|
1445
|
+
const fence = replicaFence(options.lease, identity);
|
|
1446
|
+
const partition = replicaPartitionKey(identity);
|
|
1447
|
+
const transaction = this.database.transaction([STAGING, STAGING_CHUNKS, GENERATIONS], "readwrite");
|
|
1448
|
+
const removeAbort = abortWithSignal(transaction, options.signal);
|
|
1449
|
+
try {
|
|
1450
|
+
await enforceFence(transaction, fence);
|
|
1451
|
+
transaction.objectStore(STAGING).delete(partition);
|
|
1452
|
+
transaction.objectStore(STAGING_CHUNKS).delete(chunkRange(partition));
|
|
1453
|
+
await commitTransaction(transaction);
|
|
1454
|
+
this.announce(identityNotice("reset", identity));
|
|
1455
|
+
}
|
|
1456
|
+
finally {
|
|
1457
|
+
removeAbort();
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
async startSnapshot(frame, options = {}) {
|
|
1461
|
+
this.assertScopeLive(replicaScopeOf(frame.identity));
|
|
1462
|
+
const fence = replicaFence(options.lease, frame.identity);
|
|
1463
|
+
const partition = replicaPartitionKey(frame.identity);
|
|
1464
|
+
const transaction = this.database.transaction([COMMITTED, STAGING, STAGING_CHUNKS, GENERATIONS], "readwrite");
|
|
1465
|
+
const removeAbort = abortWithSignal(transaction, options.signal);
|
|
1466
|
+
try {
|
|
1467
|
+
await enforceFence(transaction, fence);
|
|
1468
|
+
const staging = transaction.objectStore(STAGING);
|
|
1469
|
+
const [current, committed] = await Promise.all([
|
|
1470
|
+
requestResult(staging.get(partition)),
|
|
1471
|
+
requestResult(transaction.objectStore(COMMITTED).get(partition)),
|
|
1472
|
+
]);
|
|
1473
|
+
if (current !== undefined && current.snapshot === frame.snapshot &&
|
|
1474
|
+
current.revision === frame.revision &&
|
|
1475
|
+
sameReplicationIdentity(current.identity, frame.identity) &&
|
|
1476
|
+
current.baseRevision === (committed?.revision ?? null)) {
|
|
1477
|
+
await transactionDone(transaction);
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
staging.put({
|
|
1481
|
+
partition,
|
|
1482
|
+
identity: frame.identity,
|
|
1483
|
+
snapshot: frame.snapshot,
|
|
1484
|
+
revision: frame.revision,
|
|
1485
|
+
baseRevision: committed?.revision ?? null,
|
|
1486
|
+
});
|
|
1487
|
+
transaction.objectStore(STAGING_CHUNKS).delete(chunkRange(partition));
|
|
1488
|
+
await commitTransaction(transaction);
|
|
1489
|
+
this.meter.staging++;
|
|
1490
|
+
}
|
|
1491
|
+
finally {
|
|
1492
|
+
removeAbort();
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
async stageSnapshotChunk(frame, options = {}) {
|
|
1496
|
+
this.assertScopeLive(replicaScopeOf(frame.identity));
|
|
1497
|
+
const fence = replicaFence(options.lease, frame.identity);
|
|
1498
|
+
const partition = replicaPartitionKey(frame.identity);
|
|
1499
|
+
const transaction = this.database.transaction([STAGING, STAGING_CHUNKS, GENERATIONS], "readwrite");
|
|
1500
|
+
const removeAbort = abortWithSignal(transaction, options.signal);
|
|
1501
|
+
try {
|
|
1502
|
+
await enforceFence(transaction, fence);
|
|
1503
|
+
const staging = await requestResult(transaction.objectStore(STAGING).get(partition));
|
|
1504
|
+
if (staging === undefined || staging.snapshot !== frame.snapshot ||
|
|
1505
|
+
!sameReplicationIdentity(staging.identity, frame.identity)) {
|
|
1506
|
+
await abortTransaction(transaction);
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
const chunks = transaction.objectStore(STAGING_CHUNKS);
|
|
1510
|
+
const existing = await requestResult(chunks.get([partition, frame.index]));
|
|
1511
|
+
if (existing !== undefined && !sameJson(existing.datoms, frame.datoms)) {
|
|
1512
|
+
await abortTransaction(transaction);
|
|
1513
|
+
throw new ReplicationTransitionError({
|
|
1514
|
+
reason: "duplicate snapshot chunk changed bytes",
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
if (existing === undefined) {
|
|
1518
|
+
chunks.put({
|
|
1519
|
+
partition,
|
|
1520
|
+
index: frame.index,
|
|
1521
|
+
datoms: frame.datoms,
|
|
1522
|
+
handles: frame.handles,
|
|
1523
|
+
});
|
|
1524
|
+
await commitTransaction(transaction);
|
|
1525
|
+
this.meter.stagingChunks++;
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
await commitTransaction(transaction);
|
|
1529
|
+
}
|
|
1530
|
+
finally {
|
|
1531
|
+
removeAbort();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
async stagedState(frame) {
|
|
1535
|
+
const partition = replicaPartitionKey(frame.identity);
|
|
1536
|
+
const transaction = this.database.transaction([STAGING, STAGING_CHUNKS], "readonly");
|
|
1537
|
+
const staging = await requestResult(transaction.objectStore(STAGING).get(partition));
|
|
1538
|
+
const chunks = await requestResult(transaction.objectStore(STAGING_CHUNKS).getAll(chunkRange(partition)));
|
|
1539
|
+
await transactionDone(transaction);
|
|
1540
|
+
if (staging === undefined) {
|
|
1541
|
+
return { state: emptyClientReplicationState(), baseRevision: null };
|
|
1542
|
+
}
|
|
1543
|
+
let state = transition(emptyClientReplicationState(), {
|
|
1544
|
+
type: "SnapshotStart",
|
|
1545
|
+
protocol: REPLICATION_PROTOCOL_VERSION,
|
|
1546
|
+
identity: staging.identity,
|
|
1547
|
+
snapshot: staging.snapshot,
|
|
1548
|
+
revision: staging.revision,
|
|
1549
|
+
});
|
|
1550
|
+
for (const chunk of chunks.sort((a, b) => a.index - b.index)) {
|
|
1551
|
+
state = transition(state, {
|
|
1552
|
+
type: "SnapshotChunk",
|
|
1553
|
+
protocol: REPLICATION_PROTOCOL_VERSION,
|
|
1554
|
+
identity: staging.identity,
|
|
1555
|
+
snapshot: staging.snapshot,
|
|
1556
|
+
index: chunk.index,
|
|
1557
|
+
datoms: chunk.datoms,
|
|
1558
|
+
handles: chunk.handles ?? [],
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
return { state: transition(state, frame), baseRevision: staging.baseRevision };
|
|
1562
|
+
}
|
|
1563
|
+
async installWithQuotaRecovery(partition, signal, install) {
|
|
1564
|
+
let reclaimedNodes = 0;
|
|
1565
|
+
for (let attempt = 1;; attempt++) {
|
|
1566
|
+
try {
|
|
1567
|
+
return await install();
|
|
1568
|
+
}
|
|
1569
|
+
catch (error) {
|
|
1570
|
+
const recovery = replicaQuotaRecovery(attempt, classifyReplicaStorageFailure(error));
|
|
1571
|
+
if (recovery === "propagate")
|
|
1572
|
+
throw error;
|
|
1573
|
+
if (recovery === "exhausted") {
|
|
1574
|
+
throw new ReplicaQuotaExhaustedError({ partition, reclaimedNodes });
|
|
1575
|
+
}
|
|
1576
|
+
signal?.throwIfAborted();
|
|
1577
|
+
await this.boundaries.checkpoint("replica.quota");
|
|
1578
|
+
try {
|
|
1579
|
+
reclaimedNodes = (await this.collectGarbage()).nodes;
|
|
1580
|
+
}
|
|
1581
|
+
catch (sweepError) {
|
|
1582
|
+
if (classifyReplicaStorageFailure(sweepError) !== "quota")
|
|
1583
|
+
throw sweepError;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
async commitSnapshot(frame, attributes, options = {}) {
|
|
1589
|
+
this.assertScopeLive(replicaScopeOf(frame.identity));
|
|
1590
|
+
const installed = await this.installWithQuotaRecovery(replicaPartitionKey(frame.identity), options.signal, () => this.commitSnapshotOnce(frame, attributes, options));
|
|
1591
|
+
if (installed !== undefined) {
|
|
1592
|
+
this.announce(identityNotice("replica", frame.identity));
|
|
1593
|
+
}
|
|
1594
|
+
return installed;
|
|
1595
|
+
}
|
|
1596
|
+
async commitSnapshotOnce(frame, attributes, options) {
|
|
1597
|
+
const fence = replicaFence(options.lease, frame.identity);
|
|
1598
|
+
const [staged, prior] = await Promise.all([
|
|
1599
|
+
this.stagedState(frame),
|
|
1600
|
+
this.priorManifest(frame.identity),
|
|
1601
|
+
]);
|
|
1602
|
+
const committed = staged.state.committed;
|
|
1603
|
+
if (committed?.revision !== frame.revision)
|
|
1604
|
+
return undefined;
|
|
1605
|
+
if ((prior?.revision ?? null) !== staged.baseRevision)
|
|
1606
|
+
return undefined;
|
|
1607
|
+
const partition = replicaPartitionKey(frame.identity);
|
|
1608
|
+
const materializing = this.markMaterializing(partition);
|
|
1609
|
+
try {
|
|
1610
|
+
const sweep = await this.sweepGeneration(partition);
|
|
1611
|
+
return await this.installSnapshot(frame, attributes, options, committed, staged.baseRevision, prior, fence, partition, sweep);
|
|
1612
|
+
}
|
|
1613
|
+
finally {
|
|
1614
|
+
materializing();
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
async installSnapshot(frame, attributes, options, committed, baseRevision, prior, fence, partition, sweep) {
|
|
1618
|
+
const built = await materialize(this.database, frame.identity, committed, attributes, prior, options.signal, fence, this.meter);
|
|
1619
|
+
options.signal?.throwIfAborted();
|
|
1620
|
+
await this.boundaries.checkpoint("replica.installing");
|
|
1621
|
+
const transaction = this.database.transaction([COMMITTED, COMMITTED_HEADS, STAGING, STAGING_CHUNKS, GENERATIONS], "readwrite");
|
|
1622
|
+
const removeAbort = abortWithSignal(transaction, options.signal);
|
|
1623
|
+
try {
|
|
1624
|
+
await enforceFence(transaction, fence);
|
|
1625
|
+
await this.confirmNoSweep(transaction, partition, sweep);
|
|
1626
|
+
const current = await requestResult(transaction.objectStore(STAGING).get(built.record.partition));
|
|
1627
|
+
const currentCommitted = await requestResult(transaction.objectStore(COMMITTED).get(built.record.partition));
|
|
1628
|
+
const head = await requestResult(transaction.objectStore(COMMITTED_HEADS).get(built.record.partition));
|
|
1629
|
+
if (current === undefined || current.snapshot !== frame.snapshot ||
|
|
1630
|
+
current.revision !== frame.revision ||
|
|
1631
|
+
!sameReplicationIdentity(current.identity, frame.identity) ||
|
|
1632
|
+
(currentCommitted?.revision ?? null) !== baseRevision) {
|
|
1633
|
+
await abortTransaction(transaction);
|
|
1634
|
+
return undefined;
|
|
1635
|
+
}
|
|
1636
|
+
if (!supersedesStoredHead(storedOrdinal(head, currentCommitted), built.record)) {
|
|
1637
|
+
await abortTransaction(transaction);
|
|
1638
|
+
throw new ReplicaSupersededError({
|
|
1639
|
+
partition,
|
|
1640
|
+
revision: frame.revision,
|
|
1641
|
+
ordinal: frame.ordinal,
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
transaction.objectStore(COMMITTED).put(built.record);
|
|
1645
|
+
transaction.objectStore(COMMITTED_HEADS).put(committedHead(built.record));
|
|
1646
|
+
transaction.objectStore(STAGING).delete(built.record.partition);
|
|
1647
|
+
transaction.objectStore(STAGING_CHUNKS).delete(chunkRange(built.record.partition));
|
|
1648
|
+
await this.boundaries.checkpoint("replica.install");
|
|
1649
|
+
await commitTransaction(transaction);
|
|
1650
|
+
this.meter.manifests++;
|
|
1651
|
+
this.meter.heads++;
|
|
1652
|
+
}
|
|
1653
|
+
catch (error) {
|
|
1654
|
+
await abortTransaction(transaction);
|
|
1655
|
+
throw error;
|
|
1656
|
+
}
|
|
1657
|
+
finally {
|
|
1658
|
+
removeAbort();
|
|
1659
|
+
}
|
|
1660
|
+
return {
|
|
1661
|
+
db: built.db,
|
|
1662
|
+
revision: built.record.revision,
|
|
1663
|
+
ordinal: built.record.ordinal,
|
|
1664
|
+
handles: recordHandles(built.record),
|
|
1665
|
+
release: this.retainRoots(frame.identity, built.record.roots),
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
async acknowledgeOrdinal(acknowledgement, options = {}) {
|
|
1669
|
+
this.assertScopeLive(replicaScopeOf(acknowledgement.identity));
|
|
1670
|
+
const fence = replicaFence(options.lease, acknowledgement.identity);
|
|
1671
|
+
const partition = replicaPartitionKey(acknowledgement.identity);
|
|
1672
|
+
const sweep = await this.sweepGeneration(partition);
|
|
1673
|
+
options.signal?.throwIfAborted();
|
|
1674
|
+
await this.boundaries.checkpoint("replica.installing");
|
|
1675
|
+
const write = this.database.transaction([COMMITTED, COMMITTED_HEADS, GENERATIONS], "readwrite");
|
|
1676
|
+
const removeAbort = abortWithSignal(write, options.signal);
|
|
1677
|
+
try {
|
|
1678
|
+
await enforceFence(write, fence);
|
|
1679
|
+
await this.confirmNoSweep(write, partition, sweep);
|
|
1680
|
+
const [current, head] = await Promise.all([
|
|
1681
|
+
requestResult(write.objectStore(COMMITTED).get(partition)),
|
|
1682
|
+
requestResult(write.objectStore(COMMITTED_HEADS).get(partition)),
|
|
1683
|
+
]);
|
|
1684
|
+
if (current === undefined ||
|
|
1685
|
+
current.revision !== acknowledgement.revision) {
|
|
1686
|
+
await abortTransaction(write);
|
|
1687
|
+
return undefined;
|
|
1688
|
+
}
|
|
1689
|
+
if (current.ordinal >= acknowledgement.ordinal) {
|
|
1690
|
+
if (recordOrdinal(head) === undefined) {
|
|
1691
|
+
write.objectStore(COMMITTED_HEADS).put(committedHead(current));
|
|
1692
|
+
await commitTransaction(write);
|
|
1693
|
+
this.meter.heads++;
|
|
1694
|
+
return current.ordinal;
|
|
1695
|
+
}
|
|
1696
|
+
await transactionDone(write);
|
|
1697
|
+
return current.ordinal;
|
|
1698
|
+
}
|
|
1699
|
+
const acknowledged = {
|
|
1700
|
+
...current,
|
|
1701
|
+
ordinal: acknowledgement.ordinal,
|
|
1702
|
+
};
|
|
1703
|
+
write.objectStore(COMMITTED).put(acknowledged);
|
|
1704
|
+
write.objectStore(COMMITTED_HEADS).put(committedHead(acknowledged));
|
|
1705
|
+
await this.boundaries.checkpoint("replica.install");
|
|
1706
|
+
await commitTransaction(write);
|
|
1707
|
+
this.meter.manifests++;
|
|
1708
|
+
this.meter.heads++;
|
|
1709
|
+
return acknowledgement.ordinal;
|
|
1710
|
+
}
|
|
1711
|
+
catch (error) {
|
|
1712
|
+
await abortTransaction(write);
|
|
1713
|
+
throw error;
|
|
1714
|
+
}
|
|
1715
|
+
finally {
|
|
1716
|
+
removeAbort();
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
async applyChange(frame, options = {}) {
|
|
1720
|
+
this.assertScopeLive(replicaScopeOf(frame.identity));
|
|
1721
|
+
const installed = await this.installWithQuotaRecovery(replicaPartitionKey(frame.identity), options.signal, () => this.applyChangeOnce(frame, options));
|
|
1722
|
+
if (installed !== undefined) {
|
|
1723
|
+
this.announce(identityNotice("replica", frame.identity));
|
|
1724
|
+
}
|
|
1725
|
+
return installed;
|
|
1726
|
+
}
|
|
1727
|
+
async applyChangeOnce(frame, options) {
|
|
1728
|
+
const fence = replicaFence(options.lease, frame.identity);
|
|
1729
|
+
const partition = replicaPartitionKey(frame.identity);
|
|
1730
|
+
const read = this.database.transaction(COMMITTED, "readonly");
|
|
1731
|
+
const prior = await requestResult(read.objectStore(COMMITTED).get(partition));
|
|
1732
|
+
await transactionDone(read);
|
|
1733
|
+
if (prior === undefined)
|
|
1734
|
+
return undefined;
|
|
1735
|
+
const state = transition({
|
|
1736
|
+
identity: prior.identity,
|
|
1737
|
+
committed: {
|
|
1738
|
+
revision: prior.revision,
|
|
1739
|
+
ordinal: prior.ordinal,
|
|
1740
|
+
datoms: prior.datoms,
|
|
1741
|
+
handles: new Map(prior.entityHandles),
|
|
1742
|
+
},
|
|
1743
|
+
closed: false,
|
|
1744
|
+
}, frame);
|
|
1745
|
+
if (state.committed === undefined || state.committed.revision === prior.revision) {
|
|
1746
|
+
return {
|
|
1747
|
+
db: dbFromRecord(this.database, prior, frame.identity.readCompatibilityHash),
|
|
1748
|
+
revision: prior.revision,
|
|
1749
|
+
ordinal: prior.ordinal,
|
|
1750
|
+
handles: recordHandles(prior),
|
|
1751
|
+
release: this.retainRoots(frame.identity, prior.roots),
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
const materializing = this.markMaterializing(partition);
|
|
1755
|
+
try {
|
|
1756
|
+
const sweep = await this.sweepGeneration(partition);
|
|
1757
|
+
return await this.installChange(frame, options, state.committed, prior, fence, partition, sweep);
|
|
1758
|
+
}
|
|
1759
|
+
finally {
|
|
1760
|
+
materializing();
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
async installChange(frame, options, committed, prior, fence, partition, sweep) {
|
|
1764
|
+
const built = await materialize(this.database, frame.identity, committed, prior.attributes, prior, options.signal, fence, this.meter);
|
|
1765
|
+
options.signal?.throwIfAborted();
|
|
1766
|
+
await this.boundaries.checkpoint("replica.installing");
|
|
1767
|
+
const write = this.database.transaction([COMMITTED, COMMITTED_HEADS, GENERATIONS], "readwrite");
|
|
1768
|
+
const removeAbort = abortWithSignal(write, options.signal);
|
|
1769
|
+
try {
|
|
1770
|
+
await enforceFence(write, fence);
|
|
1771
|
+
await this.confirmNoSweep(write, partition, sweep);
|
|
1772
|
+
const current = await requestResult(write.objectStore(COMMITTED).get(partition));
|
|
1773
|
+
const head = await requestResult(write.objectStore(COMMITTED_HEADS).get(partition));
|
|
1774
|
+
if (current?.revision !== prior.revision) {
|
|
1775
|
+
await abortTransaction(write);
|
|
1776
|
+
return undefined;
|
|
1777
|
+
}
|
|
1778
|
+
if (!supersedesStoredHead(storedOrdinal(head, current), built.record)) {
|
|
1779
|
+
await abortTransaction(write);
|
|
1780
|
+
throw new ReplicaSupersededError({
|
|
1781
|
+
partition,
|
|
1782
|
+
revision: frame.revision,
|
|
1783
|
+
ordinal: frame.ordinal,
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
write.objectStore(COMMITTED).put(built.record);
|
|
1787
|
+
write.objectStore(COMMITTED_HEADS).put(committedHead(built.record));
|
|
1788
|
+
await this.boundaries.checkpoint("replica.install");
|
|
1789
|
+
await commitTransaction(write);
|
|
1790
|
+
this.meter.manifests++;
|
|
1791
|
+
this.meter.heads++;
|
|
1792
|
+
}
|
|
1793
|
+
catch (error) {
|
|
1794
|
+
await abortTransaction(write);
|
|
1795
|
+
throw error;
|
|
1796
|
+
}
|
|
1797
|
+
finally {
|
|
1798
|
+
removeAbort();
|
|
1799
|
+
}
|
|
1800
|
+
return {
|
|
1801
|
+
db: built.db,
|
|
1802
|
+
revision: built.record.revision,
|
|
1803
|
+
ordinal: built.record.ordinal,
|
|
1804
|
+
handles: recordHandles(built.record),
|
|
1805
|
+
release: this.retainRoots(frame.identity, built.record.roots),
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
//# sourceMappingURL=indexeddb.js.map
|