@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.3
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/README.md +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +4 -4
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +22 -19
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/refresh.d.ts.map +1 -1
- package/out/replicache/src/persist/refresh.js +0 -8
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.d.ts +23 -0
- package/out/replicache/src/process-scheduler.d.ts.map +1 -1
- package/out/replicache/src/process-scheduler.js +50 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +8 -0
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +11 -2
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/shared/src/custom-key-map.d.ts +4 -4
- package/out/shared/src/custom-key-map.d.ts.map +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/falsy.d.ts +3 -0
- package/out/shared/src/falsy.d.ts.map +1 -0
- package/out/shared/src/iterables.d.ts +6 -8
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +13 -7
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/options.d.ts +1 -0
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +5 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/prisma.d.ts +2 -0
- package/out/zero/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero/src/adapters/prisma.js +6 -0
- package/out/zero/src/adapters/prisma.js.map +1 -0
- package/out/zero/src/pg.js +4 -7
- package/out/zero/src/react.js +3 -1
- package/out/zero/src/react.js.map +1 -1
- package/out/zero/src/server.js +5 -8
- package/out/zero/src/zero-cache-dev.js +7 -3
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.d.ts +3 -2
- package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +14 -8
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +6 -0
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +16 -3
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +54 -9
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +80 -20
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +3 -0
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +26 -0
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +9 -3
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration.js +9 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +4 -3
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +4 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +9 -3
- 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 +15 -5
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +10 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +11 -30
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.js +1 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/priority-op.d.ts +8 -0
- package/out/zero-cache/src/server/priority-op.d.ts.map +1 -0
- package/out/zero-cache/src/server/priority-op.js +29 -0
- package/out/zero-cache/src/server/priority-op.js.map +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +10 -10
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +1 -1
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +4 -7
- package/out/zero-cache/src/services/change-source/custom/change-source.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 +68 -13
- 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.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +7 -2
- 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.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +7 -4
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +125 -180
- 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 +1 -10
- 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 +26 -12
- 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 +36 -90
- 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 +51 -14
- 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.d.ts +31 -36
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +25 -17
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +2 -4
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +158 -53
- 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 +55 -10
- 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 +210 -72
- 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.js +4 -2
- package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js +20 -4
- package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +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 +6 -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 +71 -25
- 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 +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +6 -5
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +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 +17 -6
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +2 -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 +14 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.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 -0
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config.yml +1 -0
- package/out/zero-cache/src/services/mutagen/error.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/error.js +4 -1
- package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +10 -24
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +8 -6
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +130 -19
- package/out/zero-cache/src/services/mutagen/pusher.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 +24 -31
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +4 -4
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +38 -36
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.d.ts +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -0
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.js +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -0
- package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +3 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- 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 +1 -0
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -1
- 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 +65 -44
- 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 +0 -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 +23 -6
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +14 -22
- 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 +46 -67
- 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 +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 +22 -11
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +3 -11
- 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 +6 -4
- 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 +216 -243
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.d.ts.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js +4 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +8 -2
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/shards.js +1 -1
- package/out/zero-cache/src/types/shards.js.map +1 -1
- package/out/zero-cache/src/types/sql.d.ts +5 -0
- package/out/zero-cache/src/types/sql.d.ts.map +1 -1
- package/out/zero-cache/src/types/sql.js +5 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +2 -3
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +2 -5
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +15 -10
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +17 -10
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +8 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +33 -0
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +6 -3
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.js +1 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +15 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +11 -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/query-manager.d.ts +4 -0
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +7 -0
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +5 -5
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +53 -8
- 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-protocol/src/connect.d.ts +4 -0
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js +3 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +16 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +25 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +2 -0
- package/out/zero-protocol/src/up.d.ts.map +1 -1
- package/out/zero-react/src/mod.d.ts +3 -1
- package/out/zero-react/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/paging-reducer.d.ts +61 -0
- package/out/zero-react/src/paging-reducer.d.ts.map +1 -0
- package/out/zero-react/src/paging-reducer.js +77 -0
- package/out/zero-react/src/paging-reducer.js.map +1 -0
- package/out/zero-react/src/use-query.d.ts +11 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +13 -11
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/use-rows.d.ts +39 -0
- package/out/zero-react/src/use-rows.d.ts.map +1 -0
- package/out/zero-react/src/use-rows.js +130 -0
- package/out/zero-react/src/use-rows.js.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts +122 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.js +342 -0
- package/out/zero-react/src/use-zero-virtualizer.js.map +1 -0
- package/out/zero-react/src/zero-provider.js +1 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-server/src/adapters/drizzle.d.ts +18 -18
- package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js +8 -22
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/pg.d.ts +19 -13
- package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts +19 -13
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.d.ts +66 -0
- package/out/zero-server/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero-server/src/adapters/prisma.js +63 -0
- package/out/zero-server/src/adapters/prisma.js.map +1 -0
- package/out/zero-server/src/custom.js +1 -15
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +9 -8
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +2 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +39 -4
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +4 -1
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +18 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/mod.d.ts +1 -1
- package/out/zero-solid/src/mod.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +10 -1
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.js +22 -5
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +1 -1
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +4 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +4 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +8 -2
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +12 -3
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +25 -2
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +24 -6
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +12 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/mutate/mutator.js +4 -4
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -5
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-registry.js +4 -4
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +1 -2
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +8 -4
- package/out/zero-cache/src/services/change-source/column-metadata.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/column-metadata.js.map +0 -1
- package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
- package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
- package/out/zero-cache/src/types/schema-versions.js +0 -28
- package/out/zero-cache/src/types/schema-versions.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-authorizer.js","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\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\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.#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 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 ).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 #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(primaryKey.length);\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);\n return rule;\n }),\n },\n ],\n });\n}\n\ntype ActionOpMap = {\n insert: InsertOp;\n update: UpdateOp;\n delete: DeleteOp;\n};\n"],"names":["v.parse"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"write-authorizer.js","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 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"],"names":["v.parse"],"mappings":"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"}
|
|
@@ -6,6 +6,8 @@ import { type Config, type ParseOptions } from '../../../shared/src/options.ts';
|
|
|
6
6
|
import * as v from '../../../shared/src/valita.ts';
|
|
7
7
|
import { type NormalizedZeroConfig } from './normalize.ts';
|
|
8
8
|
export type { LogConfig } from '../../../otel/src/log-options.ts';
|
|
9
|
+
export declare const ZERO_ENV_VAR_PREFIX = "ZERO_";
|
|
10
|
+
export declare const DEFAULT_BACK_PRESSURE_THRESHOLD = 100000;
|
|
9
11
|
export declare const appOptions: {
|
|
10
12
|
id: {
|
|
11
13
|
type: v.Type<string>;
|
|
@@ -36,10 +38,6 @@ declare const replicaOptions: {
|
|
|
36
38
|
type: v.Optional<number>;
|
|
37
39
|
desc: string[];
|
|
38
40
|
};
|
|
39
|
-
pageCacheSizeKib: {
|
|
40
|
-
type: v.Optional<number>;
|
|
41
|
-
desc: string[];
|
|
42
|
-
};
|
|
43
41
|
};
|
|
44
42
|
export type ReplicaOptions = Config<typeof replicaOptions>;
|
|
45
43
|
declare const perUserMutationLimit: {
|
|
@@ -69,6 +67,16 @@ declare const authOptions: {
|
|
|
69
67
|
desc: string[];
|
|
70
68
|
deprecated: string[];
|
|
71
69
|
};
|
|
70
|
+
issuer: {
|
|
71
|
+
type: v.Optional<string>;
|
|
72
|
+
desc: string[];
|
|
73
|
+
deprecated: string[];
|
|
74
|
+
};
|
|
75
|
+
audience: {
|
|
76
|
+
type: v.Optional<string>;
|
|
77
|
+
desc: string[];
|
|
78
|
+
deprecated: string[];
|
|
79
|
+
};
|
|
72
80
|
};
|
|
73
81
|
/** @deprecated */
|
|
74
82
|
export type AuthConfig = Config<typeof authOptions>;
|
|
@@ -109,6 +117,11 @@ export declare const zeroOptions: {
|
|
|
109
117
|
type: v.Type<boolean>;
|
|
110
118
|
desc: string[];
|
|
111
119
|
};
|
|
120
|
+
allowedClientHeaders: {
|
|
121
|
+
deprecated?: string[];
|
|
122
|
+
type: v.Optional<string[]>;
|
|
123
|
+
desc: string[];
|
|
124
|
+
};
|
|
112
125
|
};
|
|
113
126
|
mutate: {
|
|
114
127
|
url: {
|
|
@@ -126,6 +139,11 @@ export declare const zeroOptions: {
|
|
|
126
139
|
type: v.Type<boolean>;
|
|
127
140
|
desc: string[];
|
|
128
141
|
};
|
|
142
|
+
allowedClientHeaders: {
|
|
143
|
+
deprecated?: string[];
|
|
144
|
+
type: v.Optional<string[]>;
|
|
145
|
+
desc: string[];
|
|
146
|
+
};
|
|
129
147
|
};
|
|
130
148
|
/** @deprecated */
|
|
131
149
|
getQueries: {
|
|
@@ -144,6 +162,11 @@ export declare const zeroOptions: {
|
|
|
144
162
|
type: v.Type<boolean>;
|
|
145
163
|
desc: string[];
|
|
146
164
|
};
|
|
165
|
+
allowedClientHeaders: {
|
|
166
|
+
deprecated?: string[];
|
|
167
|
+
type: v.Optional<string[]>;
|
|
168
|
+
desc: string[];
|
|
169
|
+
};
|
|
147
170
|
};
|
|
148
171
|
query: {
|
|
149
172
|
url: {
|
|
@@ -161,6 +184,11 @@ export declare const zeroOptions: {
|
|
|
161
184
|
type: v.Type<boolean>;
|
|
162
185
|
desc: string[];
|
|
163
186
|
};
|
|
187
|
+
allowedClientHeaders: {
|
|
188
|
+
deprecated?: string[];
|
|
189
|
+
type: v.Optional<string[]>;
|
|
190
|
+
desc: string[];
|
|
191
|
+
};
|
|
164
192
|
};
|
|
165
193
|
cvr: {
|
|
166
194
|
db: {
|
|
@@ -219,10 +247,6 @@ export declare const zeroOptions: {
|
|
|
219
247
|
type: v.Optional<number>;
|
|
220
248
|
desc: string[];
|
|
221
249
|
};
|
|
222
|
-
pageCacheSizeKib: {
|
|
223
|
-
type: v.Optional<number>;
|
|
224
|
-
desc: string[];
|
|
225
|
-
};
|
|
226
250
|
};
|
|
227
251
|
log: {
|
|
228
252
|
level: v.Type<"error" | "debug" | "info" | "warn">;
|
|
@@ -281,6 +305,16 @@ export declare const zeroOptions: {
|
|
|
281
305
|
desc: string[];
|
|
282
306
|
deprecated: string[];
|
|
283
307
|
};
|
|
308
|
+
issuer: {
|
|
309
|
+
type: v.Optional<string>;
|
|
310
|
+
desc: string[];
|
|
311
|
+
deprecated: string[];
|
|
312
|
+
};
|
|
313
|
+
audience: {
|
|
314
|
+
type: v.Optional<string>;
|
|
315
|
+
desc: string[];
|
|
316
|
+
deprecated: string[];
|
|
317
|
+
};
|
|
284
318
|
};
|
|
285
319
|
port: {
|
|
286
320
|
type: v.Type<number>;
|
|
@@ -320,6 +354,10 @@ export declare const zeroOptions: {
|
|
|
320
354
|
type: v.Type<number>;
|
|
321
355
|
desc: string[];
|
|
322
356
|
};
|
|
357
|
+
backPressureThreshold: {
|
|
358
|
+
type: v.Type<number>;
|
|
359
|
+
desc: string[];
|
|
360
|
+
};
|
|
323
361
|
};
|
|
324
362
|
taskID: {
|
|
325
363
|
type: v.Optional<string>;
|
|
@@ -355,6 +393,10 @@ export declare const zeroOptions: {
|
|
|
355
393
|
type: v.Optional<string>;
|
|
356
394
|
desc: string[];
|
|
357
395
|
};
|
|
396
|
+
websocketMaxPayloadBytes: {
|
|
397
|
+
type: v.Type<number>;
|
|
398
|
+
desc: string[];
|
|
399
|
+
};
|
|
358
400
|
litestream: {
|
|
359
401
|
executable: {
|
|
360
402
|
type: v.Optional<string>;
|
|
@@ -371,6 +413,10 @@ export declare const zeroOptions: {
|
|
|
371
413
|
type: v.Optional<string>;
|
|
372
414
|
desc: string[];
|
|
373
415
|
};
|
|
416
|
+
endpoint: {
|
|
417
|
+
type: v.Optional<string>;
|
|
418
|
+
desc: string[];
|
|
419
|
+
};
|
|
374
420
|
port: {
|
|
375
421
|
type: v.Optional<number>;
|
|
376
422
|
desc: string[];
|
|
@@ -453,7 +499,6 @@ export declare const zeroOptions: {
|
|
|
453
499
|
};
|
|
454
500
|
};
|
|
455
501
|
export type ZeroConfig = Config<typeof zeroOptions>;
|
|
456
|
-
export declare const ZERO_ENV_VAR_PREFIX = "ZERO_";
|
|
457
502
|
export declare function getZeroConfig(opts?: Omit<ParseOptions, 'envNamePrefix'>): ZeroConfig;
|
|
458
503
|
/**
|
|
459
504
|
* Same as {@link getZeroConfig}, with an additional check that the
|
|
@@ -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;AASnD,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAC,SAAS,EAAC,MAAM,kCAAkC,CAAC;AAEhE,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAc3C,eAAO,MAAM,+BAA+B,SAAU,CAAC;AAEvD,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;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDhB,CAAC;AAuGF,kBAAkB;AAClB,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAKpD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;IAwCtB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGlB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuHlB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA6ChB,kBAAkB;;;;;;QASlB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiSpB,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,5 +1,6 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
1
2
|
import { logOptions } from "../../../otel/src/log-options.js";
|
|
2
|
-
import { parseOptions } from "../../../shared/src/options.js";
|
|
3
|
+
import { flagToEnv, parseOptions } from "../../../shared/src/options.js";
|
|
3
4
|
import { literalUnion } from "../../../shared/src/valita.js";
|
|
4
5
|
import packageJson from "../../../zero/package.json.js";
|
|
5
6
|
import { runtimeDebugFlags } from "../../../zql/src/builder/debug-delegate.js";
|
|
@@ -7,6 +8,8 @@ import { singleProcessMode } from "../types/processes.js";
|
|
|
7
8
|
import { ALLOWED_APP_ID_CHARACTERS, INVALID_APP_ID_MESSAGE } from "../types/shards.js";
|
|
8
9
|
import { assertNormalized, isDevelopmentMode } from "./normalize.js";
|
|
9
10
|
import { array, string, number, boolean } from "@badrap/valita";
|
|
11
|
+
const ZERO_ENV_VAR_PREFIX = "ZERO_";
|
|
12
|
+
const DEFAULT_BACK_PRESSURE_THRESHOLD = 1e5;
|
|
10
13
|
const appOptions = {
|
|
11
14
|
id: {
|
|
12
15
|
type: string().default("zero").assert((id) => ALLOWED_APP_ID_CHARACTERS.test(id), INVALID_APP_ID_MESSAGE),
|
|
@@ -89,18 +92,6 @@ const replicaOptions = {
|
|
|
89
92
|
`and requires double the size of the db in disk space. If unspecified, VACUUM`,
|
|
90
93
|
`operations are not performed.`
|
|
91
94
|
]
|
|
92
|
-
},
|
|
93
|
-
pageCacheSizeKib: {
|
|
94
|
-
type: number().optional(),
|
|
95
|
-
desc: [
|
|
96
|
-
`The SQLite page cache size in kibibytes (KiB) for view-syncer connections.`,
|
|
97
|
-
`The page cache stores recently accessed database pages in memory to reduce disk I/O.`,
|
|
98
|
-
`Larger cache sizes improve performance for workloads that fit in cache.`,
|
|
99
|
-
`If unspecified, SQLite's default (~2 MB) is used.`,
|
|
100
|
-
`Note that the effective memory use of this setting will be:`,
|
|
101
|
-
`2 * cache_size * num_cores as each connection to the replica gets its own cache`,
|
|
102
|
-
`and each core maintains 2 connections.`
|
|
103
|
-
]
|
|
104
95
|
}
|
|
105
96
|
};
|
|
106
97
|
const perUserMutationLimit = {
|
|
@@ -145,8 +136,29 @@ const authOptions = {
|
|
|
145
136
|
deprecated: [
|
|
146
137
|
`Use cookie-based authentication or an auth token instead - see https://zero.rocicorp.dev/docs/auth.`
|
|
147
138
|
]
|
|
139
|
+
},
|
|
140
|
+
issuer: {
|
|
141
|
+
type: string().optional(),
|
|
142
|
+
desc: [
|
|
143
|
+
`Expected issuer ({bold iss} claim) for JWT validation.`,
|
|
144
|
+
`If set, tokens with a different or missing issuer will be rejected.`
|
|
145
|
+
],
|
|
146
|
+
deprecated: [
|
|
147
|
+
`Use cookie-based authentication or an auth token instead - see https://zero.rocicorp.dev/docs/auth.`
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
audience: {
|
|
151
|
+
type: string().optional(),
|
|
152
|
+
desc: [
|
|
153
|
+
`Expected audience ({bold aud} claim) for JWT validation.`,
|
|
154
|
+
`If set, tokens with a different or missing audience will be rejected.`
|
|
155
|
+
],
|
|
156
|
+
deprecated: [
|
|
157
|
+
`Use cookie-based authentication or an auth token instead - see https://zero.rocicorp.dev/docs/auth.`
|
|
158
|
+
]
|
|
148
159
|
}
|
|
149
160
|
};
|
|
161
|
+
const makeDeprecationMessage = (flag) => `Use {bold ${flagToEnv(ZERO_ENV_VAR_PREFIX, flag)}} (or {bold --${flag}}) instead.`;
|
|
150
162
|
const makeMutatorQueryOptions = (replacement, suffix) => ({
|
|
151
163
|
url: {
|
|
152
164
|
type: array(string()).optional(),
|
|
@@ -192,14 +204,14 @@ const makeMutatorQueryOptions = (replacement, suffix) => ({
|
|
|
192
204
|
``,
|
|
193
205
|
`For full URLPattern syntax, see: https://developer.mozilla.org/en-US/docs/Web/API/URLPattern`
|
|
194
206
|
],
|
|
195
|
-
...replacement ? { deprecated: [
|
|
207
|
+
...replacement ? { deprecated: [makeDeprecationMessage(`${replacement}-url`)] } : {}
|
|
196
208
|
},
|
|
197
209
|
apiKey: {
|
|
198
210
|
type: string().optional(),
|
|
199
211
|
desc: [
|
|
200
212
|
`An optional secret used to authorize zero-cache to call the API server handling writes.`
|
|
201
213
|
],
|
|
202
|
-
...replacement ? { deprecated: [
|
|
214
|
+
...replacement ? { deprecated: [makeDeprecationMessage(`${replacement}-api-key`)] } : {}
|
|
203
215
|
},
|
|
204
216
|
forwardCookies: {
|
|
205
217
|
type: boolean().default(false),
|
|
@@ -208,14 +220,29 @@ const makeMutatorQueryOptions = (replacement, suffix) => ({
|
|
|
208
220
|
`This is useful for passing authentication cookies to the API server.`,
|
|
209
221
|
`If false, cookies are not forwarded.`
|
|
210
222
|
],
|
|
211
|
-
...replacement ? { deprecated: [
|
|
223
|
+
...replacement ? { deprecated: [makeDeprecationMessage(`${replacement}-forward-cookies`)] } : {}
|
|
224
|
+
},
|
|
225
|
+
allowedClientHeaders: {
|
|
226
|
+
type: array(string()).optional(),
|
|
227
|
+
desc: [
|
|
228
|
+
`A list of header names that clients are allowed to set via custom headers.`,
|
|
229
|
+
`If specified, only headers in this list will be forwarded to the ${suffix === "push mutations" ? "push" : "query"} URL.`,
|
|
230
|
+
`Header names are case-insensitive.`,
|
|
231
|
+
`If not specified, no client-provided headers are forwarded (secure by default).`,
|
|
232
|
+
`Example: ZERO_${replacement ? replacement.toUpperCase() : suffix === "push mutations" ? "MUTATE" : "QUERY"}_ALLOWED_CLIENT_HEADERS=x-request-id,x-correlation-id`
|
|
233
|
+
],
|
|
234
|
+
...replacement ? {
|
|
235
|
+
deprecated: [
|
|
236
|
+
makeDeprecationMessage(`${replacement}-allowed-client-headers`)
|
|
237
|
+
]
|
|
238
|
+
} : {}
|
|
212
239
|
}
|
|
213
240
|
});
|
|
214
241
|
const mutateOptions = makeMutatorQueryOptions(void 0, "push mutations");
|
|
215
|
-
const pushOptions = makeMutatorQueryOptions("mutate
|
|
242
|
+
const pushOptions = makeMutatorQueryOptions("mutate", "push mutations");
|
|
216
243
|
const queryOptions = makeMutatorQueryOptions(void 0, "send synced queries");
|
|
217
244
|
const getQueriesOptions = makeMutatorQueryOptions(
|
|
218
|
-
"query
|
|
245
|
+
"query",
|
|
219
246
|
"send synced queries"
|
|
220
247
|
);
|
|
221
248
|
const zeroOptions = {
|
|
@@ -446,6 +473,16 @@ const zeroOptions = {
|
|
|
446
473
|
`is received during this interval, the delay will be canceled and the takeover will happen`,
|
|
447
474
|
`immediately, since the incoming request indicates that the task is registered as a target.`
|
|
448
475
|
]
|
|
476
|
+
},
|
|
477
|
+
backPressureThreshold: {
|
|
478
|
+
type: number().default(DEFAULT_BACK_PRESSURE_THRESHOLD),
|
|
479
|
+
desc: [
|
|
480
|
+
`The maximum number of queued changes before back pressure is applied to the`,
|
|
481
|
+
`change source. When the queue exceeds this threshold, the change-streamer pauses`,
|
|
482
|
+
`consumption from upstream until the queue drops to 90% of the threshold.`,
|
|
483
|
+
``,
|
|
484
|
+
`Increasing this value may improve throughput at the cost of higher memory usage.`
|
|
485
|
+
]
|
|
449
486
|
}
|
|
450
487
|
},
|
|
451
488
|
taskID: {
|
|
@@ -516,6 +553,15 @@ const zeroOptions = {
|
|
|
516
553
|
"See https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback for available options."
|
|
517
554
|
]
|
|
518
555
|
},
|
|
556
|
+
websocketMaxPayloadBytes: {
|
|
557
|
+
type: number().default(10 * 1024 * 1024),
|
|
558
|
+
desc: [
|
|
559
|
+
"Maximum size of incoming WebSocket messages in bytes.",
|
|
560
|
+
"",
|
|
561
|
+
"Messages exceeding this limit are rejected before parsing.",
|
|
562
|
+
"Default: 10MB (10 * 1024 * 1024 = 10485760)"
|
|
563
|
+
]
|
|
564
|
+
},
|
|
519
565
|
litestream: {
|
|
520
566
|
executable: {
|
|
521
567
|
type: string().optional(),
|
|
@@ -544,6 +590,13 @@ const zeroOptions = {
|
|
|
544
590
|
`{bold view-syncers} receive this information from the {bold replication-manager}.`
|
|
545
591
|
]
|
|
546
592
|
},
|
|
593
|
+
endpoint: {
|
|
594
|
+
type: string().optional(),
|
|
595
|
+
desc: [
|
|
596
|
+
`The S3-compatible endpoint URL to use for the litestream backup. Only required for non-AWS services.`,
|
|
597
|
+
`The {bold replication-manager} and {bold view-syncers} must have the same endpoint.`
|
|
598
|
+
]
|
|
599
|
+
},
|
|
547
600
|
port: {
|
|
548
601
|
type: number().optional(),
|
|
549
602
|
desc: [
|
|
@@ -707,7 +760,6 @@ const zeroOptions = {
|
|
|
707
760
|
}
|
|
708
761
|
}
|
|
709
762
|
};
|
|
710
|
-
const ZERO_ENV_VAR_PREFIX = "ZERO_";
|
|
711
763
|
let loadedConfig;
|
|
712
764
|
function getZeroConfig(opts = {}) {
|
|
713
765
|
if (!loadedConfig || singleProcessMode()) {
|
|
@@ -743,7 +795,14 @@ function isAdminPasswordValid(lc, config, password) {
|
|
|
743
795
|
lc.warn?.("No admin password set; denying access");
|
|
744
796
|
return false;
|
|
745
797
|
}
|
|
746
|
-
|
|
798
|
+
const passwordBuffer = Buffer.from(password ?? "");
|
|
799
|
+
const configBuffer = Buffer.from(config.adminPassword);
|
|
800
|
+
if (passwordBuffer.length !== configBuffer.length) {
|
|
801
|
+
timingSafeEqual(configBuffer, configBuffer);
|
|
802
|
+
lc.warn?.("Invalid admin password");
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
if (!timingSafeEqual(passwordBuffer, configBuffer)) {
|
|
747
806
|
lc.warn?.("Invalid admin password");
|
|
748
807
|
return false;
|
|
749
808
|
}
|
|
@@ -758,6 +817,7 @@ function warnOnce(lc, msg) {
|
|
|
758
817
|
}
|
|
759
818
|
}
|
|
760
819
|
export {
|
|
820
|
+
DEFAULT_BACK_PRESSURE_THRESHOLD,
|
|
761
821
|
ZERO_ENV_VAR_PREFIX,
|
|
762
822
|
appOptions,
|
|
763
823
|
getNormalizedZeroConfig,
|