@rocicorp/zero 1.3.0 → 1.4.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/analyze-query/src/analyze-cli.d.ts +24 -0
- package/out/analyze-query/src/analyze-cli.d.ts.map +1 -0
- package/out/analyze-query/src/analyze-cli.js +289 -0
- package/out/analyze-query/src/analyze-cli.js.map +1 -0
- package/out/analyze-query/src/bin-analyze.js +6 -6
- package/out/analyze-query/src/bin-transform.js +2 -2
- package/out/ast-to-zql/src/bin.js +1 -1
- package/out/shared/src/logging.d.ts.map +1 -1
- package/out/shared/src/logging.js +1 -1
- package/out/shared/src/logging.js.map +1 -1
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +1 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +4 -1
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +1 -0
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +95 -89
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/analyze.d.ts +2 -0
- package/out/zero/src/analyze.d.ts.map +1 -0
- package/out/zero/src/analyze.js +2 -0
- package/out/zero/src/bindings.js +1 -1
- package/out/zero/src/zero-cache-dev.js +1 -1
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero/src/zero-out.js +1 -1
- package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +2 -2
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +5 -14
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/network.d.ts +1 -1
- package/out/zero-cache/src/config/network.d.ts.map +1 -1
- package/out/zero-cache/src/config/network.js +1 -1
- package/out/zero-cache/src/config/network.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +5 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +16 -3
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +3 -3
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts +43 -40
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +76 -56
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/observability/events.d.ts.map +1 -1
- package/out/zero-cache/src/observability/events.js +1 -1
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/scripts/decommission.js +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +2 -2
- package/out/zero-cache/src/scripts/permissions.js +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +4 -4
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +27 -12
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/logging.d.ts +1 -3
- package/out/zero-cache/src/server/logging.d.ts.map +1 -1
- package/out/zero-cache/src/server/logging.js +6 -3
- package/out/zero-cache/src/server/logging.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +26 -26
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/mutator.js +4 -2
- package/out/zero-cache/src/server/mutator.js.map +1 -1
- package/out/zero-cache/src/server/otel-log-sink.d.ts.map +1 -1
- package/out/zero-cache/src/server/otel-log-sink.js +0 -2
- package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.d.ts +1 -1
- package/out/zero-cache/src/server/otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/otel-start.js +7 -3
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-cache/src/server/reaper.js +6 -6
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +5 -3
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +2 -2
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +13 -12
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
- package/out/zero-cache/src/services/analyze.js +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +19 -23
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +58 -3
- 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 +209 -52
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +24 -15
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +35 -58
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +1 -2
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +15 -18
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +1 -1
- 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 +5 -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 +10 -7
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/replica-monitor.js +2 -2
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +19 -2
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +70 -6
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
- package/out/zero-cache/src/services/heapz.js +1 -1
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +2 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +10 -7
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +15 -4
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +40 -34
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +3 -3
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +28 -28
- package/out/zero-cache/src/services/replicator/change-processor.js +2 -2
- package/out/zero-cache/src/services/replicator/incremental-sync.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +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 +3 -3
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +3 -3
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +3 -3
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +2 -2
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +3 -3
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -2
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -16
- 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 +31 -39
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +4 -4
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -2
- 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 +6 -6
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts +1 -1
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts +1 -1
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/mutator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +3 -3
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/bindings.js +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +4 -13
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.d.ts +24 -0
- package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.js +28 -0
- package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +9 -0
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js +28 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +4 -13
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/log-options.d.ts +1 -0
- package/out/zero-client/src/client/log-options.d.ts.map +1 -1
- package/out/zero-client/src/client/log-options.js +3 -2
- package/out/zero-client/src/client/log-options.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +13 -1
- 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 +2 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-protocol/src/error.d.ts.map +1 -1
- package/out/zero-protocol/src/error.js +1 -1
- package/out/zero-protocol/src/error.js.map +1 -1
- package/out/zero-react/src/bindings.js +1 -1
- package/out/zero-solid/src/bindings.js +1 -1
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +14 -14
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +27 -2
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/change-index-enum.d.ts +9 -0
- package/out/zql/src/ivm/change-index-enum.d.ts.map +1 -0
- package/out/zql/src/ivm/change-index.d.ts +5 -0
- package/out/zql/src/ivm/change-index.d.ts.map +1 -0
- package/out/zql/src/ivm/change-type-enum.d.ts +9 -0
- package/out/zql/src/ivm/change-type-enum.d.ts.map +1 -0
- package/out/zql/src/ivm/change-type.d.ts +5 -0
- package/out/zql/src/ivm/change-type.d.ts.map +1 -0
- package/out/zql/src/ivm/change.d.ts +20 -22
- package/out/zql/src/ivm/change.d.ts.map +1 -1
- package/out/zql/src/ivm/change.js +33 -0
- package/out/zql/src/ivm/change.js.map +1 -0
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +27 -38
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +3 -2
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +1 -1
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +3 -3
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter-push.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-push.js +7 -7
- package/out/zql/src/ivm/filter-push.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +1 -1
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +49 -58
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts +2 -6
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +25 -25
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +32 -51
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +5 -10
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +52 -60
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +1 -1
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +2 -4
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts +3 -2
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +98 -122
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/skip-yields.d.ts +4 -0
- package/out/zql/src/ivm/skip-yields.d.ts.map +1 -0
- package/out/zql/src/ivm/skip-yields.js +33 -0
- package/out/zql/src/ivm/skip-yields.js.map +1 -0
- package/out/zql/src/ivm/skip.d.ts +1 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +2 -2
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/source-change-index-enum.d.ts +7 -0
- package/out/zql/src/ivm/source-change-index-enum.d.ts.map +1 -0
- package/out/zql/src/ivm/source-change-index.d.ts +5 -0
- package/out/zql/src/ivm/source-change-index.d.ts.map +1 -0
- package/out/zql/src/ivm/source.d.ts +11 -13
- package/out/zql/src/ivm/source.d.ts.map +1 -1
- package/out/zql/src/ivm/source.js +26 -0
- package/out/zql/src/ivm/source.js.map +1 -0
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +27 -50
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +2 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +3 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js +1 -1
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +2 -2
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/planner/planner-graph.d.ts +1 -1
- package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zqlite/src/internal/sql-inline.d.ts.map +1 -1
- package/out/zqlite/src/internal/sql-inline.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +11 -11
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +99 -93
package/out/zero/src/zero-out.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "../../shared/src/dotenv.js";
|
|
3
|
+
import { createLogContext } from "../../shared/src/logging.js";
|
|
3
4
|
import { parseOptions } from "../../shared/src/options.js";
|
|
4
5
|
import { ZERO_ENV_VAR_PREFIX } from "../../zero-cache/src/config/zero-config.js";
|
|
5
|
-
import { createLogContext } from "../../shared/src/logging.js";
|
|
6
6
|
import { decommissionOptions, decommissionZero } from "../../zero-cache/src/scripts/decommission.js";
|
|
7
7
|
//#region src/zero-out.ts
|
|
8
8
|
async function main() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AAIrC,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oCAAoC,CAAC;AAElE,yCAAyC;AACzC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,OAAO,CAAC;AAExC,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAAC,KACvC,OAAO,CAAC,OAAO,CAAC,CAAC;AAMtB,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,IAAI,GAAG,SAAS,WAQlE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,IAAI,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,GAC/C,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAoE3B;AAED,gEAAgE;AAChE,wBAAgB,SAAS,CACvB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,IAAI,GAAG,SAAS,EAC/B,QAAQ,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,oBAgFlC;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,SAAS,GAAG,SAAS,CAgCxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","names":[],"sources":["../../../../../zero-cache/src/auth/auth.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {JWTPayload} from 'jose';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {
|
|
1
|
+
{"version":3,"file":"auth.js","names":[],"sources":["../../../../../zero-cache/src/auth/auth.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {JWTPayload} from 'jose';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../zero-protocol/src/error-reason.ts';\nimport {\n isProtocolError,\n ProtocolError,\n type ErrorBody,\n} from '../../../zero-protocol/src/error.ts';\nimport type {PushError} from '../../../zero-protocol/src/push.ts';\n\n/** @deprecated JWT auth is deprecated */\nexport type JWTAuth = {\n readonly type: 'jwt';\n readonly raw: string;\n readonly decoded: JWTPayload;\n};\n\nexport type OpaqueAuth = {\n readonly type: 'opaque';\n readonly raw: string;\n};\n\nexport type Auth = OpaqueAuth | JWTAuth;\n\nexport type ValidateLegacyJWT = (\n token: string,\n ctx: {readonly userID: string | undefined},\n) => Promise<JWTAuth>;\n\nfunction isProvidedAuth(wireAuth: string | undefined): wireAuth is string {\n return wireAuth !== undefined && wireAuth !== '';\n}\n\nexport function authEquals(a: Auth | undefined, b: Auth | undefined) {\n if (a === b) {\n return true;\n }\n if (!a || !b) {\n return false;\n }\n return a.type === b.type && a.raw === b.raw;\n}\n\n/**\n * Resolves one auth snapshot transition without binding it to a client group.\n */\nexport async function resolveAuth(\n lc: LogContext,\n previousAuth: Auth | undefined,\n userID: string | undefined,\n wireAuth: string | undefined,\n validateLegacyJWT: ValidateLegacyJWT | undefined,\n): Promise<Auth | undefined> {\n try {\n const hasProvidedAuth = isProvidedAuth(wireAuth);\n\n if (previousAuth) {\n lc.debug?.(`Attempting to update auth from previous value`);\n } else {\n lc.debug?.(`Attempting to initialize auth`);\n }\n\n if (!hasProvidedAuth && previousAuth) {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'No token provided. An unauthenticated client cannot connect to an authenticated client group.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (!hasProvidedAuth) {\n lc.debug?.(`Cleared auth`);\n return undefined;\n }\n\n if (userID === undefined) {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message: 'Authenticated connections require a userID.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (validateLegacyJWT !== undefined) {\n const verifiedToken = await validateLegacyJWT(wireAuth, {userID});\n const nextAuth = pickToken(lc, previousAuth, verifiedToken);\n lc.debug?.(`Updated auth with JWT`);\n return nextAuth;\n }\n\n if (previousAuth?.type === 'jwt') {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'Token type cannot change from JWT to opaque. Connections are pinned to a single token type.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (previousAuth?.type === 'opaque' && previousAuth.raw === wireAuth) {\n lc.debug?.(`Opaque auth unchanged, reusing previous snapshot`);\n return previousAuth;\n }\n\n lc.debug?.(`Updated auth with opaque token`);\n return {\n type: 'opaque',\n raw: wireAuth,\n };\n } catch (e) {\n if (isProtocolError(e)) {\n throw e;\n }\n throw new ProtocolError({\n kind: ErrorKind.AuthInvalidated,\n message: `Failed to decode auth token: ${String(e)}`,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n}\n\n/** @deprecated used only in old JWT validation/rotation auth */\nexport function pickToken(\n lc: LogContext,\n previousToken: Auth | undefined,\n newToken: Auth | undefined | null,\n) {\n if (newToken === null) {\n return undefined;\n }\n\n if (\n previousToken?.type &&\n newToken?.type &&\n previousToken?.type !== newToken?.type\n ) {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'Token type cannot change. Client groups are pinned to a single token type.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (previousToken === undefined) {\n lc.debug?.(`No previous token, using new token`);\n return newToken;\n }\n\n if (newToken?.type === 'opaque') {\n return newToken;\n }\n\n if (previousToken.type === 'opaque') {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'Token type cannot change from opaque to JWT. Client groups are pinned to a single token type.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (newToken) {\n if (previousToken.decoded.sub !== newToken.decoded.sub) {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'The user id in the new token does not match the previous token. Client groups are pinned to a single user.',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n if (previousToken.decoded.iat === undefined) {\n lc.debug?.(`No issued at time for the existing token, using new token`);\n // No issued at time for the existing token? We take the most recently received token.\n return newToken;\n }\n\n if (newToken.decoded.iat === undefined) {\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'The new token does not have an issued at time but the prior token does. Tokens for a client group must either all have issued at times or all not have issued at times',\n origin: ErrorOrigin.ZeroCache,\n });\n }\n\n // The new token is newer, so we take it.\n if (previousToken.decoded.iat < newToken.decoded.iat) {\n lc.debug?.(`New token is newer, using it`);\n return newToken;\n }\n\n // if the new token is older or the same, we keep the existing token.\n lc.debug?.(`New token is older or the same, using existing token`);\n return previousToken;\n }\n\n // previousToken !== undefined but newToken is undefined\n throw new ProtocolError({\n kind: ErrorKind.Unauthorized,\n message:\n 'No token provided. An unauthenticated client cannot connect to an authenticated client group.',\n origin: ErrorOrigin.ZeroCache,\n });\n}\n\nexport function isAuthErrorBody(ex: unknown): ex is ErrorBody | PushError {\n if (typeof ex !== 'object' || ex === null) {\n return false;\n }\n\n if ('error' in ex) {\n return (\n ex.error === 'http' &&\n 'status' in ex &&\n (ex.status === 401 || ex.status === 403)\n );\n }\n\n if (!('kind' in ex)) {\n return false;\n }\n\n if (\n ex.kind === ErrorKind.AuthInvalidated ||\n ex.kind === ErrorKind.Unauthorized\n ) {\n return true;\n }\n\n return (\n (ex.kind === ErrorKind.PushFailed ||\n ex.kind === ErrorKind.TransformFailed) &&\n 'reason' in ex &&\n ex.reason === ErrorReason.HTTP &&\n 'status' in ex &&\n (ex.status === 401 || ex.status === 403)\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parse } from "../../../shared/src/valita.js";
|
|
2
|
-
import { elide } from "../types/strings.js";
|
|
3
|
-
import { permissionsConfigSchema } from "../../../zero-schema/src/compiled-permissions.js";
|
|
4
2
|
import { computeZqlSpecs } from "../db/lite-tables.js";
|
|
3
|
+
import { permissionsConfigSchema } from "../../../zero-schema/src/compiled-permissions.js";
|
|
4
|
+
import { elide } from "../types/strings.js";
|
|
5
5
|
//#region ../zero-cache/src/auth/load-permissions.ts
|
|
6
6
|
function loadPermissions(lc, replica, appID, config) {
|
|
7
7
|
const { permissions, hash } = replica.get(`SELECT permissions, hash FROM "${appID}.permissions"`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-authorizer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/write-authorizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AAUrC,OAAO,KAAK,EACV,MAAM,EAIN,QAAQ,EACT,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"write-authorizer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/write-authorizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AAUrC,OAAO,KAAK,EACV,MAAM,EAIN,QAAQ,EACT,MAAM,oCAAoC,CAAC;AAkB5C,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAMxD,OAAO,KAAK,EAAY,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAapE,MAAM,WAAW,eAAe;IAC9B,cAAc,CACZ,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,eAAe,CACb,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,iBAAiB,IAAI,IAAI,CAAC;IAC1B,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;IAEzD;;;OAGG;IACH,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CACzC;AAED,qBAAa,mBAAoB,YAAW,eAAe;;gBAgBvD,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,eAAe;IAwBpC,iBAAiB;IAUjB,OAAO;IAID,cAAc,CAClB,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAsB5B,eAAe,CACnB,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IA2DlC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAuBxD,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI;CAgUxC"}
|
|
@@ -7,12 +7,13 @@ import { newStaticQuery } from "../../../zql/src/query/static-query.js";
|
|
|
7
7
|
import { primaryKeyValueSchema } from "../../../zero-protocol/src/primary-key.js";
|
|
8
8
|
import { consume } from "../../../zql/src/ivm/stream.js";
|
|
9
9
|
import { bindStaticParameters, buildPipeline } from "../../../zql/src/builder/builder.js";
|
|
10
|
+
import { makeSourceChangeAdd, makeSourceChangeEdit, makeSourceChangeRemove } from "../../../zql/src/ivm/source.js";
|
|
10
11
|
import { compile, sql } from "../../../zqlite/src/internal/sql.js";
|
|
11
12
|
import { TableSource, fromSQLiteTypes } from "../../../zqlite/src/table-source.js";
|
|
12
|
-
import { StatementRunner } from "../db/statements.js";
|
|
13
13
|
import { mapLiteDataTypeToZqlSchemaValue } from "../types/lite.js";
|
|
14
14
|
import { computeZqlSpecs } from "../db/lite-tables.js";
|
|
15
15
|
import { getSchema, reloadPermissionsIfChanged } from "./load-permissions.js";
|
|
16
|
+
import { StatementRunner } from "../db/statements.js";
|
|
16
17
|
//#region ../zero-cache/src/auth/write-authorizer.ts
|
|
17
18
|
var WriteAuthorizerImpl = class {
|
|
18
19
|
#schema;
|
|
@@ -72,23 +73,13 @@ var WriteAuthorizerImpl = class {
|
|
|
72
73
|
const source = this.#getSource(op.tableName);
|
|
73
74
|
switch (op.op) {
|
|
74
75
|
case "insert":
|
|
75
|
-
consume(source.push(
|
|
76
|
-
type: "add",
|
|
77
|
-
row: op.value
|
|
78
|
-
}));
|
|
76
|
+
consume(source.push(makeSourceChangeAdd(op.value)));
|
|
79
77
|
break;
|
|
80
78
|
case "update":
|
|
81
|
-
consume(source.push(
|
|
82
|
-
type: "edit",
|
|
83
|
-
oldRow: this.#requirePreMutationRow(op),
|
|
84
|
-
row: op.value
|
|
85
|
-
}));
|
|
79
|
+
consume(source.push(makeSourceChangeEdit(op.value, this.#requirePreMutationRow(op))));
|
|
86
80
|
break;
|
|
87
81
|
case "delete":
|
|
88
|
-
consume(source.push(
|
|
89
|
-
type: "remove",
|
|
90
|
-
row: this.#requirePreMutationRow(op)
|
|
91
|
-
}));
|
|
82
|
+
consume(source.push(makeSourceChangeRemove(this.#requirePreMutationRow(op))));
|
|
92
83
|
break;
|
|
93
84
|
}
|
|
94
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-authorizer.js","names":["#schema","#replica","#builderDelegate","#tableSpecs","#tables","#statementRunner","#lc","#appID","#logConfig","#cgStorage","#config","#getSource","#loadedPermissions","#canUpdate","#canDelete","#requirePreMutationRow","#canInsert","#getPreMutationRow","#timedCanDo","#canDo","#getPrimaryKey","#passesPolicyGroup","#passesPolicy"],"sources":["../../../../../zero-cache/src/auth/write-authorizer.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport type {MaybePromise} from '@opentelemetry/resources';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {JWTPayload} from 'jose';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {JSONValue, ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {Condition} from '../../../zero-protocol/src/ast.ts';\nimport {\n primaryKeyValueSchema,\n type PrimaryKeyValue,\n} from '../../../zero-protocol/src/primary-key.ts';\nimport type {\n CRUDOp,\n DeleteOp,\n InsertOp,\n UpdateOp,\n UpsertOp,\n} from '../../../zero-protocol/src/push.ts';\nimport type {Policy} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport type {BuilderDelegate} from '../../../zql/src/builder/builder.ts';\nimport {\n bindStaticParameters,\n buildPipeline,\n} from '../../../zql/src/builder/builder.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport {simplifyCondition} from '../../../zql/src/query/expression.ts';\nimport {asQueryInternals} from '../../../zql/src/query/query-internals.ts';\nimport type {Query} from '../../../zql/src/query/query.ts';\nimport {newStaticQuery} from '../../../zql/src/query/static-query.ts';\nimport type {\n ClientGroupStorage,\n DatabaseStorage,\n} from '../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {compile, sql} from '../../../zqlite/src/internal/sql.ts';\nimport {\n fromSQLiteTypes,\n TableSource,\n} from '../../../zqlite/src/table-source.ts';\nimport type {LogConfig, ZeroConfig} from '../config/zero-config.ts';\nimport {computeZqlSpecs} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec} from '../db/specs.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {mapLiteDataTypeToZqlSchemaValue} from '../types/lite.ts';\nimport {\n getSchema,\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from './load-permissions.ts';\n\ntype Phase = 'preMutation' | 'postMutation';\n\nexport interface WriteAuthorizer {\n canPreMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ): Promise<boolean>;\n canPostMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ): Promise<boolean>;\n reloadPermissions(): void;\n normalizeOps(ops: CRUDOp[]): Exclude<CRUDOp, UpsertOp>[];\n\n /**\n * Validates that all table names in the operations exist in the schema.\n * @throws Error if any table name is invalid\n */\n validateTableNames(ops: CRUDOp[]): void;\n}\n\nexport class WriteAuthorizerImpl implements WriteAuthorizer {\n readonly #schema: Schema;\n readonly #replica: Database;\n readonly #builderDelegate: BuilderDelegate;\n readonly #tableSpecs: Map<string, LiteAndZqlSpec>;\n readonly #tables = new Map<string, TableSource>();\n readonly #statementRunner: StatementRunner;\n readonly #lc: LogContext;\n readonly #appID: string;\n readonly #logConfig: LogConfig;\n readonly #cgStorage: ClientGroupStorage;\n readonly #config: ZeroConfig;\n\n #loadedPermissions: LoadedPermissions | null = null;\n\n constructor(\n lc: LogContext,\n config: ZeroConfig,\n replica: Database,\n appID: string,\n cgID: string,\n writeAuthzStorage: DatabaseStorage,\n ) {\n this.#appID = appID;\n this.#config = config;\n this.#lc = lc.withContext('class', 'WriteAuthorizerImpl');\n this.#logConfig = config.log;\n this.#schema = getSchema(this.#lc, replica);\n this.#replica = replica;\n this.#cgStorage = writeAuthzStorage.createClientGroupStorage(cgID);\n this.#builderDelegate = {\n getSource: name => this.#getSource(name),\n createStorage: () => this.#cgStorage.createStorage(),\n decorateSourceInput: input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n };\n this.#tableSpecs = computeZqlSpecs(this.#lc, replica, {\n includeBackfillingColumns: false,\n });\n this.#statementRunner = new StatementRunner(replica);\n this.reloadPermissions();\n }\n\n reloadPermissions() {\n this.#loadedPermissions = reloadPermissionsIfChanged(\n this.#lc,\n this.#statementRunner,\n this.#appID,\n this.#loadedPermissions,\n this.#config,\n ).permissions;\n }\n\n destroy() {\n this.#cgStorage.destroy();\n }\n\n async canPreMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ) {\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n // insert does not run pre-mutation checks\n break;\n case 'update':\n if (!(await this.#canUpdate('preMutation', authData, op))) {\n return false;\n }\n break;\n case 'delete':\n if (!(await this.#canDelete('preMutation', authData, op))) {\n return false;\n }\n break;\n }\n }\n return true;\n }\n\n async canPostMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ) {\n this.#statementRunner.beginConcurrent();\n try {\n for (const op of ops) {\n const source = this.#getSource(op.tableName);\n switch (op.op) {\n case 'insert': {\n consume(\n source.push({\n type: 'add',\n row: op.value,\n }),\n );\n break;\n }\n // TODO(mlaw): what if someone updates the same thing twice?\n // TODO(aa): It seems like it will just work? source.push()\n // is going to push the row into the table source, and then the\n // next requirePreMutationRow will just return the row that was\n // pushed in.\n case 'update': {\n consume(\n source.push({\n type: 'edit',\n oldRow: this.#requirePreMutationRow(op),\n row: op.value,\n }),\n );\n break;\n }\n case 'delete': {\n consume(\n source.push({\n type: 'remove',\n row: this.#requirePreMutationRow(op),\n }),\n );\n break;\n }\n }\n }\n\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n if (!(await this.#canInsert('postMutation', authData, op))) {\n return false;\n }\n break;\n case 'update':\n if (!(await this.#canUpdate('postMutation', authData, op))) {\n return false;\n }\n break;\n case 'delete':\n // delete does not run post-mutation checks.\n break;\n }\n }\n } finally {\n this.#statementRunner.rollback();\n }\n\n return true;\n }\n\n normalizeOps(ops: CRUDOp[]): Exclude<CRUDOp, UpsertOp>[] {\n return ops.map(op => {\n if (op.op === 'upsert') {\n const preMutationRow = this.#getPreMutationRow(op);\n if (preMutationRow) {\n return {\n op: 'update',\n tableName: op.tableName,\n primaryKey: op.primaryKey,\n value: op.value,\n };\n }\n return {\n op: 'insert',\n tableName: op.tableName,\n primaryKey: op.primaryKey,\n value: op.value,\n };\n }\n return op;\n });\n }\n\n validateTableNames(ops: CRUDOp[]): void {\n for (const op of ops) {\n if (!this.#tableSpecs.has(op.tableName)) {\n throw new Error(`Table '${op.tableName}' is not a valid table.`);\n }\n }\n }\n\n #canInsert(phase: Phase, authData: JWTPayload | undefined, op: InsertOp) {\n return this.#timedCanDo(phase, 'insert', authData, op);\n }\n\n #canUpdate(phase: Phase, authData: JWTPayload | undefined, op: UpdateOp) {\n return this.#timedCanDo(phase, 'update', authData, op);\n }\n\n #canDelete(phase: Phase, authData: JWTPayload | undefined, op: DeleteOp) {\n return this.#timedCanDo(phase, 'delete', authData, op);\n }\n\n /**\n * Gets schema-defined primary key and validates that operation contains required PK values.\n *\n * @returns Record where keys are column names and values are client-provided values\n * @throws Error if operation value is missing required primary key columns\n */\n #getPrimaryKey(\n tableName: string,\n opValue: Record<string, ReadonlyJSONValue | undefined>,\n ): Record<string, ReadonlyJSONValue> {\n const tableSpec = this.#tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(`Table ${tableName} not found`);\n }\n const columns = tableSpec.tableSpec.primaryKey;\n\n // Extract primary key values from operation value and validate they exist\n const values: Record<string, ReadonlyJSONValue> = {};\n for (const col of columns) {\n const val = opValue[col];\n if (val === undefined) {\n throw new Error(\n `Primary key column '${col}' is missing from operation value for table ${tableName}`,\n );\n }\n values[col] = val;\n }\n\n return values;\n }\n\n #getSource(tableName: string) {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n const tableSpec = this.#tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(`Table ${tableName} not found`);\n }\n const {columns, primaryKey} = tableSpec.tableSpec;\n assert(\n primaryKey.length,\n () => `Table ${tableName} must have a primary key`,\n );\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n this.#replica,\n tableName,\n Object.fromEntries(\n Object.entries(columns).map(([name, {dataType}]) => [\n name,\n mapLiteDataTypeToZqlSchemaValue(dataType),\n ]),\n ),\n [primaryKey[0], ...primaryKey.slice(1)],\n );\n this.#tables.set(tableName, source);\n\n return source;\n }\n\n async #timedCanDo<A extends keyof ActionOpMap>(\n phase: Phase,\n action: A,\n authData: JWTPayload | undefined,\n op: ActionOpMap[A],\n ) {\n const start = performance.now();\n try {\n const ret = await this.#canDo(phase, action, authData, op);\n return ret;\n } finally {\n this.#lc.info?.(\n 'action:',\n action,\n 'duration:',\n performance.now() - start,\n 'tableName:',\n op.tableName,\n 'primaryKey:',\n op.primaryKey,\n );\n }\n }\n\n /**\n * Evaluation order is from static to dynamic, broad to specific.\n * table -> column -> row -> cell.\n *\n * If any step fails, the entire operation is denied.\n *\n * That is, table rules supersede column rules, which supersede row rules,\n *\n * All steps must allow for the operation to be allowed.\n */\n async #canDo<A extends keyof ActionOpMap>(\n phase: Phase,\n action: A,\n authData: JWTPayload | undefined,\n op: ActionOpMap[A],\n ) {\n const rules = must(this.#loadedPermissions)?.permissions?.tables?.[\n op.tableName\n ];\n const rowPolicies = rules?.row;\n let rowQuery = newStaticQuery(this.#schema, op.tableName);\n\n const primaryKeyValues = this.#getPrimaryKey(op.tableName, op.value);\n\n for (const pk in primaryKeyValues) {\n rowQuery = rowQuery.where(pk, '=', primaryKeyValues[pk]);\n }\n\n let applicableRowPolicy: Policy | undefined;\n switch (action) {\n case 'insert':\n if (phase === 'postMutation') {\n applicableRowPolicy = rowPolicies?.insert;\n }\n break;\n case 'update':\n if (phase === 'preMutation') {\n applicableRowPolicy = rowPolicies?.update?.preMutation;\n } else if (phase === 'postMutation') {\n applicableRowPolicy = rowPolicies?.update?.postMutation;\n }\n break;\n case 'delete':\n if (phase === 'preMutation') {\n applicableRowPolicy = rowPolicies?.delete;\n }\n break;\n }\n\n const cellPolicies = rules?.cell;\n const applicableCellPolicies: Policy[] = [];\n if (cellPolicies) {\n for (const [column, policy] of Object.entries(cellPolicies)) {\n if (action === 'update' && op.value[column] === undefined) {\n // If the cell is not being updated, we do not need to check\n // the cell rules.\n continue;\n }\n switch (action) {\n case 'insert':\n if (policy.insert && phase === 'postMutation') {\n applicableCellPolicies.push(policy.insert);\n }\n break;\n case 'update':\n if (phase === 'preMutation' && policy.update?.preMutation) {\n applicableCellPolicies.push(policy.update.preMutation);\n }\n if (phase === 'postMutation' && policy.update?.postMutation) {\n applicableCellPolicies.push(policy.update.postMutation);\n }\n break;\n case 'delete':\n if (policy.delete && phase === 'preMutation') {\n applicableCellPolicies.push(policy.delete);\n }\n break;\n }\n }\n }\n\n if (\n !(await this.#passesPolicyGroup(\n applicableRowPolicy,\n applicableCellPolicies,\n authData,\n rowQuery,\n ))\n ) {\n this.#lc.warn?.(\n `Permission check failed for ${JSON.stringify(\n op,\n )}, action ${action}, phase ${phase}, authData: ${JSON.stringify(\n authData,\n )}, rowPolicies: ${JSON.stringify(\n applicableRowPolicy,\n )}, cellPolicies: ${JSON.stringify(applicableCellPolicies)}`,\n );\n return false;\n }\n\n return true;\n }\n\n #getPreMutationRow(op: UpsertOp | UpdateOp | DeleteOp) {\n const {value} = op;\n\n const primaryKeyValues = this.#getPrimaryKey(op.tableName, value);\n\n const spec = this.#tableSpecs.get(op.tableName);\n if (!spec) {\n throw new Error(`Table ${op.tableName} not found`);\n }\n\n const conditions: SQLQuery[] = [];\n const values: PrimaryKeyValue[] = [];\n for (const pk in primaryKeyValues) {\n conditions.push(sql`${sql.ident(pk)}=?`);\n values.push(v.parse(primaryKeyValues[pk], primaryKeyValueSchema));\n }\n\n const ret = this.#statementRunner.get(\n compile(\n sql`SELECT ${sql.join(\n Object.keys(spec.zqlSpec).map(c => sql.ident(c)),\n sql`,`,\n )} FROM ${sql.ident(op.tableName)} WHERE ${sql.join(\n conditions,\n sql` AND `,\n )}`,\n ),\n ...values,\n );\n if (ret === undefined) {\n return ret;\n }\n return fromSQLiteTypes(spec.zqlSpec, ret, op.tableName);\n }\n\n #requirePreMutationRow(op: UpdateOp | DeleteOp) {\n const ret = this.#getPreMutationRow(op);\n assert(\n ret !== undefined,\n () => `Pre-mutation row not found for ${JSON.stringify(op.value)}`,\n );\n return ret;\n }\n\n async #passesPolicyGroup(\n applicableRowPolicy: Policy | undefined,\n applicableCellPolicies: Policy[],\n authData: JWTPayload | undefined,\n rowQuery: Query<string, Schema>,\n ) {\n if (!(await this.#passesPolicy(applicableRowPolicy, authData, rowQuery))) {\n return false;\n }\n\n for (const policy of applicableCellPolicies) {\n if (!(await this.#passesPolicy(policy, authData, rowQuery))) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Defaults to *false* if the policy is empty. At least one rule has to pass\n * for the policy to pass.\n */\n #passesPolicy(\n policy: Policy | undefined,\n authData: JWTPayload | undefined,\n rowQuery: Query<string, Schema>,\n ): MaybePromise<boolean> {\n if (policy === undefined) {\n return false;\n }\n if (policy.length === 0) {\n return false;\n }\n let rowQueryAst = asQueryInternals(rowQuery).ast;\n rowQueryAst = bindStaticParameters(\n {\n ...rowQueryAst,\n where: updateWhere(rowQueryAst.where, policy),\n },\n {\n authData: authData as Record<string, JSONValue>,\n preMutationRow: undefined,\n },\n );\n\n // call the compiler directly\n // run the sql against upstream.\n // remove the collecting into json? just need to know if a row comes back.\n\n const input = buildPipeline(rowQueryAst, this.#builderDelegate, 'query-id');\n try {\n const res = input.fetch({});\n for (const _ of res) {\n // if any row is returned at all, the\n // rule passes.\n return true;\n }\n } finally {\n input.destroy();\n }\n\n // no rows returned by any rules? The policy fails.\n return false;\n }\n}\n\nfunction updateWhere(where: Condition | undefined, policy: Policy) {\n assert(where, 'A where condition must exist for RowQuery');\n\n return simplifyCondition({\n type: 'and',\n conditions: [\n where,\n {\n type: 'or',\n conditions: policy.map(([action, rule]) => {\n assert(action, 'action must be defined in policy');\n return rule;\n }),\n },\n ],\n });\n}\n\ntype ActionOpMap = {\n insert: InsertOp;\n update: UpdateOp;\n delete: DeleteOp;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AA0EA,IAAa,sBAAb,MAA4D;CAC1D;CACA;CACA;CACA;CACA,0BAAmB,IAAI,KAA0B;CACjD;CACA;CACA;CACA;CACA;CACA;CAEA,qBAA+C;CAE/C,YACE,IACA,QACA,SACA,OACA,MACA,mBACA;AACA,QAAA,QAAc;AACd,QAAA,SAAe;AACf,QAAA,KAAW,GAAG,YAAY,SAAS,sBAAsB;AACzD,QAAA,YAAkB,OAAO;AACzB,QAAA,SAAe,UAAU,MAAA,IAAU,QAAQ;AAC3C,QAAA,UAAgB;AAChB,QAAA,YAAkB,kBAAkB,yBAAyB,KAAK;AAClE,QAAA,kBAAwB;GACtB,YAAW,SAAQ,MAAA,UAAgB,KAAK;GACxC,qBAAqB,MAAA,UAAgB,eAAe;GACpD,sBAAqB,UAAS;GAC9B,gBAAe,UAAS;GACxB,UAAU;GACV,sBAAqB,UAAS;GAC/B;AACD,QAAA,aAAmB,gBAAgB,MAAA,IAAU,SAAS,EACpD,2BAA2B,OAC5B,CAAC;AACF,QAAA,kBAAwB,IAAI,gBAAgB,QAAQ;AACpD,OAAK,mBAAmB;;CAG1B,oBAAoB;AAClB,QAAA,oBAA0B,2BACxB,MAAA,IACA,MAAA,iBACA,MAAA,OACA,MAAA,mBACA,MAAA,OACD,CAAC;;CAGJ,UAAU;AACR,QAAA,UAAgB,SAAS;;CAG3B,MAAM,eACJ,UACA,KACA;AACA,OAAK,MAAM,MAAM,IACf,SAAQ,GAAG,IAAX;GACE,KAAK,SAEH;GACF,KAAK;AACH,QAAI,CAAE,MAAM,MAAA,UAAgB,eAAe,UAAU,GAAG,CACtD,QAAO;AAET;GACF,KAAK;AACH,QAAI,CAAE,MAAM,MAAA,UAAgB,eAAe,UAAU,GAAG,CACtD,QAAO;AAET;;AAGN,SAAO;;CAGT,MAAM,gBACJ,UACA,KACA;AACA,QAAA,gBAAsB,iBAAiB;AACvC,MAAI;AACF,QAAK,MAAM,MAAM,KAAK;IACpB,MAAM,SAAS,MAAA,UAAgB,GAAG,UAAU;AAC5C,YAAQ,GAAG,IAAX;KACE,KAAK;AACH,cACE,OAAO,KAAK;OACV,MAAM;OACN,KAAK,GAAG;OACT,CAAC,CACH;AACD;KAOF,KAAK;AACH,cACE,OAAO,KAAK;OACV,MAAM;OACN,QAAQ,MAAA,sBAA4B,GAAG;OACvC,KAAK,GAAG;OACT,CAAC,CACH;AACD;KAEF,KAAK;AACH,cACE,OAAO,KAAK;OACV,MAAM;OACN,KAAK,MAAA,sBAA4B,GAAG;OACrC,CAAC,CACH;AACD;;;AAKN,QAAK,MAAM,MAAM,IACf,SAAQ,GAAG,IAAX;IACE,KAAK;AACH,SAAI,CAAE,MAAM,MAAA,UAAgB,gBAAgB,UAAU,GAAG,CACvD,QAAO;AAET;IACF,KAAK;AACH,SAAI,CAAE,MAAM,MAAA,UAAgB,gBAAgB,UAAU,GAAG,CACvD,QAAO;AAET;IACF,KAAK,SAEH;;YAGE;AACR,SAAA,gBAAsB,UAAU;;AAGlC,SAAO;;CAGT,aAAa,KAA4C;AACvD,SAAO,IAAI,KAAI,OAAM;AACnB,OAAI,GAAG,OAAO,UAAU;AAEtB,QADuB,MAAA,kBAAwB,GAAG,CAEhD,QAAO;KACL,IAAI;KACJ,WAAW,GAAG;KACd,YAAY,GAAG;KACf,OAAO,GAAG;KACX;AAEH,WAAO;KACL,IAAI;KACJ,WAAW,GAAG;KACd,YAAY,GAAG;KACf,OAAO,GAAG;KACX;;AAEH,UAAO;IACP;;CAGJ,mBAAmB,KAAqB;AACtC,OAAK,MAAM,MAAM,IACf,KAAI,CAAC,MAAA,WAAiB,IAAI,GAAG,UAAU,CACrC,OAAM,IAAI,MAAM,UAAU,GAAG,UAAU,yBAAyB;;CAKtE,WAAW,OAAc,UAAkC,IAAc;AACvE,SAAO,MAAA,WAAiB,OAAO,UAAU,UAAU,GAAG;;CAGxD,WAAW,OAAc,UAAkC,IAAc;AACvE,SAAO,MAAA,WAAiB,OAAO,UAAU,UAAU,GAAG;;CAGxD,WAAW,OAAc,UAAkC,IAAc;AACvE,SAAO,MAAA,WAAiB,OAAO,UAAU,UAAU,GAAG;;;;;;;;CASxD,eACE,WACA,SACmC;EACnC,MAAM,YAAY,MAAA,WAAiB,IAAI,UAAU;AACjD,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,SAAS,UAAU,YAAY;EAEjD,MAAM,UAAU,UAAU,UAAU;EAGpC,MAAM,SAA4C,EAAE;AACpD,OAAK,MAAM,OAAO,SAAS;GACzB,MAAM,MAAM,QAAQ;AACpB,OAAI,QAAQ,KAAA,EACV,OAAM,IAAI,MACR,uBAAuB,IAAI,8CAA8C,YAC1E;AAEH,UAAO,OAAO;;AAGhB,SAAO;;CAGT,WAAW,WAAmB;EAC5B,IAAI,SAAS,MAAA,OAAa,IAAI,UAAU;AACxC,MAAI,OACF,QAAO;EAET,MAAM,YAAY,MAAA,WAAiB,IAAI,UAAU;AACjD,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,SAAS,UAAU,YAAY;EAEjD,MAAM,EAAC,SAAS,eAAc,UAAU;AACxC,SACE,WAAW,cACL,SAAS,UAAU,0BAC1B;AACD,WAAS,IAAI,YACX,MAAA,IACA,MAAA,WACA,MAAA,SACA,WACA,OAAO,YACL,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAC,gBAAe,CAClD,MACA,gCAAgC,SAAS,CAC1C,CAAC,CACH,EACD,CAAC,WAAW,IAAI,GAAG,WAAW,MAAM,EAAE,CAAC,CACxC;AACD,QAAA,OAAa,IAAI,WAAW,OAAO;AAEnC,SAAO;;CAGT,OAAA,WACE,OACA,QACA,UACA,IACA;EACA,MAAM,QAAQ,YAAY,KAAK;AAC/B,MAAI;AAEF,UADY,MAAM,MAAA,MAAY,OAAO,QAAQ,UAAU,GAAG;YAElD;AACR,SAAA,GAAS,OACP,WACA,QACA,aACA,YAAY,KAAK,GAAG,OACpB,cACA,GAAG,WACH,eACA,GAAG,WACJ;;;;;;;;;;;;;CAcL,OAAA,MACE,OACA,QACA,UACA,IACA;EACA,MAAM,QAAQ,KAAK,MAAA,kBAAwB,EAAE,aAAa,SACxD,GAAG;EAEL,MAAM,cAAc,OAAO;EAC3B,IAAI,WAAW,eAAe,MAAA,QAAc,GAAG,UAAU;EAEzD,MAAM,mBAAmB,MAAA,cAAoB,GAAG,WAAW,GAAG,MAAM;AAEpE,OAAK,MAAM,MAAM,iBACf,YAAW,SAAS,MAAM,IAAI,KAAK,iBAAiB,IAAI;EAG1D,IAAI;AACJ,UAAQ,QAAR;GACE,KAAK;AACH,QAAI,UAAU,eACZ,uBAAsB,aAAa;AAErC;GACF,KAAK;AACH,QAAI,UAAU,cACZ,uBAAsB,aAAa,QAAQ;aAClC,UAAU,eACnB,uBAAsB,aAAa,QAAQ;AAE7C;GACF,KAAK;AACH,QAAI,UAAU,cACZ,uBAAsB,aAAa;AAErC;;EAGJ,MAAM,eAAe,OAAO;EAC5B,MAAM,yBAAmC,EAAE;AAC3C,MAAI,aACF,MAAK,MAAM,CAAC,QAAQ,WAAW,OAAO,QAAQ,aAAa,EAAE;AAC3D,OAAI,WAAW,YAAY,GAAG,MAAM,YAAY,KAAA,EAG9C;AAEF,WAAQ,QAAR;IACE,KAAK;AACH,SAAI,OAAO,UAAU,UAAU,eAC7B,wBAAuB,KAAK,OAAO,OAAO;AAE5C;IACF,KAAK;AACH,SAAI,UAAU,iBAAiB,OAAO,QAAQ,YAC5C,wBAAuB,KAAK,OAAO,OAAO,YAAY;AAExD,SAAI,UAAU,kBAAkB,OAAO,QAAQ,aAC7C,wBAAuB,KAAK,OAAO,OAAO,aAAa;AAEzD;IACF,KAAK;AACH,SAAI,OAAO,UAAU,UAAU,cAC7B,wBAAuB,KAAK,OAAO,OAAO;AAE5C;;;AAKR,MACE,CAAE,MAAM,MAAA,kBACN,qBACA,wBACA,UACA,SACD,EACD;AACA,SAAA,GAAS,OACP,+BAA+B,KAAK,UAClC,GACD,CAAC,WAAW,OAAO,UAAU,MAAM,cAAc,KAAK,UACrD,SACD,CAAC,iBAAiB,KAAK,UACtB,oBACD,CAAC,kBAAkB,KAAK,UAAU,uBAAuB,GAC3D;AACD,UAAO;;AAGT,SAAO;;CAGT,mBAAmB,IAAoC;EACrD,MAAM,EAAC,UAAS;EAEhB,MAAM,mBAAmB,MAAA,cAAoB,GAAG,WAAW,MAAM;EAEjE,MAAM,OAAO,MAAA,WAAiB,IAAI,GAAG,UAAU;AAC/C,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,SAAS,GAAG,UAAU,YAAY;EAGpD,MAAM,aAAyB,EAAE;EACjC,MAAM,SAA4B,EAAE;AACpC,OAAK,MAAM,MAAM,kBAAkB;AACjC,cAAW,KAAK,GAAG,GAAG,IAAI,MAAM,GAAG,CAAC,IAAI;AACxC,UAAO,KAAK,MAAQ,iBAAiB,KAAK,sBAAsB,CAAC;;EAGnE,MAAM,MAAM,MAAA,gBAAsB,IAChC,QACE,GAAG,UAAU,IAAI,KACf,OAAO,KAAK,KAAK,QAAQ,CAAC,KAAI,MAAK,IAAI,MAAM,EAAE,CAAC,EAChD,GAAG,IACJ,CAAC,QAAQ,IAAI,MAAM,GAAG,UAAU,CAAC,SAAS,IAAI,KAC7C,YACA,GAAG,QACJ,GACF,EACD,GAAG,OACJ;AACD,MAAI,QAAQ,KAAA,EACV,QAAO;AAET,SAAO,gBAAgB,KAAK,SAAS,KAAK,GAAG,UAAU;;CAGzD,uBAAuB,IAAyB;EAC9C,MAAM,MAAM,MAAA,kBAAwB,GAAG;AACvC,SACE,QAAQ,KAAA,SACF,kCAAkC,KAAK,UAAU,GAAG,MAAM,GACjE;AACD,SAAO;;CAGT,OAAA,kBACE,qBACA,wBACA,UACA,UACA;AACA,MAAI,CAAE,MAAM,MAAA,aAAmB,qBAAqB,UAAU,SAAS,CACrE,QAAO;AAGT,OAAK,MAAM,UAAU,uBACnB,KAAI,CAAE,MAAM,MAAA,aAAmB,QAAQ,UAAU,SAAS,CACxD,QAAO;AAIX,SAAO;;;;;;CAOT,cACE,QACA,UACA,UACuB;AACvB,MAAI,WAAW,KAAA,EACb,QAAO;AAET,MAAI,OAAO,WAAW,EACpB,QAAO;EAET,IAAI,cAAc,iBAAiB,SAAS,CAAC;AAC7C,gBAAc,qBACZ;GACE,GAAG;GACH,OAAO,YAAY,YAAY,OAAO,OAAO;GAC9C,EACD;GACY;GACV,gBAAgB,KAAA;GACjB,CACF;EAMD,MAAM,QAAQ,cAAc,aAAa,MAAA,iBAAuB,WAAW;AAC3E,MAAI;GACF,MAAM,MAAM,MAAM,MAAM,EAAE,CAAC;AAC3B,QAAK,MAAM,KAAK,IAGd,QAAO;YAED;AACR,SAAM,SAAS;;AAIjB,SAAO;;;AAIX,SAAS,YAAY,OAA8B,QAAgB;AACjE,QAAO,OAAO,4CAA4C;AAE1D,QAAO,kBAAkB;EACvB,MAAM;EACN,YAAY,CACV,OACA;GACE,MAAM;GACN,YAAY,OAAO,KAAK,CAAC,QAAQ,UAAU;AACzC,WAAO,QAAQ,mCAAmC;AAClD,WAAO;KACP;GACH,CACF;EACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"write-authorizer.js","names":["#schema","#replica","#builderDelegate","#tableSpecs","#tables","#statementRunner","#lc","#appID","#logConfig","#cgStorage","#config","#getSource","#loadedPermissions","#canUpdate","#canDelete","#requirePreMutationRow","#canInsert","#getPreMutationRow","#timedCanDo","#canDo","#getPrimaryKey","#passesPolicyGroup","#passesPolicy"],"sources":["../../../../../zero-cache/src/auth/write-authorizer.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport type {MaybePromise} from '@opentelemetry/resources';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {JWTPayload} from 'jose';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {JSONValue, ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {Condition} from '../../../zero-protocol/src/ast.ts';\nimport {\n primaryKeyValueSchema,\n type PrimaryKeyValue,\n} from '../../../zero-protocol/src/primary-key.ts';\nimport type {\n CRUDOp,\n DeleteOp,\n InsertOp,\n UpdateOp,\n UpsertOp,\n} from '../../../zero-protocol/src/push.ts';\nimport type {Policy} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport type {BuilderDelegate} from '../../../zql/src/builder/builder.ts';\nimport {\n bindStaticParameters,\n buildPipeline,\n} from '../../../zql/src/builder/builder.ts';\nimport {\n makeSourceChangeAdd,\n makeSourceChangeEdit,\n makeSourceChangeRemove,\n} from '../../../zql/src/ivm/source.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport {simplifyCondition} from '../../../zql/src/query/expression.ts';\nimport {asQueryInternals} from '../../../zql/src/query/query-internals.ts';\nimport type {Query} from '../../../zql/src/query/query.ts';\nimport {newStaticQuery} from '../../../zql/src/query/static-query.ts';\nimport type {\n ClientGroupStorage,\n DatabaseStorage,\n} from '../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {compile, sql} from '../../../zqlite/src/internal/sql.ts';\nimport {\n fromSQLiteTypes,\n TableSource,\n} from '../../../zqlite/src/table-source.ts';\nimport type {LogConfig, ZeroConfig} from '../config/zero-config.ts';\nimport {computeZqlSpecs} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec} from '../db/specs.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {mapLiteDataTypeToZqlSchemaValue} from '../types/lite.ts';\nimport {\n getSchema,\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from './load-permissions.ts';\n\ntype Phase = 'preMutation' | 'postMutation';\n\nexport interface WriteAuthorizer {\n canPreMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ): Promise<boolean>;\n canPostMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ): Promise<boolean>;\n reloadPermissions(): void;\n normalizeOps(ops: CRUDOp[]): Exclude<CRUDOp, UpsertOp>[];\n\n /**\n * Validates that all table names in the operations exist in the schema.\n * @throws Error if any table name is invalid\n */\n validateTableNames(ops: CRUDOp[]): void;\n}\n\nexport class WriteAuthorizerImpl implements WriteAuthorizer {\n readonly #schema: Schema;\n readonly #replica: Database;\n readonly #builderDelegate: BuilderDelegate;\n readonly #tableSpecs: Map<string, LiteAndZqlSpec>;\n readonly #tables = new Map<string, TableSource>();\n readonly #statementRunner: StatementRunner;\n readonly #lc: LogContext;\n readonly #appID: string;\n readonly #logConfig: LogConfig;\n readonly #cgStorage: ClientGroupStorage;\n readonly #config: ZeroConfig;\n\n #loadedPermissions: LoadedPermissions | null = null;\n\n constructor(\n lc: LogContext,\n config: ZeroConfig,\n replica: Database,\n appID: string,\n cgID: string,\n writeAuthzStorage: DatabaseStorage,\n ) {\n this.#appID = appID;\n this.#config = config;\n this.#lc = lc.withContext('class', 'WriteAuthorizerImpl');\n this.#logConfig = config.log;\n this.#schema = getSchema(this.#lc, replica);\n this.#replica = replica;\n this.#cgStorage = writeAuthzStorage.createClientGroupStorage(cgID);\n this.#builderDelegate = {\n getSource: name => this.#getSource(name),\n createStorage: () => this.#cgStorage.createStorage(),\n decorateSourceInput: input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n };\n this.#tableSpecs = computeZqlSpecs(this.#lc, replica, {\n includeBackfillingColumns: false,\n });\n this.#statementRunner = new StatementRunner(replica);\n this.reloadPermissions();\n }\n\n reloadPermissions() {\n this.#loadedPermissions = reloadPermissionsIfChanged(\n this.#lc,\n this.#statementRunner,\n this.#appID,\n this.#loadedPermissions,\n this.#config,\n ).permissions;\n }\n\n destroy() {\n this.#cgStorage.destroy();\n }\n\n async canPreMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ) {\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n // insert does not run pre-mutation checks\n break;\n case 'update':\n if (!(await this.#canUpdate('preMutation', authData, op))) {\n return false;\n }\n break;\n case 'delete':\n if (!(await this.#canDelete('preMutation', authData, op))) {\n return false;\n }\n break;\n }\n }\n return true;\n }\n\n async canPostMutation(\n authData: JWTPayload | undefined,\n ops: Exclude<CRUDOp, UpsertOp>[],\n ) {\n this.#statementRunner.beginConcurrent();\n try {\n for (const op of ops) {\n const source = this.#getSource(op.tableName);\n switch (op.op) {\n case 'insert': {\n consume(source.push(makeSourceChangeAdd(op.value)));\n break;\n }\n // TODO(mlaw): what if someone updates the same thing twice?\n // TODO(aa): It seems like it will just work? source.push()\n // is going to push the row into the table source, and then the\n // next requirePreMutationRow will just return the row that was\n // pushed in.\n case 'update': {\n consume(\n source.push(\n makeSourceChangeEdit(op.value, this.#requirePreMutationRow(op)),\n ),\n );\n break;\n }\n case 'delete': {\n consume(\n source.push(\n makeSourceChangeRemove(this.#requirePreMutationRow(op)),\n ),\n );\n break;\n }\n }\n }\n\n for (const op of ops) {\n switch (op.op) {\n case 'insert':\n if (!(await this.#canInsert('postMutation', authData, op))) {\n return false;\n }\n break;\n case 'update':\n if (!(await this.#canUpdate('postMutation', authData, op))) {\n return false;\n }\n break;\n case 'delete':\n // delete does not run post-mutation checks.\n break;\n }\n }\n } finally {\n this.#statementRunner.rollback();\n }\n\n return true;\n }\n\n normalizeOps(ops: CRUDOp[]): Exclude<CRUDOp, UpsertOp>[] {\n return ops.map(op => {\n if (op.op === 'upsert') {\n const preMutationRow = this.#getPreMutationRow(op);\n if (preMutationRow) {\n return {\n op: 'update',\n tableName: op.tableName,\n primaryKey: op.primaryKey,\n value: op.value,\n };\n }\n return {\n op: 'insert',\n tableName: op.tableName,\n primaryKey: op.primaryKey,\n value: op.value,\n };\n }\n return op;\n });\n }\n\n validateTableNames(ops: CRUDOp[]): void {\n for (const op of ops) {\n if (!this.#tableSpecs.has(op.tableName)) {\n throw new Error(`Table '${op.tableName}' is not a valid table.`);\n }\n }\n }\n\n #canInsert(phase: Phase, authData: JWTPayload | undefined, op: InsertOp) {\n return this.#timedCanDo(phase, 'insert', authData, op);\n }\n\n #canUpdate(phase: Phase, authData: JWTPayload | undefined, op: UpdateOp) {\n return this.#timedCanDo(phase, 'update', authData, op);\n }\n\n #canDelete(phase: Phase, authData: JWTPayload | undefined, op: DeleteOp) {\n return this.#timedCanDo(phase, 'delete', authData, op);\n }\n\n /**\n * Gets schema-defined primary key and validates that operation contains required PK values.\n *\n * @returns Record where keys are column names and values are client-provided values\n * @throws Error if operation value is missing required primary key columns\n */\n #getPrimaryKey(\n tableName: string,\n opValue: Record<string, ReadonlyJSONValue | undefined>,\n ): Record<string, ReadonlyJSONValue> {\n const tableSpec = this.#tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(`Table ${tableName} not found`);\n }\n const columns = tableSpec.tableSpec.primaryKey;\n\n // Extract primary key values from operation value and validate they exist\n const values: Record<string, ReadonlyJSONValue> = {};\n for (const col of columns) {\n const val = opValue[col];\n if (val === undefined) {\n throw new Error(\n `Primary key column '${col}' is missing from operation value for table ${tableName}`,\n );\n }\n values[col] = val;\n }\n\n return values;\n }\n\n #getSource(tableName: string) {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n const tableSpec = this.#tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(`Table ${tableName} not found`);\n }\n const {columns, primaryKey} = tableSpec.tableSpec;\n assert(\n primaryKey.length,\n () => `Table ${tableName} must have a primary key`,\n );\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n this.#replica,\n tableName,\n Object.fromEntries(\n Object.entries(columns).map(([name, {dataType}]) => [\n name,\n mapLiteDataTypeToZqlSchemaValue(dataType),\n ]),\n ),\n [primaryKey[0], ...primaryKey.slice(1)],\n );\n this.#tables.set(tableName, source);\n\n return source;\n }\n\n async #timedCanDo<A extends keyof ActionOpMap>(\n phase: Phase,\n action: A,\n authData: JWTPayload | undefined,\n op: ActionOpMap[A],\n ) {\n const start = performance.now();\n try {\n const ret = await this.#canDo(phase, action, authData, op);\n return ret;\n } finally {\n this.#lc.info?.(\n 'action:',\n action,\n 'duration:',\n performance.now() - start,\n 'tableName:',\n op.tableName,\n 'primaryKey:',\n op.primaryKey,\n );\n }\n }\n\n /**\n * Evaluation order is from static to dynamic, broad to specific.\n * table -> column -> row -> cell.\n *\n * If any step fails, the entire operation is denied.\n *\n * That is, table rules supersede column rules, which supersede row rules,\n *\n * All steps must allow for the operation to be allowed.\n */\n async #canDo<A extends keyof ActionOpMap>(\n phase: Phase,\n action: A,\n authData: JWTPayload | undefined,\n op: ActionOpMap[A],\n ) {\n const rules = must(this.#loadedPermissions)?.permissions?.tables?.[\n op.tableName\n ];\n const rowPolicies = rules?.row;\n let rowQuery = newStaticQuery(this.#schema, op.tableName);\n\n const primaryKeyValues = this.#getPrimaryKey(op.tableName, op.value);\n\n for (const pk in primaryKeyValues) {\n rowQuery = rowQuery.where(pk, '=', primaryKeyValues[pk]);\n }\n\n let applicableRowPolicy: Policy | undefined;\n switch (action) {\n case 'insert':\n if (phase === 'postMutation') {\n applicableRowPolicy = rowPolicies?.insert;\n }\n break;\n case 'update':\n if (phase === 'preMutation') {\n applicableRowPolicy = rowPolicies?.update?.preMutation;\n } else if (phase === 'postMutation') {\n applicableRowPolicy = rowPolicies?.update?.postMutation;\n }\n break;\n case 'delete':\n if (phase === 'preMutation') {\n applicableRowPolicy = rowPolicies?.delete;\n }\n break;\n }\n\n const cellPolicies = rules?.cell;\n const applicableCellPolicies: Policy[] = [];\n if (cellPolicies) {\n for (const [column, policy] of Object.entries(cellPolicies)) {\n if (action === 'update' && op.value[column] === undefined) {\n // If the cell is not being updated, we do not need to check\n // the cell rules.\n continue;\n }\n switch (action) {\n case 'insert':\n if (policy.insert && phase === 'postMutation') {\n applicableCellPolicies.push(policy.insert);\n }\n break;\n case 'update':\n if (phase === 'preMutation' && policy.update?.preMutation) {\n applicableCellPolicies.push(policy.update.preMutation);\n }\n if (phase === 'postMutation' && policy.update?.postMutation) {\n applicableCellPolicies.push(policy.update.postMutation);\n }\n break;\n case 'delete':\n if (policy.delete && phase === 'preMutation') {\n applicableCellPolicies.push(policy.delete);\n }\n break;\n }\n }\n }\n\n if (\n !(await this.#passesPolicyGroup(\n applicableRowPolicy,\n applicableCellPolicies,\n authData,\n rowQuery,\n ))\n ) {\n this.#lc.warn?.(\n `Permission check failed for ${JSON.stringify(\n op,\n )}, action ${action}, phase ${phase}, authData: ${JSON.stringify(\n authData,\n )}, rowPolicies: ${JSON.stringify(\n applicableRowPolicy,\n )}, cellPolicies: ${JSON.stringify(applicableCellPolicies)}`,\n );\n return false;\n }\n\n return true;\n }\n\n #getPreMutationRow(op: UpsertOp | UpdateOp | DeleteOp) {\n const {value} = op;\n\n const primaryKeyValues = this.#getPrimaryKey(op.tableName, value);\n\n const spec = this.#tableSpecs.get(op.tableName);\n if (!spec) {\n throw new Error(`Table ${op.tableName} not found`);\n }\n\n const conditions: SQLQuery[] = [];\n const values: PrimaryKeyValue[] = [];\n for (const pk in primaryKeyValues) {\n conditions.push(sql`${sql.ident(pk)}=?`);\n values.push(v.parse(primaryKeyValues[pk], primaryKeyValueSchema));\n }\n\n const ret = this.#statementRunner.get(\n compile(\n sql`SELECT ${sql.join(\n Object.keys(spec.zqlSpec).map(c => sql.ident(c)),\n sql`,`,\n )} FROM ${sql.ident(op.tableName)} WHERE ${sql.join(\n conditions,\n sql` AND `,\n )}`,\n ),\n ...values,\n );\n if (ret === undefined) {\n return ret;\n }\n return fromSQLiteTypes(spec.zqlSpec, ret, op.tableName);\n }\n\n #requirePreMutationRow(op: UpdateOp | DeleteOp) {\n const ret = this.#getPreMutationRow(op);\n assert(\n ret !== undefined,\n () => `Pre-mutation row not found for ${JSON.stringify(op.value)}`,\n );\n return ret;\n }\n\n async #passesPolicyGroup(\n applicableRowPolicy: Policy | undefined,\n applicableCellPolicies: Policy[],\n authData: JWTPayload | undefined,\n rowQuery: Query<string, Schema>,\n ) {\n if (!(await this.#passesPolicy(applicableRowPolicy, authData, rowQuery))) {\n return false;\n }\n\n for (const policy of applicableCellPolicies) {\n if (!(await this.#passesPolicy(policy, authData, rowQuery))) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Defaults to *false* if the policy is empty. At least one rule has to pass\n * for the policy to pass.\n */\n #passesPolicy(\n policy: Policy | undefined,\n authData: JWTPayload | undefined,\n rowQuery: Query<string, Schema>,\n ): MaybePromise<boolean> {\n if (policy === undefined) {\n return false;\n }\n if (policy.length === 0) {\n return false;\n }\n let rowQueryAst = asQueryInternals(rowQuery).ast;\n rowQueryAst = bindStaticParameters(\n {\n ...rowQueryAst,\n where: updateWhere(rowQueryAst.where, policy),\n },\n {\n authData: authData as Record<string, JSONValue>,\n preMutationRow: undefined,\n },\n );\n\n // call the compiler directly\n // run the sql against upstream.\n // remove the collecting into json? just need to know if a row comes back.\n\n const input = buildPipeline(rowQueryAst, this.#builderDelegate, 'query-id');\n try {\n const res = input.fetch({});\n for (const _ of res) {\n // if any row is returned at all, the\n // rule passes.\n return true;\n }\n } finally {\n input.destroy();\n }\n\n // no rows returned by any rules? The policy fails.\n return false;\n }\n}\n\nfunction updateWhere(where: Condition | undefined, policy: Policy) {\n assert(where, 'A where condition must exist for RowQuery');\n\n return simplifyCondition({\n type: 'and',\n conditions: [\n where,\n {\n type: 'or',\n conditions: policy.map(([action, rule]) => {\n assert(action, 'action must be defined in policy');\n return rule;\n }),\n },\n ],\n });\n}\n\ntype ActionOpMap = {\n insert: InsertOp;\n update: UpdateOp;\n delete: DeleteOp;\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { LogContext } from '@rocicorp/logger';
|
|
2
1
|
import { type NetworkInterfaceInfo } from 'os';
|
|
2
|
+
import type { LogContext } from '@rocicorp/logger';
|
|
3
3
|
export declare const DEFAULT_PREFERRED_PREFIXES: readonly ["eth", "en"];
|
|
4
4
|
export declare function getHostIp(lc?: LogContext, preferredPrefixes?: readonly string[]): string;
|
|
5
5
|
export declare function getPreferredIp(interfaces: NodeJS.Dict<NetworkInterfaceInfo[]>, preferredPrefixes: readonly string[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/network.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,oBAAoB,EAAC,MAAM,IAAI,CAAC;AAChE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,0BAA0B,wBAG7B,CAAC;AAEX,wBAAgB,SAAS,CACvB,EAAE,CAAC,EAAE,UAAU,EACf,iBAAiB,GAAE,SAAS,MAAM,EAA+B,UAMlE;AAED,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,EAC/C,iBAAiB,EAAE,SAAS,MAAM,EAAE,UA2CrC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isIPv6, isPrivate, isReserved } from "is-in-subnet";
|
|
2
1
|
import { networkInterfaces } from "os";
|
|
2
|
+
import { isIPv6, isPrivate, isReserved } from "is-in-subnet";
|
|
3
3
|
//#region ../zero-cache/src/config/network.ts
|
|
4
4
|
var DEFAULT_PREFERRED_PREFIXES = ["eth", "en"];
|
|
5
5
|
function getHostIp(lc, preferredPrefixes = DEFAULT_PREFERRED_PREFIXES) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","names":[],"sources":["../../../../../zero-cache/src/config/network.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {isIPv6, isPrivate, isReserved} from 'is-in-subnet';\
|
|
1
|
+
{"version":3,"file":"network.js","names":[],"sources":["../../../../../zero-cache/src/config/network.ts"],"sourcesContent":["import {networkInterfaces, type NetworkInterfaceInfo} from 'os';\nimport type {LogContext} from '@rocicorp/logger';\nimport {isIPv6, isPrivate, isReserved} from 'is-in-subnet';\n\nexport const DEFAULT_PREFERRED_PREFIXES = [\n 'eth', // linux\n 'en', // macbooks\n] as const;\n\nexport function getHostIp(\n lc?: LogContext,\n preferredPrefixes: readonly string[] = DEFAULT_PREFERRED_PREFIXES,\n) {\n const interfaces = networkInterfaces();\n const preferred = getPreferredIp(interfaces, preferredPrefixes);\n lc?.info?.(`network interfaces`, {preferred, interfaces});\n return preferred;\n}\n\nexport function getPreferredIp(\n interfaces: NodeJS.Dict<NetworkInterfaceInfo[]>,\n preferredPrefixes: readonly string[],\n) {\n const rank = ({name}: {name: string}) => {\n for (let i = 0; i < preferredPrefixes.length; i++) {\n if (name.startsWith(preferredPrefixes[i])) {\n return i;\n }\n }\n return Number.MAX_SAFE_INTEGER;\n };\n\n const sorted = Object.entries(interfaces)\n .flatMap(([name, infos]) => (infos ?? []).map(info => ({...info, name})))\n .sort((a, b) => {\n const ap =\n (isIPv6(a.address) && isPrivate(a.address)) || isReserved(a.address);\n const bp =\n (isIPv6(b.address) && isPrivate(b.address)) || isReserved(b.address);\n if (ap !== bp) {\n // Avoid link-local, site-local, or otherwise private addresses\n return ap ? 1 : -1;\n }\n if (a.internal !== b.internal) {\n // Prefer non-internal addresses.\n return a.internal ? 1 : -1;\n }\n if (a.family !== b.family) {\n // Prefer IPv4.\n return a.family === 'IPv4' ? -1 : 1;\n }\n const rankA = rank(a);\n const rankB = rank(b);\n if (rankA !== rankB) {\n return rankA - rankB;\n }\n // arbitrary\n return a.address.localeCompare(b.address);\n });\n\n // Enclose IPv6 addresses in square brackets for use in a URL.\n const preferred =\n sorted[0].family === 'IPv4' ? sorted[0].address : `[${sorted[0].address}]`;\n return preferred;\n}\n"],"mappings":";;;AAIA,IAAa,6BAA6B,CACxC,OACA,KACD;AAED,SAAgB,UACd,IACA,oBAAuC,4BACvC;CACA,MAAM,aAAa,mBAAmB;CACtC,MAAM,YAAY,eAAe,YAAY,kBAAkB;AAC/D,KAAI,OAAO,sBAAsB;EAAC;EAAW;EAAW,CAAC;AACzD,QAAO;;AAGT,SAAgB,eACd,YACA,mBACA;CACA,MAAM,QAAQ,EAAC,WAA0B;AACvC,OAAK,IAAI,IAAI,GAAG,IAAI,kBAAkB,QAAQ,IAC5C,KAAI,KAAK,WAAW,kBAAkB,GAAG,CACvC,QAAO;AAGX,SAAO,OAAO;;CAGhB,MAAM,SAAS,OAAO,QAAQ,WAAW,CACtC,SAAS,CAAC,MAAM,YAAY,SAAS,EAAE,EAAE,KAAI,UAAS;EAAC,GAAG;EAAM;EAAK,EAAE,CAAC,CACxE,MAAM,GAAG,MAAM;EACd,MAAM,KACH,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,QAAQ,IAAK,WAAW,EAAE,QAAQ;AAGtE,MAAI,QADD,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,QAAQ,IAAK,WAAW,EAAE,QAAQ,EAGpE,QAAO,KAAK,IAAI;AAElB,MAAI,EAAE,aAAa,EAAE,SAEnB,QAAO,EAAE,WAAW,IAAI;AAE1B,MAAI,EAAE,WAAW,EAAE,OAEjB,QAAO,EAAE,WAAW,SAAS,KAAK;EAEpC,MAAM,QAAQ,KAAK,EAAE;EACrB,MAAM,QAAQ,KAAK,EAAE;AACrB,MAAI,UAAU,MACZ,QAAO,QAAQ;AAGjB,SAAO,EAAE,QAAQ,cAAc,EAAE,QAAQ;GACzC;AAKJ,QADE,OAAO,GAAG,WAAW,SAAS,OAAO,GAAG,UAAU,IAAI,OAAO,GAAG,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/normalize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,qEAAqE;AACrE,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,GAAG,EAAE;QACH,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,MAAM,IAAI,oBAAoB,CAexC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB,oBAAoB,CAyEtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.js","names":[],"sources":["../../../../../zero-cache/src/config/normalize.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"normalize.js","names":[],"sources":["../../../../../zero-cache/src/config/normalize.ts"],"sourcesContent":["import {availableParallelism} from 'node:os';\nimport type {LogContext} from '@rocicorp/logger';\nimport {nanoid} from 'nanoid';\nimport {assert, assertNotUndefined} from '../../../shared/src/asserts.ts';\nimport {getHostIp} from './network.ts';\nimport type {ZeroConfig} from './zero-config.ts';\n\n/** {@link ZeroConfig} with defaults set per option documentation. */\nexport type NormalizedZeroConfig = ZeroConfig & {\n taskID: string;\n changeStreamer: {\n port: number;\n address: string;\n };\n change: {\n db: string;\n };\n cvr: {\n db: string;\n };\n litestream: {\n port: number;\n };\n numSyncWorkers: number;\n};\n\nexport function isDevelopmentMode(): boolean {\n return process.env.NODE_ENV === 'development';\n}\n\nexport function assertNormalized(\n config: ZeroConfig,\n): asserts config is NormalizedZeroConfig {\n assert(config.taskID, 'missing --task-id');\n assert(config.changeStreamer.port, 'missing --change-streamer-port');\n assert(config.changeStreamer.address, 'missing --change-streamer-address');\n assert(config.litestream.port, 'missing --litestream-port');\n assert(config.change.db, 'missing --change-db');\n assert(config.cvr.db, 'missing --cvr-db');\n assertNotUndefined(config.numSyncWorkers, 'missing --num-sync-workers');\n\n if (!isDevelopmentMode()) {\n assert(\n config.adminPassword,\n 'missing --admin-password: required in production mode',\n );\n }\n}\n\n/**\n * Normalizes the parsed `config` by setting defaults from the environment\n * or from other options as documented. When defaults are applied, the\n * corresponding `env` variable is updated so that the settings are propagated\n * to spawned child workers. Child workers can then call\n * {@link assertNormalized} to verify that the expected defaults have been set.\n */\nexport function normalizeZeroConfig(\n lc: LogContext,\n config: ZeroConfig,\n env: NodeJS.ProcessEnv,\n defaultTaskID?: string,\n): NormalizedZeroConfig {\n if (!config.taskID) {\n const taskID = defaultTaskID ?? nanoid();\n config.taskID = taskID;\n env['ZERO_TASK_ID'] = taskID;\n }\n if (!config.changeStreamer.port) {\n const port = config.port + 1;\n config.changeStreamer.port = port;\n env['ZERO_CHANGE_STREAMER_PORT'] = String(port);\n }\n if (!config.litestream.port) {\n const port = config.port + 2;\n config.litestream.port = port;\n env['ZERO_LITESTREAM_PORT'] = String(port);\n }\n if (config.numSyncWorkers === undefined) {\n // Reserve 1 core for the replicator. The change-streamer is not CPU heavy.\n const numSyncers = Math.max(1, availableParallelism() - 1);\n config.numSyncWorkers = numSyncers;\n env['ZERO_NUM_SYNC_WORKERS'] = String(numSyncers);\n }\n\n const hostIP = getHostIp(\n lc,\n config.changeStreamer.discoveryInterfacePreferences,\n );\n if (!config.changeStreamer.address) {\n const {port} = config.changeStreamer;\n const address = `${hostIP}:${port}`;\n config.changeStreamer.address = address;\n env['ZERO_CHANGE_STREAMER_ADDRESS'] = address;\n }\n\n if (!config.change.db) {\n config.change.db = config.upstream.db;\n env['ZERO_CHANGE_DB'] = config.upstream.db;\n }\n\n if (!config.cvr.db) {\n config.cvr.db = config.upstream.db;\n env['ZERO_CVR_DB'] = config.upstream.db;\n }\n\n lc.info?.(`runtime env: taskID=${config.taskID}, hostIP=${hostIP}`);\n\n return {\n ...config,\n taskID: config.taskID,\n\n changeStreamer: {\n ...config.changeStreamer,\n port: config.changeStreamer.port,\n address: config.changeStreamer.address,\n },\n\n litestream: {\n ...config.litestream,\n port: config.litestream.port,\n },\n\n change: {\n ...config.change,\n db: config.change.db,\n },\n\n cvr: {\n ...config.cvr,\n db: config.cvr.db,\n },\n\n numSyncWorkers: config.numSyncWorkers,\n };\n}\n"],"mappings":";;;;;AA0BA,SAAgB,oBAA6B;AAC3C,QAAA,QAAA,IAAA,aAAgC;;AAGlC,SAAgB,iBACd,QACwC;AACxC,QAAO,OAAO,QAAQ,oBAAoB;AAC1C,QAAO,OAAO,eAAe,MAAM,iCAAiC;AACpE,QAAO,OAAO,eAAe,SAAS,oCAAoC;AAC1E,QAAO,OAAO,WAAW,MAAM,4BAA4B;AAC3D,QAAO,OAAO,OAAO,IAAI,sBAAsB;AAC/C,QAAO,OAAO,IAAI,IAAI,mBAAmB;AACzC,oBAAmB,OAAO,gBAAgB,6BAA6B;AAEvE,KAAI,CAAC,mBAAmB,CACtB,QACE,OAAO,eACP,wDACD;;;;;;;;;AAWL,SAAgB,oBACd,IACA,QACA,KACA,eACsB;AACtB,KAAI,CAAC,OAAO,QAAQ;EAClB,MAAM,SAAS,iBAAiB,QAAQ;AACxC,SAAO,SAAS;AAChB,MAAI,kBAAkB;;AAExB,KAAI,CAAC,OAAO,eAAe,MAAM;EAC/B,MAAM,OAAO,OAAO,OAAO;AAC3B,SAAO,eAAe,OAAO;AAC7B,MAAI,+BAA+B,OAAO,KAAK;;AAEjD,KAAI,CAAC,OAAO,WAAW,MAAM;EAC3B,MAAM,OAAO,OAAO,OAAO;AAC3B,SAAO,WAAW,OAAO;AACzB,MAAI,0BAA0B,OAAO,KAAK;;AAE5C,KAAI,OAAO,mBAAmB,KAAA,GAAW;EAEvC,MAAM,aAAa,KAAK,IAAI,GAAG,sBAAsB,GAAG,EAAE;AAC1D,SAAO,iBAAiB;AACxB,MAAI,2BAA2B,OAAO,WAAW;;CAGnD,MAAM,SAAS,UACb,IACA,OAAO,eAAe,8BACvB;AACD,KAAI,CAAC,OAAO,eAAe,SAAS;EAClC,MAAM,EAAC,SAAQ,OAAO;EACtB,MAAM,UAAU,GAAG,OAAO,GAAG;AAC7B,SAAO,eAAe,UAAU;AAChC,MAAI,kCAAkC;;AAGxC,KAAI,CAAC,OAAO,OAAO,IAAI;AACrB,SAAO,OAAO,KAAK,OAAO,SAAS;AACnC,MAAI,oBAAoB,OAAO,SAAS;;AAG1C,KAAI,CAAC,OAAO,IAAI,IAAI;AAClB,SAAO,IAAI,KAAK,OAAO,SAAS;AAChC,MAAI,iBAAiB,OAAO,SAAS;;AAGvC,IAAG,OAAO,uBAAuB,OAAO,OAAO,WAAW,SAAS;AAEnE,QAAO;EACL,GAAG;EACH,QAAQ,OAAO;EAEf,gBAAgB;GACd,GAAG,OAAO;GACV,MAAM,OAAO,eAAe;GAC5B,SAAS,OAAO,eAAe;GAChC;EAED,YAAY;GACV,GAAG,OAAO;GACV,MAAM,OAAO,WAAW;GACzB;EAED,QAAQ;GACN,GAAG,OAAO;GACV,IAAI,OAAO,OAAO;GACnB;EAED,KAAK;GACH,GAAG,OAAO;GACV,IAAI,OAAO,IAAI;GAChB;EAED,gBAAgB,OAAO;EACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zero-config.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/zero-config.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"zero-config.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/config/zero-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AAUnD,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAC,SAAS,EAAC,MAAM,kCAAkC,CAAC;AAEhE,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAE3C,eAAO,MAAM,UAAU;;;;;;;;;CA+CtB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;CAwBxB,CAAC;AAEF,QAAA,MAAM,cAAc;;;;;;;;;CAmBnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE3D,QAAA,MAAM,oBAAoB;;;;;;;;;CAczB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE5D,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DhB,CAAC;AAuGF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAEpD,+DAA+D;AAC/D,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,UAAU,EACV,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CACrD,CAAC;AAKF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;IAsDtB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGlB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAuLhB,kBAAkB;;;;;;QASlB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2WpB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAIpD,wBAAgB,aAAa,CAC3B,IAAI,GAAE,IAAI,CAAC,YAAY,EAAE,eAAe,CAAM,GAC7C,UAAU,CAaZ;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,GAAE,IAAI,CAAC,YAAY,EAAE,eAAe,CAAM,GAC7C,oBAAoB,CAItB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,GAAG,SAAS,GACpD,MAAM,CAER;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,eAAe,CAAC,EACnD,QAAQ,EAAE,MAAM,GAAG,SAAS,WAwC7B;AAYD,wBAAgB,kBAAkB,SAEjC"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { literalUnion, valita_exports } from "../../../shared/src/valita.js";
|
|
2
|
-
import { singleProcessMode } from "../types/processes.js";
|
|
3
|
-
import { DEFAULT_PREFERRED_PREFIXES } from "./network.js";
|
|
4
|
-
import { assertNormalized, isDevelopmentMode } from "./normalize.js";
|
|
5
2
|
import { logOptions } from "../../../otel/src/log-options.js";
|
|
6
3
|
import { flagToEnv, parseOptions } from "../../../shared/src/options.js";
|
|
7
4
|
import package_default from "../../../zero/package.js";
|
|
8
5
|
import { runtimeDebugFlags } from "../../../zql/src/builder/debug-delegate.js";
|
|
6
|
+
import { singleProcessMode } from "../types/processes.js";
|
|
9
7
|
import { ALLOWED_APP_ID_CHARACTERS, INVALID_APP_ID_MESSAGE } from "../types/shards.js";
|
|
8
|
+
import { DEFAULT_PREFERRED_PREFIXES } from "./network.js";
|
|
9
|
+
import { assertNormalized, isDevelopmentMode } from "./normalize.js";
|
|
10
10
|
import { timingSafeEqual } from "node:crypto";
|
|
11
11
|
//#region ../zero-cache/src/config/zero-config.ts
|
|
12
|
+
/**
|
|
13
|
+
* These types represent the _compiled_ config whereas `define-config` types represent the _source_ config.
|
|
14
|
+
*/
|
|
12
15
|
var ZERO_ENV_VAR_PREFIX = "ZERO_";
|
|
13
16
|
var appOptions = {
|
|
14
17
|
id: {
|
|
@@ -365,6 +368,16 @@ var zeroOptions = {
|
|
|
365
368
|
`This is used by the {bold change-streamer} for catching up`,
|
|
366
369
|
`{bold zero-cache} replication subscriptions.`
|
|
367
370
|
]
|
|
371
|
+
},
|
|
372
|
+
statementTimeoutMs: {
|
|
373
|
+
type: valita_exports.number().default(2e4),
|
|
374
|
+
desc: [
|
|
375
|
+
`Fail change-log transactions if a statement response from postgres is not received within`,
|
|
376
|
+
`the specified timeout. This differs from a postgres {bold statement_timeout} in that`,
|
|
377
|
+
`it is implemented to handle a pathological case in which Postgres does not return a`,
|
|
378
|
+
`response but otherwise believes the transaction to be idle.`
|
|
379
|
+
],
|
|
380
|
+
hidden: true
|
|
368
381
|
}
|
|
369
382
|
},
|
|
370
383
|
replica: replicaOptions,
|