@rocicorp/zero 1.11.0-canary.12 → 1.11.0-canary.14
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/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +25 -25
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/otel/src/log-options.d.ts +16 -0
- package/out/otel/src/log-options.d.ts.map +1 -1
- package/out/otel/src/log-options.js +54 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
- package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
- package/out/replicache/src/get-kv-store-provider.js +4 -4
- package/out/replicache/src/get-kv-store-provider.js.map +1 -1
- package/out/replicache/src/kv/idb-store.d.ts +10 -1
- package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store.js +18 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
- package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
- package/out/replicache/src/kv/mem-fallback-store.js +177 -0
- package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
- package/out/replicache/src/kv/op-sqlite/store.js +3 -3
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts +9 -0
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +86 -6
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/new-client-channel.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +17 -3
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +81 -11
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/idb-databases-store-db-name.js +1 -1
- package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
- package/out/replicache/src/persist/persist.d.ts.map +1 -1
- package/out/replicache/src/persist/persist.js +6 -3
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +43 -3
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +135 -17
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/storage-failure.d.ts +37 -0
- package/out/replicache/src/storage-failure.d.ts.map +1 -0
- package/out/replicache/src/storage-failure.js +31 -0
- package/out/replicache/src/storage-failure.js.map +1 -0
- package/out/shared/src/random-values.js +12 -1
- package/out/shared/src/random-values.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/zero.js +2 -1
- package/out/zero-cache/src/config/zero-config.d.ts +26 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +36 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
- package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
- package/out/zero-cache/src/observability/log-throttle.js +76 -0
- package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
- package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
- package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js +2 -0
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +20 -2
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +189 -27
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +204 -18
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +11 -2
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +11 -2
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +43 -0
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +57 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +20 -6
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +17 -7
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +66 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +154 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +5 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +20 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +26 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +88 -0
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js +9 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +29 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +34 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.d.ts +159 -0
- package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
- package/out/zero-cache/src/services/plannerz.js +263 -0
- package/out/zero-cache/src/services/plannerz.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.js +1 -1
- package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +48 -5
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -3
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +11 -0
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +20 -7
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +36 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +393 -30
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +77 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.js +206 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +11 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +7 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +50 -3
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +29 -0
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +8 -23
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +1 -0
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-client/src/mod.js +1 -0
- package/out/zero-protocol/src/down.d.ts +2 -2
- package/out/zero-react/src/zero.js +1 -0
- package/out/zero-solid/src/zero.js +1 -0
- package/out/zql/src/builder/builder.d.ts +6 -0
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +5 -4
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +19 -22
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +34 -18
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +13 -0
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +1 -1
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/take-gate.d.ts +23 -2
- package/out/zql/src/ivm/take-gate.d.ts.map +1 -1
- package/out/zql/src/ivm/take-gate.js +23 -1
- package/out/zql/src/ivm/take-gate.js.map +1 -1
- package/out/zql/src/planner/planner-builder.d.ts +12 -1
- package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
- package/out/zql/src/planner/planner-builder.js +8 -1
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.d.ts +43 -0
- package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
- package/out/zql/src/planner/planner-connection.js +31 -4
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-graph.d.ts +10 -0
- package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
- package/out/zql/src/planner/planner-graph.js +14 -0
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-warnings.d.ts +83 -0
- package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
- package/out/zql/src/planner/planner-warnings.js +78 -0
- package/out/zql/src/planner/planner-warnings.js.map +1 -0
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +30 -8
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zqlite/src/pending-delta.d.ts +110 -0
- package/out/zqlite/src/pending-delta.d.ts.map +1 -0
- package/out/zqlite/src/pending-delta.js +278 -0
- package/out/zqlite/src/pending-delta.js.map +1 -0
- package/out/zqlite/src/query-delegate.d.ts.map +1 -1
- package/out/zqlite/src/query-delegate.js +5 -1
- package/out/zqlite/src/query-delegate.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +52 -1
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js +2 -26
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
- package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
- package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
- package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
- package/out/zqlite/src/table-source.d.ts +68 -0
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +206 -7
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -35
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts +0 -156
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.js +0 -15
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.js.map +0 -1
|
@@ -9,5 +9,12 @@ import type { AST } from '../../zero-protocol/src/ast.ts';
|
|
|
9
9
|
* console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
|
-
export declare function astToZQL(ast: AST): string;
|
|
12
|
+
export declare function astToZQL(ast: AST, options?: AstToZQLOptions): string;
|
|
13
|
+
export type AstToZQLOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Renders every literal value, and the `start` row, as `?` so that the
|
|
16
|
+
* output can be logged without leaking row data or query arguments.
|
|
17
|
+
*/
|
|
18
|
+
readonly redactLiterals?: boolean | undefined;
|
|
19
|
+
};
|
|
13
20
|
//# sourceMappingURL=ast-to-zql.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-to-zql.d.ts","sourceRoot":"","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,GAAG,EAWJ,MAAM,gCAAgC,CAAC;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"ast-to-zql.d.ts","sourceRoot":"","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,GAAG,EAWJ,MAAM,gCAAgC,CAAC;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CAyCxE;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/C,CAAC"}
|
|
@@ -13,53 +13,53 @@ import { SUBQ_PREFIX } from "../../zero-protocol/src/ast.js";
|
|
|
13
13
|
* console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
function astToZQL(ast) {
|
|
16
|
+
function astToZQL(ast, options = {}) {
|
|
17
17
|
let code = "";
|
|
18
|
-
if (ast.where) code += transformCondition(ast.where, ".where", /* @__PURE__ */ new Set());
|
|
18
|
+
if (ast.where) code += transformCondition(ast.where, ".where", /* @__PURE__ */ new Set(), options);
|
|
19
19
|
if (ast.related && ast.related.length > 0) for (const related of ast.related) if (related.hidden) {
|
|
20
20
|
const nestedRelated = related.subquery.related?.[0];
|
|
21
|
-
if (nestedRelated) code += transformRelated(nestedRelated);
|
|
22
|
-
} else code += transformRelated(related);
|
|
21
|
+
if (nestedRelated) code += transformRelated(nestedRelated, options);
|
|
22
|
+
} else code += transformRelated(related, options);
|
|
23
23
|
if (ast.orderBy && ast.orderBy.length > 0) code += transformOrder(ast.orderBy);
|
|
24
24
|
if (ast.limit !== void 0) code += `.limit(${ast.limit})`;
|
|
25
25
|
if (ast.start) {
|
|
26
26
|
const { row, exclusive } = ast.start;
|
|
27
|
-
code += `.start(${JSON.stringify(row)}${exclusive ? "" : ", { inclusive: true }"})`;
|
|
27
|
+
code += `.start(${options.redactLiterals ? "?" : JSON.stringify(row)}${exclusive ? "" : ", { inclusive: true }"})`;
|
|
28
28
|
}
|
|
29
29
|
return code;
|
|
30
30
|
}
|
|
31
|
-
function transformCondition(condition, prefix, args) {
|
|
31
|
+
function transformCondition(condition, prefix, args, options) {
|
|
32
32
|
switch (condition.type) {
|
|
33
|
-
case "simple": return transformSimpleCondition(condition, prefix);
|
|
33
|
+
case "simple": return transformSimpleCondition(condition, prefix, options);
|
|
34
34
|
case "and":
|
|
35
|
-
case "or": return transformLogicalCondition(condition, prefix, args);
|
|
36
|
-
case "correlatedSubquery": return transformExistsCondition(condition, prefix, args);
|
|
35
|
+
case "or": return transformLogicalCondition(condition, prefix, args, options);
|
|
36
|
+
case "correlatedSubquery": return transformExistsCondition(condition, prefix, args, options);
|
|
37
37
|
default: unreachable(condition);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
function transformSimpleCondition(condition, prefix) {
|
|
40
|
+
function transformSimpleCondition(condition, prefix, options) {
|
|
41
41
|
const { left, op, right } = condition;
|
|
42
|
-
const leftCode = transformValuePosition(left);
|
|
43
|
-
const rightCode = transformValuePosition(right);
|
|
42
|
+
const leftCode = transformValuePosition(left, options);
|
|
43
|
+
const rightCode = transformValuePosition(right, options);
|
|
44
44
|
if (op === "=") return `${prefix}(${leftCode}, ${rightCode})`;
|
|
45
45
|
return `${prefix}(${leftCode}, '${op}', ${rightCode})`;
|
|
46
46
|
}
|
|
47
|
-
function transformLogicalCondition(condition, prefix, args) {
|
|
47
|
+
function transformLogicalCondition(condition, prefix, args, options) {
|
|
48
48
|
const { type, conditions } = condition;
|
|
49
|
-
if (conditions.length === 1) return transformCondition(conditions[0], prefix, args);
|
|
49
|
+
if (conditions.length === 1) return transformCondition(conditions[0], prefix, args, options);
|
|
50
50
|
if (type === "and") {
|
|
51
|
-
const parts = conditions.map((c) => transformCondition(c, prefix, args));
|
|
51
|
+
const parts = conditions.map((c) => transformCondition(c, prefix, args, options));
|
|
52
52
|
if (prefix === ".where") return parts.join("");
|
|
53
53
|
args.add("and");
|
|
54
54
|
return "and(" + parts.join(", ") + ")";
|
|
55
55
|
}
|
|
56
56
|
args = /* @__PURE__ */ new Set();
|
|
57
|
-
const conditionsCode = conditions.map((c) => transformCondition(c, "cmp", args)).join(", ");
|
|
57
|
+
const conditionsCode = conditions.map((c) => transformCondition(c, "cmp", args, options)).join(", ");
|
|
58
58
|
args.add("cmp");
|
|
59
59
|
args.add(type);
|
|
60
60
|
return `.where(({${toSorted(args).join(", ")}}) => ${type}(${conditionsCode}))`;
|
|
61
61
|
}
|
|
62
|
-
function transformExistsCondition(condition, prefix, args) {
|
|
62
|
+
function transformExistsCondition(condition, prefix, args, options) {
|
|
63
63
|
const { related, op } = condition;
|
|
64
64
|
const relationship = extractRelationshipName(related);
|
|
65
65
|
const nextSubquery = getNextExistsSubquery(related);
|
|
@@ -74,15 +74,15 @@ function transformExistsCondition(condition, prefix, args) {
|
|
|
74
74
|
args.add("exists");
|
|
75
75
|
return `exists('${relationship}'${optionsStr})`;
|
|
76
76
|
}
|
|
77
|
-
if (prefix === ".where") return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;
|
|
77
|
+
if (prefix === ".where") return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr})`;
|
|
78
78
|
args.add("exists");
|
|
79
|
-
return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;
|
|
79
|
+
return `exists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr})`;
|
|
80
80
|
}
|
|
81
81
|
if (hasSubQueryProps) {
|
|
82
|
-
if (prefix === ".where") return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})))`;
|
|
82
|
+
if (prefix === ".where") return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr})))`;
|
|
83
83
|
args.add("not");
|
|
84
84
|
args.add("exists");
|
|
85
|
-
return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr}))`;
|
|
85
|
+
return `not(exists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr}))`;
|
|
86
86
|
}
|
|
87
87
|
if (prefix === ".where") return `.where(({exists, not}) => not(exists('${relationship}'${optionsStr})))`;
|
|
88
88
|
args.add("not");
|
|
@@ -97,11 +97,11 @@ function extractRelationshipName(related) {
|
|
|
97
97
|
const alias = must(related.subquery.alias);
|
|
98
98
|
return alias.startsWith("zsubq_") ? alias.substring(SUBQ_PREFIX.length) : alias;
|
|
99
99
|
}
|
|
100
|
-
function transformRelated(related) {
|
|
100
|
+
function transformRelated(related, options) {
|
|
101
101
|
const { alias } = related.subquery;
|
|
102
102
|
if (!alias) return "";
|
|
103
103
|
let code = `.related('${alias}'`;
|
|
104
|
-
if (related.subquery.where || related.subquery.related && related.subquery.related.length > 0 || related.subquery.orderBy || related.subquery.limit) code += ", q => q" + astToZQL(related.subquery);
|
|
104
|
+
if (related.subquery.where || related.subquery.related && related.subquery.related.length > 0 || related.subquery.orderBy || related.subquery.limit) code += ", q => q" + astToZQL(related.subquery, options);
|
|
105
105
|
code += ")";
|
|
106
106
|
return code;
|
|
107
107
|
}
|
|
@@ -110,9 +110,9 @@ function transformOrder(orderBy) {
|
|
|
110
110
|
for (const [field, direction] of orderBy) code += `.orderBy('${field}', '${direction}')`;
|
|
111
111
|
return code;
|
|
112
112
|
}
|
|
113
|
-
function transformValuePosition(value) {
|
|
113
|
+
function transformValuePosition(value, options) {
|
|
114
114
|
switch (value.type) {
|
|
115
|
-
case "literal": return transformLiteral(value);
|
|
115
|
+
case "literal": return options.redactLiterals ? "?" : transformLiteral(value);
|
|
116
116
|
case "column": return `'${value.name}'`;
|
|
117
117
|
case "static": return transformParameter(value);
|
|
118
118
|
default: unreachable(value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-to-zql.js","names":[],"sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"sourcesContent":["import {unreachable} from '../../shared/src/asserts.ts';\nimport {toSorted} from '../../shared/src/iterables.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralReference,\n Ordering,\n Parameter,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {SUBQ_PREFIX} from '../../zero-protocol/src/ast.ts';\n\n/**\n * Converts an AST to the equivalent query builder code.\n * This is useful for debugging and understanding queries.\n *\n * @example\n * ```\n * const ast = query.issue.where('id', '=', 123)[astSymbol];\n * console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)\n * ```\n */\nexport function astToZQL(ast: AST): string {\n let code = '';\n\n // Handle where conditions\n if (ast.where) {\n code += transformCondition(ast.where, '.where', new Set());\n }\n\n // Handle related subqueries\n if (ast.related && ast.related.length > 0) {\n for (const related of ast.related) {\n if (related.hidden) {\n const nestedRelated = related.subquery.related?.[0];\n if (nestedRelated) {\n code += transformRelated(nestedRelated);\n }\n } else {\n code += transformRelated(related);\n }\n }\n }\n\n // Handle orderBy\n if (ast.orderBy && ast.orderBy.length > 0) {\n code += transformOrder(ast.orderBy);\n }\n\n // Handle limit\n if (ast.limit !== undefined) {\n code += `.limit(${ast.limit})`;\n }\n\n // Handle start\n if (ast.start) {\n const {row, exclusive} = ast.start;\n code += `.start(${JSON.stringify(row)}${\n exclusive ? '' : ', { inclusive: true }'\n })`;\n }\n\n return code;\n}\n\ntype Args = Set<string>;\n\ntype Prefix = '.where' | 'cmp';\n\nfunction transformCondition(\n condition: Condition,\n prefix: Prefix,\n args: Args,\n): string {\n switch (condition.type) {\n case 'simple':\n return transformSimpleCondition(condition, prefix);\n case 'and':\n case 'or':\n return transformLogicalCondition(condition, prefix, args);\n case 'correlatedSubquery':\n return transformExistsCondition(condition, prefix, args);\n default:\n unreachable(condition);\n }\n}\n\nfunction transformSimpleCondition(\n condition: SimpleCondition,\n prefix: Prefix,\n): string {\n const {left, op, right} = condition;\n\n const leftCode = transformValuePosition(left);\n const rightCode = transformValuePosition(right);\n\n // Handle the shorthand form for equals\n if (op === '=') {\n return `${prefix}(${leftCode}, ${rightCode})`;\n }\n\n return `${prefix}(${leftCode}, '${op}', ${rightCode})`;\n}\n\nfunction transformLogicalCondition(\n condition: Conjunction | Disjunction,\n prefix: Prefix,\n args: Args,\n): string {\n const {type, conditions} = condition;\n\n // For single condition, no need for logical operator\n if (conditions.length === 1) {\n return transformCondition(conditions[0], prefix, args);\n }\n\n // Generate multiple where calls for top-level AND conditions\n if (type === 'and') {\n const parts = conditions.map(c => transformCondition(c, prefix, args));\n // Simply concatenate the where conditions\n if (prefix === '.where') {\n return parts.join('');\n }\n args.add('and');\n return 'and(' + parts.join(', ') + ')';\n }\n\n args = new Set<string>();\n\n // Handle nested conditions with a callback for OR conditions and nested ANDs/ORs\n const conditionsCode = conditions\n .map(c => transformCondition(c, 'cmp', args))\n .join(', ');\n\n args.add('cmp');\n args.add(type);\n const argsCode = toSorted(args).join(', ');\n\n return `.where(({${argsCode}}) => ${type}(${conditionsCode}))`;\n}\n\nfunction transformExistsCondition(\n condition: CorrelatedSubqueryCondition,\n prefix: '.where' | 'cmp',\n args: Set<string>,\n): string {\n const {related, op} = condition;\n const relationship = extractRelationshipName(related);\n\n const nextSubquery = getNextExistsSubquery(related);\n\n // Check if subquery has additional properties\n const hasSubQueryProps =\n nextSubquery.where ||\n (nextSubquery.related && nextSubquery.related.length > 0) ||\n nextSubquery.orderBy ||\n nextSubquery.limit;\n\n // Build options string for flip and scalar\n const optionParts: string[] = [];\n if (condition.flip !== undefined) {\n optionParts.push(`flip: ${condition.flip}`);\n }\n if (condition.scalar !== undefined) {\n optionParts.push(`scalar: ${condition.scalar}`);\n }\n const optionsStr =\n optionParts.length > 0 ? `, {${optionParts.join(', ')}}` : '';\n\n if (op === 'EXISTS') {\n if (!hasSubQueryProps) {\n if (prefix === '.where') {\n return `.whereExists('${relationship}'${optionsStr})`;\n }\n args.add('exists');\n return `exists('${relationship}'${optionsStr})`;\n }\n\n if (prefix === '.where') {\n return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;\n }\n prefix satisfies 'cmp';\n args.add('exists');\n return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;\n }\n\n op satisfies 'NOT EXISTS';\n\n if (hasSubQueryProps) {\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(\n nextSubquery,\n )}${optionsStr})))`;\n }\n prefix satisfies 'cmp';\n args.add('not');\n args.add('exists');\n return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr}))`;\n }\n\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}'${optionsStr})))`;\n }\n args.add('not');\n args.add('exists');\n\n return `not(exists('${relationship}'${optionsStr})))`;\n}\n\n// If the `exists` is applied against a junction edge, both hops will have the same alias and both hops will be exists conditions.\nfunction getNextExistsSubquery(related: CorrelatedSubquery): AST {\n if (\n related.subquery.where?.type === 'correlatedSubquery' &&\n related.subquery.where.related.subquery.alias?.includes(\n SUBQ_PREFIX + 'zhidden_',\n )\n ) {\n return getNextExistsSubquery(related.subquery.where.related);\n }\n\n return related.subquery;\n}\n\nfunction extractRelationshipName(related: CorrelatedSubquery): string {\n const alias = must(related.subquery.alias);\n return alias.startsWith(SUBQ_PREFIX)\n ? alias.substring(SUBQ_PREFIX.length)\n : alias;\n}\n\nfunction transformRelated(related: CorrelatedSubquery): string {\n const {alias} = related.subquery;\n if (!alias) return '';\n\n const relationship = alias;\n let code = `.related('${relationship}'`;\n\n // If the subquery has additional filters or configurations\n if (\n related.subquery.where ||\n (related.subquery.related && related.subquery.related.length > 0) ||\n related.subquery.orderBy ||\n related.subquery.limit\n ) {\n code += ', q => q' + astToZQL(related.subquery);\n }\n\n code += ')';\n return code;\n}\n\nfunction transformOrder(orderBy: Ordering): string {\n let code = '';\n for (const [field, direction] of orderBy) {\n code += `.orderBy('${field}', '${direction}')`;\n }\n return code;\n}\n\nfunction transformValuePosition(value: ValuePosition): string {\n switch (value.type) {\n case 'literal':\n return transformLiteral(value);\n case 'column':\n return `'${value.name}'`;\n case 'static':\n return transformParameter(value);\n default:\n unreachable(value);\n }\n}\n\nfunction transformLiteral(literal: LiteralReference): string {\n if (literal.value === null) {\n return 'null';\n }\n if (Array.isArray(literal.value)) {\n return JSON.stringify(literal.value);\n }\n if (typeof literal.value === 'string') {\n return `'${literal.value.replace(/'/g, \"\\\\'\")}'`;\n }\n return String(literal.value);\n}\n\nfunction transformParameter(param: Parameter): string {\n const fieldStr = Array.isArray(param.field)\n ? `[${param.field.map(f => `'${f}'`).join(', ')}]`\n : `'${param.field}'`;\n\n return `authParam(${fieldStr})`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ast-to-zql.js","names":[],"sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"sourcesContent":["import {unreachable} from '../../shared/src/asserts.ts';\nimport {toSorted} from '../../shared/src/iterables.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralReference,\n Ordering,\n Parameter,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {SUBQ_PREFIX} from '../../zero-protocol/src/ast.ts';\n\n/**\n * Converts an AST to the equivalent query builder code.\n * This is useful for debugging and understanding queries.\n *\n * @example\n * ```\n * const ast = query.issue.where('id', '=', 123)[astSymbol];\n * console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)\n * ```\n */\nexport function astToZQL(ast: AST, options: AstToZQLOptions = {}): string {\n let code = '';\n\n // Handle where conditions\n if (ast.where) {\n code += transformCondition(ast.where, '.where', new Set(), options);\n }\n\n // Handle related subqueries\n if (ast.related && ast.related.length > 0) {\n for (const related of ast.related) {\n if (related.hidden) {\n const nestedRelated = related.subquery.related?.[0];\n if (nestedRelated) {\n code += transformRelated(nestedRelated, options);\n }\n } else {\n code += transformRelated(related, options);\n }\n }\n }\n\n // Handle orderBy\n if (ast.orderBy && ast.orderBy.length > 0) {\n code += transformOrder(ast.orderBy);\n }\n\n // Handle limit\n if (ast.limit !== undefined) {\n code += `.limit(${ast.limit})`;\n }\n\n // Handle start\n if (ast.start) {\n const {row, exclusive} = ast.start;\n code += `.start(${options.redactLiterals ? '?' : JSON.stringify(row)}${\n exclusive ? '' : ', { inclusive: true }'\n })`;\n }\n\n return code;\n}\n\nexport type AstToZQLOptions = {\n /**\n * Renders every literal value, and the `start` row, as `?` so that the\n * output can be logged without leaking row data or query arguments.\n */\n readonly redactLiterals?: boolean | undefined;\n};\n\ntype Args = Set<string>;\n\ntype Prefix = '.where' | 'cmp';\n\nfunction transformCondition(\n condition: Condition,\n prefix: Prefix,\n args: Args,\n options: AstToZQLOptions,\n): string {\n switch (condition.type) {\n case 'simple':\n return transformSimpleCondition(condition, prefix, options);\n case 'and':\n case 'or':\n return transformLogicalCondition(condition, prefix, args, options);\n case 'correlatedSubquery':\n return transformExistsCondition(condition, prefix, args, options);\n default:\n unreachable(condition);\n }\n}\n\nfunction transformSimpleCondition(\n condition: SimpleCondition,\n prefix: Prefix,\n options: AstToZQLOptions,\n): string {\n const {left, op, right} = condition;\n\n const leftCode = transformValuePosition(left, options);\n const rightCode = transformValuePosition(right, options);\n\n // Handle the shorthand form for equals\n if (op === '=') {\n return `${prefix}(${leftCode}, ${rightCode})`;\n }\n\n return `${prefix}(${leftCode}, '${op}', ${rightCode})`;\n}\n\nfunction transformLogicalCondition(\n condition: Conjunction | Disjunction,\n prefix: Prefix,\n args: Args,\n options: AstToZQLOptions,\n): string {\n const {type, conditions} = condition;\n\n // For single condition, no need for logical operator\n if (conditions.length === 1) {\n return transformCondition(conditions[0], prefix, args, options);\n }\n\n // Generate multiple where calls for top-level AND conditions\n if (type === 'and') {\n const parts = conditions.map(c =>\n transformCondition(c, prefix, args, options),\n );\n // Simply concatenate the where conditions\n if (prefix === '.where') {\n return parts.join('');\n }\n args.add('and');\n return 'and(' + parts.join(', ') + ')';\n }\n\n args = new Set<string>();\n\n // Handle nested conditions with a callback for OR conditions and nested ANDs/ORs\n const conditionsCode = conditions\n .map(c => transformCondition(c, 'cmp', args, options))\n .join(', ');\n\n args.add('cmp');\n args.add(type);\n const argsCode = toSorted(args).join(', ');\n\n return `.where(({${argsCode}}) => ${type}(${conditionsCode}))`;\n}\n\nfunction transformExistsCondition(\n condition: CorrelatedSubqueryCondition,\n prefix: '.where' | 'cmp',\n args: Set<string>,\n options: AstToZQLOptions,\n): string {\n const {related, op} = condition;\n const relationship = extractRelationshipName(related);\n\n const nextSubquery = getNextExistsSubquery(related);\n\n // Check if subquery has additional properties\n const hasSubQueryProps =\n nextSubquery.where ||\n (nextSubquery.related && nextSubquery.related.length > 0) ||\n nextSubquery.orderBy ||\n nextSubquery.limit;\n\n // Build options string for flip and scalar\n const optionParts: string[] = [];\n if (condition.flip !== undefined) {\n optionParts.push(`flip: ${condition.flip}`);\n }\n if (condition.scalar !== undefined) {\n optionParts.push(`scalar: ${condition.scalar}`);\n }\n const optionsStr =\n optionParts.length > 0 ? `, {${optionParts.join(', ')}}` : '';\n\n if (op === 'EXISTS') {\n if (!hasSubQueryProps) {\n if (prefix === '.where') {\n return `.whereExists('${relationship}'${optionsStr})`;\n }\n args.add('exists');\n return `exists('${relationship}'${optionsStr})`;\n }\n\n if (prefix === '.where') {\n return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr})`;\n }\n prefix satisfies 'cmp';\n args.add('exists');\n return `exists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr})`;\n }\n\n op satisfies 'NOT EXISTS';\n\n if (hasSubQueryProps) {\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(\n nextSubquery,\n options,\n )}${optionsStr})))`;\n }\n prefix satisfies 'cmp';\n args.add('not');\n args.add('exists');\n return `not(exists('${relationship}', q => q${astToZQL(nextSubquery, options)}${optionsStr}))`;\n }\n\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}'${optionsStr})))`;\n }\n args.add('not');\n args.add('exists');\n\n return `not(exists('${relationship}'${optionsStr})))`;\n}\n\n// If the `exists` is applied against a junction edge, both hops will have the same alias and both hops will be exists conditions.\nfunction getNextExistsSubquery(related: CorrelatedSubquery): AST {\n if (\n related.subquery.where?.type === 'correlatedSubquery' &&\n related.subquery.where.related.subquery.alias?.includes(\n SUBQ_PREFIX + 'zhidden_',\n )\n ) {\n return getNextExistsSubquery(related.subquery.where.related);\n }\n\n return related.subquery;\n}\n\nfunction extractRelationshipName(related: CorrelatedSubquery): string {\n const alias = must(related.subquery.alias);\n return alias.startsWith(SUBQ_PREFIX)\n ? alias.substring(SUBQ_PREFIX.length)\n : alias;\n}\n\nfunction transformRelated(\n related: CorrelatedSubquery,\n options: AstToZQLOptions,\n): string {\n const {alias} = related.subquery;\n if (!alias) return '';\n\n const relationship = alias;\n let code = `.related('${relationship}'`;\n\n // If the subquery has additional filters or configurations\n if (\n related.subquery.where ||\n (related.subquery.related && related.subquery.related.length > 0) ||\n related.subquery.orderBy ||\n related.subquery.limit\n ) {\n code += ', q => q' + astToZQL(related.subquery, options);\n }\n\n code += ')';\n return code;\n}\n\nfunction transformOrder(orderBy: Ordering): string {\n let code = '';\n for (const [field, direction] of orderBy) {\n code += `.orderBy('${field}', '${direction}')`;\n }\n return code;\n}\n\nfunction transformValuePosition(\n value: ValuePosition,\n options: AstToZQLOptions,\n): string {\n switch (value.type) {\n case 'literal':\n return options.redactLiterals ? '?' : transformLiteral(value);\n case 'column':\n return `'${value.name}'`;\n case 'static':\n return transformParameter(value);\n default:\n unreachable(value);\n }\n}\n\nfunction transformLiteral(literal: LiteralReference): string {\n if (literal.value === null) {\n return 'null';\n }\n if (Array.isArray(literal.value)) {\n return JSON.stringify(literal.value);\n }\n if (typeof literal.value === 'string') {\n return `'${literal.value.replace(/'/g, \"\\\\'\")}'`;\n }\n return String(literal.value);\n}\n\nfunction transformParameter(param: Parameter): string {\n const fieldStr = Array.isArray(param.field)\n ? `[${param.field.map(f => `'${f}'`).join(', ')}]`\n : `'${param.field}'`;\n\n return `authParam(${fieldStr})`;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAgB,SAAS,KAAU,UAA2B,CAAC,GAAW;CACxE,IAAI,OAAO;CAGX,IAAI,IAAI,OACN,QAAQ,mBAAmB,IAAI,OAAO,0BAAU,IAAI,IAAI,GAAG,OAAO;CAIpE,IAAI,IAAI,WAAW,IAAI,QAAQ,SAAS,GACtC,KAAK,MAAM,WAAW,IAAI,SACxB,IAAI,QAAQ,QAAQ;EAClB,MAAM,gBAAgB,QAAQ,SAAS,UAAU;EACjD,IAAI,eACF,QAAQ,iBAAiB,eAAe,OAAO;CAEnD,OACE,QAAQ,iBAAiB,SAAS,OAAO;CAM/C,IAAI,IAAI,WAAW,IAAI,QAAQ,SAAS,GACtC,QAAQ,eAAe,IAAI,OAAO;CAIpC,IAAI,IAAI,UAAU,KAAA,GAChB,QAAQ,UAAU,IAAI,MAAM;CAI9B,IAAI,IAAI,OAAO;EACb,MAAM,EAAC,KAAK,cAAa,IAAI;EAC7B,QAAQ,UAAU,QAAQ,iBAAiB,MAAM,KAAK,UAAU,GAAG,IACjE,YAAY,KAAK,wBAClB;CACH;CAEA,OAAO;AACT;AAcA,SAAS,mBACP,WACA,QACA,MACA,SACQ;CACR,QAAQ,UAAU,MAAlB;EACE,KAAK,UACH,OAAO,yBAAyB,WAAW,QAAQ,OAAO;EAC5D,KAAK;EACL,KAAK,MACH,OAAO,0BAA0B,WAAW,QAAQ,MAAM,OAAO;EACnE,KAAK,sBACH,OAAO,yBAAyB,WAAW,QAAQ,MAAM,OAAO;EAClE,SACE,YAAY,SAAS;CACzB;AACF;AAEA,SAAS,yBACP,WACA,QACA,SACQ;CACR,MAAM,EAAC,MAAM,IAAI,UAAS;CAE1B,MAAM,WAAW,uBAAuB,MAAM,OAAO;CACrD,MAAM,YAAY,uBAAuB,OAAO,OAAO;CAGvD,IAAI,OAAO,KACT,OAAO,GAAG,OAAO,GAAG,SAAS,IAAI,UAAU;CAG7C,OAAO,GAAG,OAAO,GAAG,SAAS,KAAK,GAAG,KAAK,UAAU;AACtD;AAEA,SAAS,0BACP,WACA,QACA,MACA,SACQ;CACR,MAAM,EAAC,MAAM,eAAc;CAG3B,IAAI,WAAW,WAAW,GACxB,OAAO,mBAAmB,WAAW,IAAI,QAAQ,MAAM,OAAO;CAIhE,IAAI,SAAS,OAAO;EAClB,MAAM,QAAQ,WAAW,KAAI,MAC3B,mBAAmB,GAAG,QAAQ,MAAM,OAAO,CAC7C;EAEA,IAAI,WAAW,UACb,OAAO,MAAM,KAAK,EAAE;EAEtB,KAAK,IAAI,KAAK;EACd,OAAO,SAAS,MAAM,KAAK,IAAI,IAAI;CACrC;CAEA,uBAAO,IAAI,IAAY;CAGvB,MAAM,iBAAiB,WACpB,KAAI,MAAK,mBAAmB,GAAG,OAAO,MAAM,OAAO,CAAC,EACpD,KAAK,IAAI;CAEZ,KAAK,IAAI,KAAK;CACd,KAAK,IAAI,IAAI;CAGb,OAAO,YAFU,SAAS,IAAI,EAAE,KAAK,IAElB,EAAS,QAAQ,KAAK,GAAG,eAAe;AAC7D;AAEA,SAAS,yBACP,WACA,QACA,MACA,SACQ;CACR,MAAM,EAAC,SAAS,OAAM;CACtB,MAAM,eAAe,wBAAwB,OAAO;CAEpD,MAAM,eAAe,sBAAsB,OAAO;CAGlD,MAAM,mBACJ,aAAa,SACZ,aAAa,WAAW,aAAa,QAAQ,SAAS,KACvD,aAAa,WACb,aAAa;CAGf,MAAM,cAAwB,CAAC;CAC/B,IAAI,UAAU,SAAS,KAAA,GACrB,YAAY,KAAK,SAAS,UAAU,MAAM;CAE5C,IAAI,UAAU,WAAW,KAAA,GACvB,YAAY,KAAK,WAAW,UAAU,QAAQ;CAEhD,MAAM,aACJ,YAAY,SAAS,IAAI,MAAM,YAAY,KAAK,IAAI,EAAE,KAAK;CAE7D,IAAI,OAAO,UAAU;EACnB,IAAI,CAAC,kBAAkB;GACrB,IAAI,WAAW,UACb,OAAO,iBAAiB,aAAa,GAAG,WAAW;GAErD,KAAK,IAAI,QAAQ;GACjB,OAAO,WAAW,aAAa,GAAG,WAAW;EAC/C;EAEA,IAAI,WAAW,UACb,OAAO,iBAAiB,aAAa,WAAW,SAAS,cAAc,OAAO,IAAI,WAAW;EAG/F,KAAK,IAAI,QAAQ;EACjB,OAAO,WAAW,aAAa,WAAW,SAAS,cAAc,OAAO,IAAI,WAAW;CACzF;CAIA,IAAI,kBAAkB;EACpB,IAAI,WAAW,UACb,OAAO,yCAAyC,aAAa,WAAW,SACtE,cACA,OACF,IAAI,WAAW;EAGjB,KAAK,IAAI,KAAK;EACd,KAAK,IAAI,QAAQ;EACjB,OAAO,eAAe,aAAa,WAAW,SAAS,cAAc,OAAO,IAAI,WAAW;CAC7F;CAEA,IAAI,WAAW,UACb,OAAO,yCAAyC,aAAa,GAAG,WAAW;CAE7E,KAAK,IAAI,KAAK;CACd,KAAK,IAAI,QAAQ;CAEjB,OAAO,eAAe,aAAa,GAAG,WAAW;AACnD;AAGA,SAAS,sBAAsB,SAAkC;CAC/D,IACE,QAAQ,SAAS,OAAO,SAAS,wBACjC,QAAQ,SAAS,MAAM,QAAQ,SAAS,OAAO,SAAA,gBAE/C,GAEA,OAAO,sBAAsB,QAAQ,SAAS,MAAM,OAAO;CAG7D,OAAO,QAAQ;AACjB;AAEA,SAAS,wBAAwB,SAAqC;CACpE,MAAM,QAAQ,KAAK,QAAQ,SAAS,KAAK;CACzC,OAAO,MAAM,WAAA,QAAsB,IAC/B,MAAM,UAAU,YAAY,MAAM,IAClC;AACN;AAEA,SAAS,iBACP,SACA,SACQ;CACR,MAAM,EAAC,UAAS,QAAQ;CACxB,IAAI,CAAC,OAAO,OAAO;CAGnB,IAAI,OAAO,aAAa,MAAa;CAGrC,IACE,QAAQ,SAAS,SAChB,QAAQ,SAAS,WAAW,QAAQ,SAAS,QAAQ,SAAS,KAC/D,QAAQ,SAAS,WACjB,QAAQ,SAAS,OAEjB,QAAQ,aAAa,SAAS,QAAQ,UAAU,OAAO;CAGzD,QAAQ;CACR,OAAO;AACT;AAEA,SAAS,eAAe,SAA2B;CACjD,IAAI,OAAO;CACX,KAAK,MAAM,CAAC,OAAO,cAAc,SAC/B,QAAQ,aAAa,MAAM,MAAM,UAAU;CAE7C,OAAO;AACT;AAEA,SAAS,uBACP,OACA,SACQ;CACR,QAAQ,MAAM,MAAd;EACE,KAAK,WACH,OAAO,QAAQ,iBAAiB,MAAM,iBAAiB,KAAK;EAC9D,KAAK,UACH,OAAO,IAAI,MAAM,KAAK;EACxB,KAAK,UACH,OAAO,mBAAmB,KAAK;EACjC,SACE,YAAY,KAAK;CACrB;AACF;AAEA,SAAS,iBAAiB,SAAmC;CAC3D,IAAI,QAAQ,UAAU,MACpB,OAAO;CAET,IAAI,MAAM,QAAQ,QAAQ,KAAK,GAC7B,OAAO,KAAK,UAAU,QAAQ,KAAK;CAErC,IAAI,OAAO,QAAQ,UAAU,UAC3B,OAAO,IAAI,QAAQ,MAAM,QAAQ,MAAM,KAAK,EAAE;CAEhD,OAAO,OAAO,QAAQ,KAAK;AAC7B;AAEA,SAAS,mBAAmB,OAA0B;CAKpD,OAAO,aAJU,MAAM,QAAQ,MAAM,KAAK,IACtC,IAAI,MAAM,MAAM,KAAI,MAAK,IAAI,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,KAC9C,IAAI,MAAM,MAAM,GAES;AAC/B"}
|
|
@@ -15,6 +15,22 @@ export declare const logOptions: {
|
|
|
15
15
|
type: v.Type<number>;
|
|
16
16
|
desc: string[];
|
|
17
17
|
};
|
|
18
|
+
slowAdvanceThreshold: {
|
|
19
|
+
type: v.Type<number>;
|
|
20
|
+
desc: string[];
|
|
21
|
+
};
|
|
22
|
+
planWarningRowThreshold: {
|
|
23
|
+
type: v.Type<number>;
|
|
24
|
+
desc: string[];
|
|
25
|
+
};
|
|
26
|
+
planWarningCostThreshold: {
|
|
27
|
+
type: v.Type<number>;
|
|
28
|
+
desc: string[];
|
|
29
|
+
};
|
|
30
|
+
queryStatsIntervalSeconds: {
|
|
31
|
+
type: v.Type<number>;
|
|
32
|
+
desc: string[];
|
|
33
|
+
};
|
|
18
34
|
ivmSampling: {
|
|
19
35
|
type: v.Type<number>;
|
|
20
36
|
desc: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-options.d.ts","sourceRoot":"","sources":["../../../../otel/src/log-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,4BAA4B,CAAC;AAEhD,eAAO,MAAM,QAAQ,6CAAmD,CAAC;AAEzE,eAAO,MAAM,UAAU;IACrB,KAAK;IAEL,MAAM;QACJ,IAAI;QACJ,IAAI;;IAMN,gBAAgB;QACd,IAAI;QACJ,IAAI;;IAKN,oBAAoB;QAClB,IAAI;QACJ,IAAI;;
|
|
1
|
+
{"version":3,"file":"log-options.d.ts","sourceRoot":"","sources":["../../../../otel/src/log-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,4BAA4B,CAAC;AAEhD,eAAO,MAAM,QAAQ,6CAAmD,CAAC;AAEzE,eAAO,MAAM,UAAU;IACrB,KAAK;IAEL,MAAM;QACJ,IAAI;QACJ,IAAI;;IAMN,gBAAgB;QACd,IAAI;QACJ,IAAI;;IAKN,oBAAoB;QAClB,IAAI;QACJ,IAAI;;IASN,oBAAoB;QAClB,IAAI;QACJ,IAAI;;IAYN,uBAAuB;QACrB,IAAI;QACJ,IAAI;;IAWN,wBAAwB;QACtB,IAAI;QACJ,IAAI;;IAON,yBAAyB;QACvB,IAAI;QACJ,IAAI;;IAaN,WAAW;QACT,IAAI;QACJ,IAAI;;CAIP,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -13,7 +13,60 @@ var logOptions = {
|
|
|
13
13
|
},
|
|
14
14
|
slowHydrateThreshold: {
|
|
15
15
|
type: valita_exports.number().default(100),
|
|
16
|
-
desc: [
|
|
16
|
+
desc: [
|
|
17
|
+
`The number of milliseconds a query hydration must take to print a slow warning.`,
|
|
18
|
+
``,
|
|
19
|
+
`The warning logs the query with its literal values redacted, and is logged`,
|
|
20
|
+
`at most once every 5 minutes per query shape (the query with its values`,
|
|
21
|
+
`redacted), with a count of the slow hydrations suppressed in between.`
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
slowAdvanceThreshold: {
|
|
25
|
+
type: valita_exports.number().default(100),
|
|
26
|
+
desc: [
|
|
27
|
+
`The number of milliseconds a query must take to process one advancement`,
|
|
28
|
+
`(the changes of a replicated transaction, or a batch of them) to print a`,
|
|
29
|
+
`slow warning.`,
|
|
30
|
+
``,
|
|
31
|
+
`Like {bold slowHydrateThreshold}, the warning logs the query with its values`,
|
|
32
|
+
`redacted, at most once every 5 minutes per query shape. When an advancement`,
|
|
33
|
+
`times out and resets the pipelines, the queries that took the most time are`,
|
|
34
|
+
`logged regardless of this threshold.`
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
planWarningRowThreshold: {
|
|
38
|
+
type: valita_exports.number().default(1e4),
|
|
39
|
+
desc: [
|
|
40
|
+
`Log a warning when the query planner estimates that one read of a table`,
|
|
41
|
+
`scans or sorts at least this many rows: a read that scans the whole`,
|
|
42
|
+
`table because no index covers the columns it looks rows up by, or that`,
|
|
43
|
+
`sorts every matching row because no index covers the ordering.`,
|
|
44
|
+
``,
|
|
45
|
+
`The warning is logged at most once an hour per query shape (the query`,
|
|
46
|
+
`with its values redacted). Set to 0 to disable. Requires the query planner.`
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
planWarningCostThreshold: {
|
|
50
|
+
type: valita_exports.number().default(1e6),
|
|
51
|
+
desc: [
|
|
52
|
+
`Log a warning when the best plan the query planner finds for a query is`,
|
|
53
|
+
`still estimated to process at least this many rows. Throttled like`,
|
|
54
|
+
`{bold planWarningRowThreshold}. Set to 0 to disable.`
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
queryStatsIntervalSeconds: {
|
|
58
|
+
type: valita_exports.number().default(60),
|
|
59
|
+
desc: [
|
|
60
|
+
`How often each view-syncer worker logs the work done per query shape (the`,
|
|
61
|
+
`query with its values redacted): the number of hydrations and`,
|
|
62
|
+
`advancements, the time they took, and the rows they read and output.`,
|
|
63
|
+
``,
|
|
64
|
+
`Unlike the slow query warnings, every query is counted, so the logs can be`,
|
|
65
|
+
`summed across workers and over time to rank queries by the time they take.`,
|
|
66
|
+
`Logged at the info level as {bold query-stats} events, for the 100 shapes`,
|
|
67
|
+
`that took the most time in the interval, plus a {bold query-stats-summary}`,
|
|
68
|
+
`event with the totals. Set to 0 to disable.`
|
|
69
|
+
]
|
|
17
70
|
},
|
|
18
71
|
ivmSampling: {
|
|
19
72
|
type: valita_exports.number().default(5e3),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-options.js","names":[],"sources":["../../../../otel/src/log-options.ts"],"sourcesContent":["import {type Config} from '../../shared/src/options-types.ts';\nimport * as v from '../../shared/src/valita.ts';\n\nexport const logLevel = v.literalUnion('debug', 'info', 'warn', 'error');\n\nexport const logOptions = {\n level: logLevel.default('info'),\n\n format: {\n type: v.literalUnion('text', 'json').default('text'),\n desc: [\n `Use {bold text} for developer-friendly console logging`,\n `and {bold json} for consumption by structured-logging services`,\n ],\n },\n\n slowRowThreshold: {\n type: v.number().default(2),\n desc: [\n `The number of ms a row must take to fetch from table-source before it is considered slow.`,\n ],\n },\n\n slowHydrateThreshold: {\n type: v.number().default(100),\n desc: [\n `The number of milliseconds a query hydration must take to print a slow warning.`,\n ],\n },\n\n ivmSampling: {\n type: v.number().default(5000),\n desc: [\n `How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value.`,\n ],\n },\n};\n\nexport type LogConfig = Config<typeof logOptions>;\n"],"mappings":";;AAGA,IAAa,WAAW,aAAe,SAAS,QAAQ,QAAQ,OAAO;AAEvE,IAAa,aAAa;CACxB,OAAO,SAAS,QAAQ,MAAM;CAE9B,QAAQ;EACN,MAAM,aAAe,QAAQ,MAAM,EAAE,QAAQ,MAAM;EACnD,MAAM,CACJ,0DACA,gEACF;CACF;CAEA,kBAAkB;EAChB,MAAM,eAAE,OAAO,EAAE,QAAQ,CAAC;EAC1B,MAAM,CACJ,2FACF;CACF;CAEA,sBAAsB;EACpB,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAG;EAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"log-options.js","names":[],"sources":["../../../../otel/src/log-options.ts"],"sourcesContent":["import {type Config} from '../../shared/src/options-types.ts';\nimport * as v from '../../shared/src/valita.ts';\n\nexport const logLevel = v.literalUnion('debug', 'info', 'warn', 'error');\n\nexport const logOptions = {\n level: logLevel.default('info'),\n\n format: {\n type: v.literalUnion('text', 'json').default('text'),\n desc: [\n `Use {bold text} for developer-friendly console logging`,\n `and {bold json} for consumption by structured-logging services`,\n ],\n },\n\n slowRowThreshold: {\n type: v.number().default(2),\n desc: [\n `The number of ms a row must take to fetch from table-source before it is considered slow.`,\n ],\n },\n\n slowHydrateThreshold: {\n type: v.number().default(100),\n desc: [\n `The number of milliseconds a query hydration must take to print a slow warning.`,\n ``,\n `The warning logs the query with its literal values redacted, and is logged`,\n `at most once every 5 minutes per query shape (the query with its values`,\n `redacted), with a count of the slow hydrations suppressed in between.`,\n ],\n },\n\n slowAdvanceThreshold: {\n type: v.number().default(100),\n desc: [\n `The number of milliseconds a query must take to process one advancement`,\n `(the changes of a replicated transaction, or a batch of them) to print a`,\n `slow warning.`,\n ``,\n `Like {bold slowHydrateThreshold}, the warning logs the query with its values`,\n `redacted, at most once every 5 minutes per query shape. When an advancement`,\n `times out and resets the pipelines, the queries that took the most time are`,\n `logged regardless of this threshold.`,\n ],\n },\n\n planWarningRowThreshold: {\n type: v.number().default(10_000),\n desc: [\n `Log a warning when the query planner estimates that one read of a table`,\n `scans or sorts at least this many rows: a read that scans the whole`,\n `table because no index covers the columns it looks rows up by, or that`,\n `sorts every matching row because no index covers the ordering.`,\n ``,\n `The warning is logged at most once an hour per query shape (the query`,\n `with its values redacted). Set to 0 to disable. Requires the query planner.`,\n ],\n },\n\n planWarningCostThreshold: {\n type: v.number().default(1_000_000),\n desc: [\n `Log a warning when the best plan the query planner finds for a query is`,\n `still estimated to process at least this many rows. Throttled like`,\n `{bold planWarningRowThreshold}. Set to 0 to disable.`,\n ],\n },\n\n queryStatsIntervalSeconds: {\n type: v.number().default(60),\n desc: [\n `How often each view-syncer worker logs the work done per query shape (the`,\n `query with its values redacted): the number of hydrations and`,\n `advancements, the time they took, and the rows they read and output.`,\n ``,\n `Unlike the slow query warnings, every query is counted, so the logs can be`,\n `summed across workers and over time to rank queries by the time they take.`,\n `Logged at the info level as {bold query-stats} events, for the 100 shapes`,\n `that took the most time in the interval, plus a {bold query-stats-summary}`,\n `event with the totals. Set to 0 to disable.`,\n ],\n },\n\n ivmSampling: {\n type: v.number().default(5000),\n desc: [\n `How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value.`,\n ],\n },\n};\n\nexport type LogConfig = Config<typeof logOptions>;\n"],"mappings":";;AAGA,IAAa,WAAW,aAAe,SAAS,QAAQ,QAAQ,OAAO;AAEvE,IAAa,aAAa;CACxB,OAAO,SAAS,QAAQ,MAAM;CAE9B,QAAQ;EACN,MAAM,aAAe,QAAQ,MAAM,EAAE,QAAQ,MAAM;EACnD,MAAM,CACJ,0DACA,gEACF;CACF;CAEA,kBAAkB;EAChB,MAAM,eAAE,OAAO,EAAE,QAAQ,CAAC;EAC1B,MAAM,CACJ,2FACF;CACF;CAEA,sBAAsB;EACpB,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAG;EAC5B,MAAM;GACJ;GACA;GACA;GACA;GACA;EACF;CACF;CAEA,sBAAsB;EACpB,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAG;EAC5B,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CAEA,yBAAyB;EACvB,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAM;EAC/B,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CAEA,0BAA0B;EACxB,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAS;EAClC,MAAM;GACJ;GACA;GACA;EACF;CACF;CAEA,2BAA2B;EACzB,MAAM,eAAE,OAAO,EAAE,QAAQ,EAAE;EAC3B,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;CAEA,aAAa;EACX,MAAM,eAAE,OAAO,EAAE,QAAQ,GAAI;EAC7B,MAAM,CACJ,8FACF;CACF;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
2
|
import type { StoreProvider } from './kv/store.ts';
|
|
3
|
-
export declare function getKVStoreProvider(
|
|
3
|
+
export declare function getKVStoreProvider(_lc: LogContext, kvStore: 'mem' | 'idb' | StoreProvider | undefined): StoreProvider;
|
|
4
4
|
//# sourceMappingURL=get-kv-store-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-kv-store-provider.d.ts","sourceRoot":"","sources":["../../../../replicache/src/get-kv-store-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"get-kv-store-provider.d.ts","sourceRoot":"","sources":["../../../../replicache/src/get-kv-store-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AAEjD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,KAAK,GAAG,KAAK,GAAG,aAAa,GAAG,SAAS,GACjD,aAAa,CAgBf"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { IDBStore, dropIDBStore } from "./kv/idb-store.js";
|
|
1
2
|
import { MemStore, dropMemStore } from "./kv/mem-store.js";
|
|
2
|
-
import { dropIDBStoreWithMemFallback, newIDBStoreWithMemFallback } from "./kv/idb-store-with-mem-fallback.js";
|
|
3
3
|
//#region ../replicache/src/get-kv-store-provider.ts
|
|
4
|
-
function getKVStoreProvider(
|
|
4
|
+
function getKVStoreProvider(_lc, kvStore) {
|
|
5
5
|
switch (kvStore) {
|
|
6
6
|
case "idb":
|
|
7
7
|
case void 0: return {
|
|
8
|
-
create: (name) =>
|
|
9
|
-
drop:
|
|
8
|
+
create: (name) => new IDBStore(name),
|
|
9
|
+
drop: dropIDBStore
|
|
10
10
|
};
|
|
11
11
|
case "mem": return {
|
|
12
12
|
create: (name) => new MemStore(name),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-kv-store-provider.js","names":[],"sources":["../../../../replicache/src/get-kv-store-provider.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {
|
|
1
|
+
{"version":3,"file":"get-kv-store-provider.js","names":[],"sources":["../../../../replicache/src/get-kv-store-provider.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {dropIDBStore, IDBStore} from './kv/idb-store.ts';\nimport {dropMemStore, MemStore} from './kv/mem-store.ts';\nimport type {StoreProvider} from './kv/store.ts';\n\nexport function getKVStoreProvider(\n _lc: LogContext,\n kvStore: 'mem' | 'idb' | StoreProvider | undefined,\n): StoreProvider {\n switch (kvStore) {\n case 'idb':\n case undefined:\n return {\n create: name => new IDBStore(name),\n drop: dropIDBStore,\n };\n case 'mem':\n return {\n create: name => new MemStore(name),\n drop: name => dropMemStore(name),\n };\n default:\n return kvStore;\n }\n}\n"],"mappings":";;;AAKA,SAAgB,mBACd,KACA,SACe;CACf,QAAQ,SAAR;EACE,KAAK;EACL,KAAK,KAAA,GACH,OAAO;GACL,SAAQ,SAAQ,IAAI,SAAS,IAAI;GACjC,MAAM;EACR;EACF,KAAK,OACH,OAAO;GACL,SAAQ,SAAQ,IAAI,SAAS,IAAI;GACjC,OAAM,SAAQ,aAAa,IAAI;EACjC;EACF,SACE,OAAO;CACX;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StorageFailureError } from '../storage-failure.ts';
|
|
1
2
|
import type { Read, Store, Write } from './store.ts';
|
|
2
3
|
export declare class IDBStore implements Store {
|
|
3
4
|
#private;
|
|
@@ -20,8 +21,16 @@ export declare class IDBNotFoundError extends Error {
|
|
|
20
21
|
* `read()` and `write()` reject with this error when the initial
|
|
21
22
|
* `indexedDB.open` failed. The browser's error is the `cause`. A failure after
|
|
22
23
|
* the database opened, such as a transaction error, is not wrapped.
|
|
24
|
+
*
|
|
25
|
+
* It is a `cannot-open` storage failure, or `full` when the browser says so
|
|
26
|
+
* (WebKit's IndexedDB is SQLite underneath and reports `database or disk is
|
|
27
|
+
* full`).
|
|
23
28
|
*/
|
|
24
|
-
export declare class IDBOpenError extends
|
|
29
|
+
export declare class IDBOpenError extends StorageFailureError {
|
|
25
30
|
name: string;
|
|
31
|
+
constructor(message: string, options: {
|
|
32
|
+
cause: unknown;
|
|
33
|
+
});
|
|
26
34
|
}
|
|
35
|
+
export declare function dropIDBStore(name: string): Promise<void>;
|
|
27
36
|
//# sourceMappingURL=idb-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idb-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/idb-store.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,YAAY,CAAC;AAUnD,qBAAa,QAAS,YAAW,KAAK;;IAKpC,YAAY,IAAI,EAAE,MAAM,EAKvB;IAED,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAKpB;IAED,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAKtB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAM3B;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;CA4DF;AAyHD;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,IAAI,SAAsB;CAC3B;
|
|
1
|
+
{"version":3,"file":"idb-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/idb-store.ts"],"names":[],"mappings":"AAQA,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,YAAY,CAAC;AAUnD,qBAAa,QAAS,YAAW,KAAK;;IAKpC,YAAY,IAAI,EAAE,MAAM,EAKvB;IAED,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAKpB;IAED,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAKtB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAM3B;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;CA4DF;AAyHD;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,IAAI,SAAsB;CAC3B;AAID;;;;;;;;GAQG;AACH,qBAAa,YAAa,SAAQ,mBAAmB;IACnD,IAAI,SAAkB;IAEtB,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,EAMrD;CACF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxD"}
|
|
@@ -2,6 +2,7 @@ import { assertNotNull } from "../../../shared/src/asserts.js";
|
|
|
2
2
|
import { mustGetBrowserGlobal } from "../../../shared/src/browser-env.js";
|
|
3
3
|
import { promiseVoid } from "../../../shared/src/resolved-promises.js";
|
|
4
4
|
import { deepFreezeAllowUndefined } from "../frozen-json.js";
|
|
5
|
+
import { StorageFailureError } from "../storage-failure.js";
|
|
5
6
|
import { storeIsClosedRejection, transactionIsClosedRejection } from "./throw-if-closed.js";
|
|
6
7
|
import { WriteImplBase, deleteSentinel } from "./write-impl-base.js";
|
|
7
8
|
import { resolver } from "@rocicorp/resolver";
|
|
@@ -157,15 +158,30 @@ function openDatabase(name) {
|
|
|
157
158
|
var IDBNotFoundError = class extends Error {
|
|
158
159
|
name = "IDBNotFoundError";
|
|
159
160
|
};
|
|
161
|
+
var DISK_FULL = /database or disk is full/;
|
|
160
162
|
/**
|
|
161
163
|
* `read()` and `write()` reject with this error when the initial
|
|
162
164
|
* `indexedDB.open` failed. The browser's error is the `cause`. A failure after
|
|
163
165
|
* the database opened, such as a transaction error, is not wrapped.
|
|
166
|
+
*
|
|
167
|
+
* It is a `cannot-open` storage failure, or `full` when the browser says so
|
|
168
|
+
* (WebKit's IndexedDB is SQLite underneath and reports `database or disk is
|
|
169
|
+
* full`).
|
|
164
170
|
*/
|
|
165
|
-
var IDBOpenError = class extends
|
|
171
|
+
var IDBOpenError = class extends StorageFailureError {
|
|
166
172
|
name = "IDBOpenError";
|
|
173
|
+
constructor(message, options) {
|
|
174
|
+
super(DISK_FULL.test(String(options.cause)) ? "full" : "cannot-open", message, options);
|
|
175
|
+
}
|
|
167
176
|
};
|
|
177
|
+
function dropIDBStore(name) {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const req = indexedDB.deleteDatabase(name);
|
|
180
|
+
req.onsuccess = () => resolve();
|
|
181
|
+
req.onerror = () => reject(req.error);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
168
184
|
//#endregion
|
|
169
|
-
export { IDBNotFoundError,
|
|
185
|
+
export { IDBNotFoundError, IDBStore, dropIDBStore };
|
|
170
186
|
|
|
171
187
|
//# sourceMappingURL=idb-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idb-store.js","names":["#db","#closed","#withReopen","#idbDeleted","#tx"],"sources":["../../../../../replicache/src/kv/idb-store.ts"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport {assertNotNull} from '../../../shared/src/asserts.ts';\nimport {mustGetBrowserGlobal} from '../../../shared/src/browser-env.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport {\n type FrozenJSONValue,\n deepFreezeAllowUndefined,\n} from '../frozen-json.ts';\nimport type {Read, Store, Write} from './store.ts';\nimport {\n storeIsClosedRejection,\n transactionIsClosedRejection,\n} from './throw-if-closed.ts';\nimport {WriteImplBase, deleteSentinel} from './write-impl-base.ts';\n\nconst RELAXED = {durability: 'relaxed'} as const;\nconst OBJECT_STORE = 'chunks';\n\nexport class IDBStore implements Store {\n #db: Promise<IDBDatabase>;\n #closed = false;\n #idbDeleted = false;\n\n constructor(name: string) {\n this.#db = openDatabase(name);\n // read() and write() surface an open failure as an IDBOpenError. Don't\n // leave an unhandled rejection when neither is called.\n this.#db.catch(() => undefined);\n }\n\n read(): Promise<Read> {\n if (this.#closed) {\n return storeIsClosedRejection();\n }\n return this.#withReopen(readImpl);\n }\n\n write(): Promise<Write> {\n if (this.#closed) {\n return storeIsClosedRejection();\n }\n return this.#withReopen(writeImpl);\n }\n\n async close(): Promise<void> {\n if (!this.#idbDeleted) {\n const db = await this.#db;\n db.close();\n }\n this.#closed = true;\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n get kind(): string {\n return 'idb';\n }\n\n async #withReopen<R>(fn: (db: IDBDatabase) => R): Promise<R> {\n // Tries to reopen an IndexedDB, and rejects if the database needs\n // upgrading (is missing for whatever reason).\n const reopenExistingDB = async (name: string): Promise<IDBDatabase> => {\n const {promise, resolve, reject} = resolver<IDBDatabase>();\n const req = indexedDB.open(name);\n\n req.onupgradeneeded = () => {\n const tx = req.transaction;\n assertNotNull(tx);\n tx.abort();\n this.#idbDeleted = true;\n reject(\n new IDBNotFoundError(\n `Expected IndexedDB not found: ${name}. This likely means that the user deleted IndexedDB instances while the app was running. This is non-fatal. The app will continue running in memory until reload.`,\n ),\n );\n };\n\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n\n const db = await promise;\n db.onversionchange = () => db.close();\n return db;\n };\n\n // We abstract on `readImpl` to work around an issue in Safari. Safari does\n // not allow any microtask between a transaction is created until it is\n // first used. We used to use `await read()` here instead of `await\n // this._db` but then there is a microtask between the creation of the\n // transaction and the return of this function. By doing `await this._db`\n // here we only await the db and no await is involved with the transaction.\n // See https://github.com/jakearchibald/idb-keyval/commit/1af0a00b1a70a678d2f9cf5e74c55a22e57324c5#r55989916\n const db = await this.#db;\n\n try {\n return fn(db);\n } catch (e: unknown) {\n if (!this.#closed && e instanceof DOMException) {\n if (e.name === 'InvalidStateError') {\n this.#db = reopenExistingDB(db.name);\n const reopened = await this.#db;\n return fn(reopened);\n } else if (e.name === 'NotFoundError') {\n // This edge-case can happen if the db has been deleted and the\n // user/developer has DevTools open in certain browsers.\n // See discussion at https://github.com/rocicorp/replicache-internal/pull/216\n this.#idbDeleted = true;\n mustGetBrowserGlobal('indexedDB').deleteDatabase(db.name);\n throw new IDBNotFoundError(\n `Expected IndexedDB ${db.name} missing object store. Deleting db. This is non-fatal, the app will continue working in memory until it is reloaded.`,\n );\n }\n }\n throw e;\n }\n }\n}\n\nclass ReadImpl implements Read {\n readonly #tx: IDBTransaction;\n #closed = false;\n\n constructor(tx: IDBTransaction) {\n this.#tx = tx;\n }\n\n has(key: string): Promise<boolean> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n return new Promise((resolve, reject) => {\n const req = objectStore(this.#tx).count(key);\n req.onsuccess = () => resolve(req.result > 0);\n req.onerror = () => reject(req.error);\n });\n }\n\n get(key: string): Promise<FrozenJSONValue | undefined> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n return new Promise((resolve, reject) => {\n const req = objectStore(this.#tx).get(key);\n req.onsuccess = () => resolve(deepFreezeAllowUndefined(req.result));\n req.onerror = () => reject(req.error);\n });\n }\n\n release(): void {\n this.#closed = true;\n // Do nothing. We rely on IDB locking.\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nclass WriteImpl extends WriteImplBase {\n readonly #tx: IDBTransaction;\n #closed = false;\n\n constructor(tx: IDBTransaction) {\n super(new ReadImpl(tx));\n this.#tx = tx;\n }\n\n commit(): Promise<void> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n if (this._pending.size === 0) {\n return promiseVoid;\n }\n\n return new Promise((resolve, reject) => {\n const tx = this.#tx;\n const store = objectStore(tx);\n for (const [key, val] of this._pending) {\n if (val === deleteSentinel) {\n store.delete(key);\n } else {\n store.put(val, key);\n }\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n release(): void {\n // We rely on IDB locking so no need to do anything here.\n this.#closed = true;\n super.release();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nfunction writeImpl(db: IDBDatabase): Write {\n const tx = db.transaction(OBJECT_STORE, 'readwrite', RELAXED);\n return new WriteImpl(tx);\n}\n\nfunction readImpl(db: IDBDatabase): Read {\n const tx = db.transaction(OBJECT_STORE, 'readonly');\n return new ReadImpl(tx);\n}\n\nfunction objectStore(tx: IDBTransaction): IDBObjectStore {\n return tx.objectStore(OBJECT_STORE);\n}\n\nfunction openDatabase(name: string): Promise<IDBDatabase> {\n const idb = mustGetBrowserGlobal('indexedDB');\n return new Promise((resolve, reject) => {\n const req = idb.open(name);\n req.onupgradeneeded = () => {\n req.result.createObjectStore(OBJECT_STORE);\n };\n req.onsuccess = () => {\n const db = req.result;\n // Another tab/process wants to modify the db, so release it.\n db.onversionchange = () => db.close();\n resolve(db);\n };\n req.onerror = () =>\n reject(\n new IDBOpenError(`Failed to open IndexedDB ${name}`, {\n cause: req.error,\n }),\n );\n });\n}\n\n/**\n * This error is thrown when we detect that the IndexedDB has been removed. This\n * does not normally happen but can happen during development if the user has\n * DevTools open and deletes the IndexedDB from there.\n */\nexport class IDBNotFoundError extends Error {\n name = 'IDBNotFoundError';\n}\n\n/**\n * `read()` and `write()` reject with this error when the initial\n * `indexedDB.open` failed. The browser's error is the `cause`. A failure after\n * the database opened, such as a transaction error, is not wrapped.\n */\nexport class IDBOpenError extends Error {\n name = 'IDBOpenError';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"idb-store.js","names":["#db","#closed","#withReopen","#idbDeleted","#tx"],"sources":["../../../../../replicache/src/kv/idb-store.ts"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport {assertNotNull} from '../../../shared/src/asserts.ts';\nimport {mustGetBrowserGlobal} from '../../../shared/src/browser-env.ts';\nimport {promiseVoid} from '../../../shared/src/resolved-promises.ts';\nimport {\n type FrozenJSONValue,\n deepFreezeAllowUndefined,\n} from '../frozen-json.ts';\nimport {StorageFailureError} from '../storage-failure.ts';\nimport type {Read, Store, Write} from './store.ts';\nimport {\n storeIsClosedRejection,\n transactionIsClosedRejection,\n} from './throw-if-closed.ts';\nimport {WriteImplBase, deleteSentinel} from './write-impl-base.ts';\n\nconst RELAXED = {durability: 'relaxed'} as const;\nconst OBJECT_STORE = 'chunks';\n\nexport class IDBStore implements Store {\n #db: Promise<IDBDatabase>;\n #closed = false;\n #idbDeleted = false;\n\n constructor(name: string) {\n this.#db = openDatabase(name);\n // read() and write() surface an open failure as an IDBOpenError. Don't\n // leave an unhandled rejection when neither is called.\n this.#db.catch(() => undefined);\n }\n\n read(): Promise<Read> {\n if (this.#closed) {\n return storeIsClosedRejection();\n }\n return this.#withReopen(readImpl);\n }\n\n write(): Promise<Write> {\n if (this.#closed) {\n return storeIsClosedRejection();\n }\n return this.#withReopen(writeImpl);\n }\n\n async close(): Promise<void> {\n if (!this.#idbDeleted) {\n const db = await this.#db;\n db.close();\n }\n this.#closed = true;\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n get kind(): string {\n return 'idb';\n }\n\n async #withReopen<R>(fn: (db: IDBDatabase) => R): Promise<R> {\n // Tries to reopen an IndexedDB, and rejects if the database needs\n // upgrading (is missing for whatever reason).\n const reopenExistingDB = async (name: string): Promise<IDBDatabase> => {\n const {promise, resolve, reject} = resolver<IDBDatabase>();\n const req = indexedDB.open(name);\n\n req.onupgradeneeded = () => {\n const tx = req.transaction;\n assertNotNull(tx);\n tx.abort();\n this.#idbDeleted = true;\n reject(\n new IDBNotFoundError(\n `Expected IndexedDB not found: ${name}. This likely means that the user deleted IndexedDB instances while the app was running. This is non-fatal. The app will continue running in memory until reload.`,\n ),\n );\n };\n\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n\n const db = await promise;\n db.onversionchange = () => db.close();\n return db;\n };\n\n // We abstract on `readImpl` to work around an issue in Safari. Safari does\n // not allow any microtask between a transaction is created until it is\n // first used. We used to use `await read()` here instead of `await\n // this._db` but then there is a microtask between the creation of the\n // transaction and the return of this function. By doing `await this._db`\n // here we only await the db and no await is involved with the transaction.\n // See https://github.com/jakearchibald/idb-keyval/commit/1af0a00b1a70a678d2f9cf5e74c55a22e57324c5#r55989916\n const db = await this.#db;\n\n try {\n return fn(db);\n } catch (e: unknown) {\n if (!this.#closed && e instanceof DOMException) {\n if (e.name === 'InvalidStateError') {\n this.#db = reopenExistingDB(db.name);\n const reopened = await this.#db;\n return fn(reopened);\n } else if (e.name === 'NotFoundError') {\n // This edge-case can happen if the db has been deleted and the\n // user/developer has DevTools open in certain browsers.\n // See discussion at https://github.com/rocicorp/replicache-internal/pull/216\n this.#idbDeleted = true;\n mustGetBrowserGlobal('indexedDB').deleteDatabase(db.name);\n throw new IDBNotFoundError(\n `Expected IndexedDB ${db.name} missing object store. Deleting db. This is non-fatal, the app will continue working in memory until it is reloaded.`,\n );\n }\n }\n throw e;\n }\n }\n}\n\nclass ReadImpl implements Read {\n readonly #tx: IDBTransaction;\n #closed = false;\n\n constructor(tx: IDBTransaction) {\n this.#tx = tx;\n }\n\n has(key: string): Promise<boolean> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n return new Promise((resolve, reject) => {\n const req = objectStore(this.#tx).count(key);\n req.onsuccess = () => resolve(req.result > 0);\n req.onerror = () => reject(req.error);\n });\n }\n\n get(key: string): Promise<FrozenJSONValue | undefined> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n return new Promise((resolve, reject) => {\n const req = objectStore(this.#tx).get(key);\n req.onsuccess = () => resolve(deepFreezeAllowUndefined(req.result));\n req.onerror = () => reject(req.error);\n });\n }\n\n release(): void {\n this.#closed = true;\n // Do nothing. We rely on IDB locking.\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nclass WriteImpl extends WriteImplBase {\n readonly #tx: IDBTransaction;\n #closed = false;\n\n constructor(tx: IDBTransaction) {\n super(new ReadImpl(tx));\n this.#tx = tx;\n }\n\n commit(): Promise<void> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n if (this._pending.size === 0) {\n return promiseVoid;\n }\n\n return new Promise((resolve, reject) => {\n const tx = this.#tx;\n const store = objectStore(tx);\n for (const [key, val] of this._pending) {\n if (val === deleteSentinel) {\n store.delete(key);\n } else {\n store.put(val, key);\n }\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n release(): void {\n // We rely on IDB locking so no need to do anything here.\n this.#closed = true;\n super.release();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nfunction writeImpl(db: IDBDatabase): Write {\n const tx = db.transaction(OBJECT_STORE, 'readwrite', RELAXED);\n return new WriteImpl(tx);\n}\n\nfunction readImpl(db: IDBDatabase): Read {\n const tx = db.transaction(OBJECT_STORE, 'readonly');\n return new ReadImpl(tx);\n}\n\nfunction objectStore(tx: IDBTransaction): IDBObjectStore {\n return tx.objectStore(OBJECT_STORE);\n}\n\nfunction openDatabase(name: string): Promise<IDBDatabase> {\n const idb = mustGetBrowserGlobal('indexedDB');\n return new Promise((resolve, reject) => {\n const req = idb.open(name);\n req.onupgradeneeded = () => {\n req.result.createObjectStore(OBJECT_STORE);\n };\n req.onsuccess = () => {\n const db = req.result;\n // Another tab/process wants to modify the db, so release it.\n db.onversionchange = () => db.close();\n resolve(db);\n };\n req.onerror = () =>\n reject(\n new IDBOpenError(`Failed to open IndexedDB ${name}`, {\n cause: req.error,\n }),\n );\n });\n}\n\n/**\n * This error is thrown when we detect that the IndexedDB has been removed. This\n * does not normally happen but can happen during development if the user has\n * DevTools open and deletes the IndexedDB from there.\n */\nexport class IDBNotFoundError extends Error {\n name = 'IDBNotFoundError';\n}\n\nconst DISK_FULL = /database or disk is full/;\n\n/**\n * `read()` and `write()` reject with this error when the initial\n * `indexedDB.open` failed. The browser's error is the `cause`. A failure after\n * the database opened, such as a transaction error, is not wrapped.\n *\n * It is a `cannot-open` storage failure, or `full` when the browser says so\n * (WebKit's IndexedDB is SQLite underneath and reports `database or disk is\n * full`).\n */\nexport class IDBOpenError extends StorageFailureError {\n name = 'IDBOpenError';\n\n constructor(message: string, options: {cause: unknown}) {\n super(\n DISK_FULL.test(String(options.cause)) ? 'full' : 'cannot-open',\n message,\n options,\n );\n }\n}\n\nexport function dropIDBStore(name: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.deleteDatabase(name);\n req.onsuccess = () => resolve();\n req.onerror = () => reject(req.error);\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type StorageFailureError } from '../storage-failure.ts';
|
|
2
|
+
import type { Read, Store, StoreProvider, Write } from './store.ts';
|
|
3
|
+
/** Whether an instance moved onto a memory store of this name. */
|
|
4
|
+
export declare function isFallbackStore(name: string): boolean;
|
|
5
|
+
/** Creates and drops the memory stores instances fell back to. */
|
|
6
|
+
export declare const fallbackStoreProvider: StoreProvider;
|
|
7
|
+
/**
|
|
8
|
+
* Wraps a {@link StoreProvider} so that the stores it creates move onto memory
|
|
9
|
+
* together when their storage fails while the instance is opening (see
|
|
10
|
+
* `onStorageFailure`): a store whose `create` throws a
|
|
11
|
+
* {@link StorageFailureError} starts on a {@link MemStore}, and after
|
|
12
|
+
* {@link fallBack} the other stores switch on their next `read()` or
|
|
13
|
+
* `write()`. The memory stores keep the same names, so drops reach them too.
|
|
14
|
+
*
|
|
15
|
+
* Only before {@link opened}. After that the in-memory dag holds data loaded
|
|
16
|
+
* from the real store and loads more on demand, which an empty memory store
|
|
17
|
+
* cannot serve, so a failure is left to the caller. It is still reported, the
|
|
18
|
+
* first time a transaction fails to begin or to commit on a storage failure,
|
|
19
|
+
* whichever caller ran it (persist, heartbeat, garbage collection, ...).
|
|
20
|
+
*/
|
|
21
|
+
export declare class MemFallbackStoreProvider implements StoreProvider {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(inner: StoreProvider, onFallBack: (failure: StorageFailureError) => void, onFailureAfterOpen: (failure: StorageFailureError) => void);
|
|
24
|
+
/** Set once the stores have moved onto memory. */
|
|
25
|
+
get failure(): StorageFailureError | undefined;
|
|
26
|
+
/** The open has finished; storage failures no longer move the stores. */
|
|
27
|
+
opened(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Moves the stores onto memory if `error` reports a storage failure, the
|
|
30
|
+
* open has not finished, and they are not on memory already. Returns
|
|
31
|
+
* whether it moved them.
|
|
32
|
+
*/
|
|
33
|
+
fallBack(error: unknown): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Reports `error` if it is a storage failure after the open. Before it,
|
|
36
|
+
* the open's own error handling decides whether to fall back.
|
|
37
|
+
*/
|
|
38
|
+
report(error: unknown): void;
|
|
39
|
+
create: (name: string) => MemFallbackStore;
|
|
40
|
+
drop: (name: string) => Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export declare class MemFallbackStore implements Store {
|
|
43
|
+
#private;
|
|
44
|
+
constructor(name: string, store: Store, provider: MemFallbackStoreProvider);
|
|
45
|
+
read(): Promise<Read>;
|
|
46
|
+
write(): Promise<Write>;
|
|
47
|
+
/** The store currently backing this one: the real store, or memory. */
|
|
48
|
+
get backing(): Store;
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
get closed(): boolean;
|
|
51
|
+
/** `'mem'` from the moment the stores are on memory. */
|
|
52
|
+
get kind(): string | undefined;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=mem-fallback-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-fallback-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/mem-fallback-store.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAC,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAC,MAAM,YAAY,CAAC;AASlE,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,EAAE,aAMnC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAyB,YAAW,aAAa;;IAO5D,YACE,KAAK,EAAE,aAAa,EACpB,UAAU,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,EAClD,kBAAkB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,EAK3D;IAED,kDAAkD;IAClD,IAAI,OAAO,IAAI,mBAAmB,GAAG,SAAS,CAE7C;IAED,yEAAyE;IACzE,MAAM,IAAI,IAAI,CAEb;IAED;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWhC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAO3B;IAED,MAAM,SAAU,MAAM,KAAG,gBAAgB,CAYvC;IAEF,IAAI,SAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAGG;CACxC;AAED,qBAAa,gBAAiB,YAAW,KAAK;;IAO5C,YAAY,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,wBAAwB,EAKzE;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAK1B;IAEK,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAK5B;IAOD,uEAAuE;IACvE,IAAI,OAAO,IAAI,KAAK,CAanB;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGrB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,wDAAwD;IACxD,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;CACF"}
|