@syncular/server 0.0.6-96 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/auth-leases.d.ts +85 -0
- package/dist/auth-leases.d.ts.map +1 -0
- package/dist/auth-leases.js +368 -0
- package/dist/auth-leases.js.map +1 -0
- package/dist/better-sqlite3.d.ts +22 -0
- package/dist/better-sqlite3.d.ts.map +1 -0
- package/dist/better-sqlite3.js +16 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/blobs/access.d.ts +35 -0
- package/dist/blobs/access.d.ts.map +1 -0
- package/dist/blobs/access.js +149 -0
- package/dist/blobs/access.js.map +1 -0
- package/dist/blobs/adapters/database.d.ts +26 -9
- package/dist/blobs/adapters/database.d.ts.map +1 -1
- package/dist/blobs/adapters/database.js +68 -23
- package/dist/blobs/adapters/database.js.map +1 -1
- package/dist/blobs/index.d.ts +1 -0
- package/dist/blobs/index.d.ts.map +1 -1
- package/dist/blobs/index.js +5 -4
- package/dist/blobs/index.js.map +1 -1
- package/dist/blobs/manager.d.ts +69 -44
- package/dist/blobs/manager.d.ts.map +1 -1
- package/dist/blobs/manager.js +250 -65
- package/dist/blobs/manager.js.map +1 -1
- package/dist/blobs/migrate.d.ts.map +1 -1
- package/dist/blobs/migrate.js +16 -8
- package/dist/blobs/migrate.js.map +1 -1
- package/dist/blobs/types.d.ts +4 -0
- package/dist/blobs/types.d.ts.map +1 -1
- package/dist/bun-sqlite.d.ts +19 -0
- package/dist/bun-sqlite.d.ts.map +1 -0
- package/dist/bun-sqlite.js +19 -0
- package/dist/bun-sqlite.js.map +1 -0
- package/dist/clients.d.ts +1 -0
- package/dist/clients.d.ts.map +1 -1
- package/dist/clients.js.map +1 -1
- package/dist/cloudflare/durable-object.d.ts +93 -0
- package/dist/cloudflare/durable-object.d.ts.map +1 -0
- package/dist/cloudflare/durable-object.js +210 -0
- package/dist/cloudflare/durable-object.js.map +1 -0
- package/dist/cloudflare/index.d.ts +22 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +22 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare/r2.d.ts +180 -0
- package/dist/cloudflare/r2.d.ts.map +1 -0
- package/dist/cloudflare/r2.js +258 -0
- package/dist/cloudflare/r2.js.map +1 -0
- package/dist/cloudflare/scope-cache.d.ts +54 -0
- package/dist/cloudflare/scope-cache.d.ts.map +1 -0
- package/dist/cloudflare/scope-cache.js +223 -0
- package/dist/cloudflare/scope-cache.js.map +1 -0
- package/dist/cloudflare/sentry.d.ts +47 -0
- package/dist/cloudflare/sentry.d.ts.map +1 -0
- package/dist/cloudflare/sentry.js +163 -0
- package/dist/cloudflare/sentry.js.map +1 -0
- package/dist/cloudflare/worker.d.ts +46 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +63 -0
- package/dist/cloudflare/worker.js.map +1 -0
- package/dist/commit-integrity.d.ts +38 -0
- package/dist/commit-integrity.d.ts.map +1 -0
- package/dist/commit-integrity.js +260 -0
- package/dist/commit-integrity.js.map +1 -0
- package/dist/compaction.js.map +1 -1
- package/dist/crdt-yjs/index.d.ts +99 -0
- package/dist/crdt-yjs/index.d.ts.map +1 -0
- package/dist/crdt-yjs/index.js +629 -0
- package/dist/crdt-yjs/index.js.map +1 -0
- package/dist/d1.d.ts +13 -0
- package/dist/d1.d.ts.map +1 -0
- package/dist/d1.js +14 -0
- package/dist/d1.js.map +1 -0
- package/dist/dialect/base.d.ts +11 -1
- package/dist/dialect/base.d.ts.map +1 -1
- package/dist/dialect/base.js +43 -6
- package/dist/dialect/base.js.map +1 -1
- package/dist/dialect/helpers.d.ts +6 -0
- package/dist/dialect/helpers.d.ts.map +1 -1
- package/dist/dialect/helpers.js +24 -0
- package/dist/dialect/helpers.js.map +1 -1
- package/dist/dialect/index.js +3 -3
- package/dist/dialect/types.d.ts +40 -0
- package/dist/dialect/types.d.ts.map +1 -1
- package/dist/encrypted-crdt.d.ts +67 -0
- package/dist/encrypted-crdt.d.ts.map +1 -0
- package/dist/encrypted-crdt.js +426 -0
- package/dist/encrypted-crdt.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/filesystem/index.d.ts +44 -0
- package/dist/filesystem/index.d.ts.map +1 -0
- package/dist/filesystem/index.js +164 -0
- package/dist/filesystem/index.js.map +1 -0
- package/dist/handlers/collection.d.ts +11 -3
- package/dist/handlers/collection.d.ts.map +1 -1
- package/dist/handlers/collection.js +34 -56
- package/dist/handlers/collection.js.map +1 -1
- package/dist/handlers/create-handler.d.ts +31 -7
- package/dist/handlers/create-handler.d.ts.map +1 -1
- package/dist/handlers/create-handler.js +332 -115
- package/dist/handlers/create-handler.js.map +1 -1
- package/dist/handlers/index.js +3 -3
- package/dist/handlers/types.d.ts +86 -1
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/helpers/conflict.js.map +1 -1
- package/dist/helpers/emitted-change.js.map +1 -1
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/index.js +6 -4
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/paginate.js.map +1 -1
- package/dist/helpers/scope-authorization.d.ts +7 -0
- package/dist/helpers/scope-authorization.d.ts.map +1 -0
- package/dist/helpers/scope-authorization.js +19 -0
- package/dist/helpers/scope-authorization.js.map +1 -0
- package/dist/helpers/scope-commit-index.d.ts +12 -0
- package/dist/helpers/scope-commit-index.d.ts.map +1 -0
- package/dist/helpers/scope-commit-index.js +35 -0
- package/dist/helpers/scope-commit-index.js.map +1 -0
- package/dist/helpers/scope-strings.js.map +1 -1
- package/dist/hono/api-key-auth.d.ts +49 -0
- package/dist/hono/api-key-auth.d.ts.map +1 -0
- package/dist/hono/api-key-auth.js +108 -0
- package/dist/hono/api-key-auth.js.map +1 -0
- package/dist/hono/audit-redaction.d.ts +20 -0
- package/dist/hono/audit-redaction.d.ts.map +1 -0
- package/dist/hono/audit-redaction.js +85 -0
- package/dist/hono/audit-redaction.js.map +1 -0
- package/dist/hono/blobs.d.ts +75 -0
- package/dist/hono/blobs.d.ts.map +1 -0
- package/dist/hono/blobs.js +586 -0
- package/dist/hono/blobs.js.map +1 -0
- package/dist/hono/console/gateway.d.ts +42 -0
- package/dist/hono/console/gateway.d.ts.map +1 -0
- package/dist/hono/console/gateway.js +2158 -0
- package/dist/hono/console/gateway.js.map +1 -0
- package/dist/hono/console/live-auth.d.ts +7 -0
- package/dist/hono/console/live-auth.d.ts.map +1 -0
- package/dist/hono/console/live-auth.js +39 -0
- package/dist/hono/console/live-auth.js.map +1 -0
- package/dist/hono/console/route-descriptor.d.ts +6 -0
- package/dist/hono/console/route-descriptor.d.ts.map +1 -0
- package/dist/hono/console/route-descriptor.js +16 -0
- package/dist/hono/console/route-descriptor.js.map +1 -0
- package/dist/hono/console/routes/api-keys.d.ts +8 -0
- package/dist/hono/console/routes/api-keys.d.ts.map +1 -0
- package/dist/hono/console/routes/api-keys.js +575 -0
- package/dist/hono/console/routes/api-keys.js.map +1 -0
- package/dist/hono/console/routes/clients.d.ts +8 -0
- package/dist/hono/console/routes/clients.d.ts.map +1 -0
- package/dist/hono/console/routes/clients.js +322 -0
- package/dist/hono/console/routes/clients.js.map +1 -0
- package/dist/hono/console/routes/commits.d.ts +8 -0
- package/dist/hono/console/routes/commits.d.ts.map +1 -0
- package/dist/hono/console/routes/commits.js +882 -0
- package/dist/hono/console/routes/commits.js.map +1 -0
- package/dist/hono/console/routes/context.d.ts +188 -0
- package/dist/hono/console/routes/context.d.ts.map +1 -0
- package/dist/hono/console/routes/context.js +633 -0
- package/dist/hono/console/routes/context.js.map +1 -0
- package/dist/hono/console/routes/events.d.ts +8 -0
- package/dist/hono/console/routes/events.d.ts.map +1 -0
- package/dist/hono/console/routes/events.js +501 -0
- package/dist/hono/console/routes/events.js.map +1 -0
- package/dist/hono/console/routes/maintenance.d.ts +8 -0
- package/dist/hono/console/routes/maintenance.d.ts.map +1 -0
- package/dist/hono/console/routes/maintenance.js +341 -0
- package/dist/hono/console/routes/maintenance.js.map +1 -0
- package/dist/hono/console/routes/shared.d.ts +174 -0
- package/dist/hono/console/routes/shared.d.ts.map +1 -0
- package/dist/hono/console/routes/shared.js +583 -0
- package/dist/hono/console/routes/shared.js.map +1 -0
- package/dist/hono/console/routes/stats.d.ts +8 -0
- package/dist/hono/console/routes/stats.d.ts.map +1 -0
- package/dist/hono/console/routes/stats.js +295 -0
- package/dist/hono/console/routes/stats.js.map +1 -0
- package/dist/hono/console/routes/storage.d.ts +8 -0
- package/dist/hono/console/routes/storage.d.ts.map +1 -0
- package/dist/hono/console/routes/storage.js +121 -0
- package/dist/hono/console/routes/storage.js.map +1 -0
- package/dist/hono/console/routes.d.ts +36 -0
- package/dist/hono/console/routes.d.ts.map +1 -0
- package/dist/hono/console/routes.js +112 -0
- package/dist/hono/console/routes.js.map +1 -0
- package/dist/hono/console/schema-errors.d.ts +2 -0
- package/dist/hono/console/schema-errors.d.ts.map +1 -0
- package/dist/hono/console/schema-errors.js +17 -0
- package/dist/hono/console/schema-errors.js.map +1 -0
- package/dist/hono/console/schemas.d.ts +1515 -0
- package/dist/hono/console/schemas.d.ts.map +1 -0
- package/dist/hono/console/schemas.js +661 -0
- package/dist/hono/console/schemas.js.map +1 -0
- package/dist/hono/console/types.d.ts +213 -0
- package/dist/hono/console/types.d.ts.map +1 -0
- package/dist/hono/console/types.js +2 -0
- package/dist/hono/console/types.js.map +1 -0
- package/dist/hono/console/ui.d.ts +38 -0
- package/dist/hono/console/ui.d.ts.map +1 -0
- package/dist/hono/console/ui.js +43 -0
- package/dist/hono/console/ui.js.map +1 -0
- package/dist/hono/create-server.d.ts +71 -0
- package/dist/hono/create-server.d.ts.map +1 -0
- package/dist/hono/create-server.js +121 -0
- package/dist/hono/create-server.js.map +1 -0
- package/dist/hono/errors.d.ts +13 -0
- package/dist/hono/errors.d.ts.map +1 -0
- package/dist/hono/errors.js +21 -0
- package/dist/hono/errors.js.map +1 -0
- package/dist/hono/index.d.ts +20 -0
- package/dist/hono/index.d.ts.map +1 -0
- package/dist/hono/index.js +31 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/hono/openapi.d.ts +72 -0
- package/dist/hono/openapi.d.ts.map +1 -0
- package/dist/hono/openapi.js +99 -0
- package/dist/hono/openapi.js.map +1 -0
- package/dist/hono/proxy/connection-manager.d.ts +78 -0
- package/dist/hono/proxy/connection-manager.d.ts.map +1 -0
- package/dist/hono/proxy/connection-manager.js +251 -0
- package/dist/hono/proxy/connection-manager.js.map +1 -0
- package/dist/hono/proxy/index.d.ts +8 -0
- package/dist/hono/proxy/index.d.ts.map +1 -0
- package/dist/hono/proxy/index.js +8 -0
- package/dist/hono/proxy/index.js.map +1 -0
- package/dist/hono/proxy/routes.d.ts +86 -0
- package/dist/hono/proxy/routes.d.ts.map +1 -0
- package/dist/hono/proxy/routes.js +183 -0
- package/dist/hono/proxy/routes.js.map +1 -0
- package/dist/hono/rate-limit.d.ts +101 -0
- package/dist/hono/rate-limit.d.ts.map +1 -0
- package/dist/hono/rate-limit.js +184 -0
- package/dist/hono/rate-limit.js.map +1 -0
- package/dist/hono/realtime-sync-packs.d.ts +43 -0
- package/dist/hono/realtime-sync-packs.d.ts.map +1 -0
- package/dist/hono/realtime-sync-packs.js +219 -0
- package/dist/hono/realtime-sync-packs.js.map +1 -0
- package/dist/hono/routes/audit.d.ts +12 -0
- package/dist/hono/routes/audit.d.ts.map +1 -0
- package/dist/hono/routes/audit.js +385 -0
- package/dist/hono/routes/audit.js.map +1 -0
- package/dist/hono/routes/auth-leases.d.ts +8 -0
- package/dist/hono/routes/auth-leases.d.ts.map +1 -0
- package/dist/hono/routes/auth-leases.js +88 -0
- package/dist/hono/routes/auth-leases.js.map +1 -0
- package/dist/hono/routes/combined.d.ts +8 -0
- package/dist/hono/routes/combined.d.ts.map +1 -0
- package/dist/hono/routes/combined.js +392 -0
- package/dist/hono/routes/combined.js.map +1 -0
- package/dist/hono/routes/context.d.ts +314 -0
- package/dist/hono/routes/context.d.ts.map +1 -0
- package/dist/hono/routes/context.js +1147 -0
- package/dist/hono/routes/context.js.map +1 -0
- package/dist/hono/routes/health.d.ts +8 -0
- package/dist/hono/routes/health.d.ts.map +1 -0
- package/dist/hono/routes/health.js +16 -0
- package/dist/hono/routes/health.js.map +1 -0
- package/dist/hono/routes/realtime.d.ts +9 -0
- package/dist/hono/routes/realtime.d.ts.map +1 -0
- package/dist/hono/routes/realtime.js +626 -0
- package/dist/hono/routes/realtime.js.map +1 -0
- package/dist/hono/routes/shared.d.ts +689 -0
- package/dist/hono/routes/shared.d.ts.map +1 -0
- package/dist/hono/routes/shared.js +972 -0
- package/dist/hono/routes/shared.js.map +1 -0
- package/dist/hono/routes/snapshots.d.ts +10 -0
- package/dist/hono/routes/snapshots.d.ts.map +1 -0
- package/dist/hono/routes/snapshots.js +281 -0
- package/dist/hono/routes/snapshots.js.map +1 -0
- package/dist/hono/routes.d.ts +19 -0
- package/dist/hono/routes.d.ts.map +1 -0
- package/dist/hono/routes.js +37 -0
- package/dist/hono/routes.js.map +1 -0
- package/dist/hono/validation.d.ts +5 -0
- package/dist/hono/validation.d.ts.map +1 -0
- package/dist/hono/validation.js +47 -0
- package/dist/hono/validation.js.map +1 -0
- package/dist/hono/websocket-origin.d.ts +9 -0
- package/dist/hono/websocket-origin.d.ts.map +1 -0
- package/dist/hono/websocket-origin.js +96 -0
- package/dist/hono/websocket-origin.js.map +1 -0
- package/dist/hono/ws.d.ts +341 -0
- package/dist/hono/ws.d.ts.map +1 -0
- package/dist/hono/ws.js +711 -0
- package/dist/hono/ws.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -18
- package/dist/index.js.map +1 -1
- package/dist/libsql.d.ts +29 -0
- package/dist/libsql.d.ts.map +1 -0
- package/dist/libsql.js +25 -0
- package/dist/libsql.js.map +1 -0
- package/dist/migrate.js.map +1 -1
- package/dist/neon.d.ts +21 -0
- package/dist/neon.d.ts.map +1 -0
- package/dist/neon.js +22 -0
- package/dist/neon.js.map +1 -0
- package/dist/notify.d.ts +30 -0
- package/dist/notify.d.ts.map +1 -1
- package/dist/notify.js +160 -41
- package/dist/notify.js.map +1 -1
- package/dist/pglite.d.ts +37 -0
- package/dist/pglite.d.ts.map +1 -0
- package/dist/pglite.js +37 -0
- package/dist/pglite.js.map +1 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/types.d.ts +73 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +30 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/postgres/index.d.ts +68 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +924 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/proxy/collection.d.ts +0 -2
- package/dist/proxy/collection.d.ts.map +1 -1
- package/dist/proxy/collection.js +2 -17
- package/dist/proxy/collection.js.map +1 -1
- package/dist/proxy/handler.d.ts +1 -1
- package/dist/proxy/handler.d.ts.map +1 -1
- package/dist/proxy/handler.js +3 -4
- package/dist/proxy/handler.js.map +1 -1
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js +3 -3
- package/dist/proxy/index.js.map +1 -1
- package/dist/proxy/mutation-detector.js.map +1 -1
- package/dist/proxy/oplog.d.ts.map +1 -1
- package/dist/proxy/oplog.js +32 -8
- package/dist/proxy/oplog.js.map +1 -1
- package/dist/prune.d.ts +8 -1
- package/dist/prune.d.ts.map +1 -1
- package/dist/prune.js +68 -28
- package/dist/prune.js.map +1 -1
- package/dist/pull.d.ts +31 -0
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +1014 -474
- package/dist/pull.js.map +1 -1
- package/dist/push.d.ts +36 -2
- package/dist/push.d.ts.map +1 -1
- package/dist/push.js +603 -358
- package/dist/push.js.map +1 -1
- package/dist/realtime/in-memory.js.map +1 -1
- package/dist/realtime/index.d.ts +2 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +2 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/types.d.ts +12 -0
- package/dist/realtime/types.d.ts.map +1 -1
- package/dist/realtime/types.js +13 -1
- package/dist/realtime/types.js.map +1 -1
- package/dist/relay/client-role/forward-engine.d.ts +63 -0
- package/dist/relay/client-role/forward-engine.d.ts.map +1 -0
- package/dist/relay/client-role/forward-engine.js +267 -0
- package/dist/relay/client-role/forward-engine.js.map +1 -0
- package/dist/relay/client-role/index.d.ts +9 -0
- package/dist/relay/client-role/index.d.ts.map +1 -0
- package/dist/relay/client-role/index.js +9 -0
- package/dist/relay/client-role/index.js.map +1 -0
- package/dist/relay/client-role/pull-engine.d.ts +72 -0
- package/dist/relay/client-role/pull-engine.d.ts.map +1 -0
- package/dist/relay/client-role/pull-engine.js +249 -0
- package/dist/relay/client-role/pull-engine.js.map +1 -0
- package/dist/relay/client-role/sequence-mapper.d.ts +65 -0
- package/dist/relay/client-role/sequence-mapper.d.ts.map +1 -0
- package/dist/relay/client-role/sequence-mapper.js +161 -0
- package/dist/relay/client-role/sequence-mapper.js.map +1 -0
- package/dist/relay/evaluation/relay-paths.d.ts +41 -0
- package/dist/relay/evaluation/relay-paths.d.ts.map +1 -0
- package/dist/relay/evaluation/relay-paths.js +504 -0
- package/dist/relay/evaluation/relay-paths.js.map +1 -0
- package/dist/relay/evaluation/rust-boundary.d.ts +47 -0
- package/dist/relay/evaluation/rust-boundary.d.ts.map +1 -0
- package/dist/relay/evaluation/rust-boundary.js +220 -0
- package/dist/relay/evaluation/rust-boundary.js.map +1 -0
- package/dist/relay/index.d.ts +37 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/index.js +44 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/relay/migrate.d.ts +18 -0
- package/dist/relay/migrate.d.ts.map +1 -0
- package/dist/relay/migrate.js +99 -0
- package/dist/relay/migrate.js.map +1 -0
- package/dist/relay/mode-manager.d.ts +60 -0
- package/dist/relay/mode-manager.d.ts.map +1 -0
- package/dist/relay/mode-manager.js +114 -0
- package/dist/relay/mode-manager.js.map +1 -0
- package/dist/relay/realtime.d.ts +90 -0
- package/dist/relay/realtime.d.ts.map +1 -0
- package/dist/relay/realtime.js +147 -0
- package/dist/relay/realtime.js.map +1 -0
- package/dist/relay/relay.d.ts +190 -0
- package/dist/relay/relay.d.ts.map +1 -0
- package/dist/relay/relay.js +320 -0
- package/dist/relay/relay.js.map +1 -0
- package/dist/relay/schema.d.ts +158 -0
- package/dist/relay/schema.d.ts.map +1 -0
- package/dist/relay/schema.js +7 -0
- package/dist/relay/schema.js.map +1 -0
- package/dist/relay/server-role/index.d.ts +56 -0
- package/dist/relay/server-role/index.d.ts.map +1 -0
- package/dist/relay/server-role/index.js +193 -0
- package/dist/relay/server-role/index.js.map +1 -0
- package/dist/relay/server-role/pull.d.ts +27 -0
- package/dist/relay/server-role/pull.d.ts.map +1 -0
- package/dist/relay/server-role/pull.js +24 -0
- package/dist/relay/server-role/pull.js.map +1 -0
- package/dist/relay/server-role/push.d.ts +29 -0
- package/dist/relay/server-role/push.d.ts.map +1 -0
- package/dist/relay/server-role/push.js +122 -0
- package/dist/relay/server-role/push.js.map +1 -0
- package/dist/s3/index.d.ts +83 -0
- package/dist/s3/index.d.ts.map +1 -0
- package/dist/s3/index.js +223 -0
- package/dist/s3/index.js.map +1 -0
- package/dist/schema.d.ts +137 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -0
- package/dist/schema.js.map +1 -1
- package/dist/service-worker/index.d.ts +114 -0
- package/dist/service-worker/index.d.ts.map +1 -0
- package/dist/service-worker/index.js +487 -0
- package/dist/service-worker/index.js.map +1 -0
- package/dist/snapshot-artifacts/sqlite-bun.d.ts +15 -0
- package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +1 -0
- package/dist/snapshot-artifacts/sqlite-bun.js +128 -0
- package/dist/snapshot-artifacts/sqlite-bun.js.map +1 -0
- package/dist/snapshot-artifacts.d.ts +206 -0
- package/dist/snapshot-artifacts.d.ts.map +1 -0
- package/dist/snapshot-artifacts.js +545 -0
- package/dist/snapshot-artifacts.js.map +1 -0
- package/dist/snapshot-chunks/db-metadata.d.ts +18 -0
- package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
- package/dist/snapshot-chunks/db-metadata.js +91 -63
- package/dist/snapshot-chunks/db-metadata.js.map +1 -1
- package/dist/snapshot-chunks/index.js +2 -2
- package/dist/snapshot-chunks/types.d.ts +2 -0
- package/dist/snapshot-chunks/types.d.ts.map +1 -1
- package/dist/snapshot-chunks.d.ts +33 -3
- package/dist/snapshot-chunks.d.ts.map +1 -1
- package/dist/snapshot-chunks.js +136 -55
- package/dist/snapshot-chunks.js.map +1 -1
- package/dist/sqlite/index.d.ts +53 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +795 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite3.d.ts +22 -0
- package/dist/sqlite3.d.ts.map +1 -0
- package/dist/sqlite3.js +99 -0
- package/dist/sqlite3.js.map +1 -0
- package/dist/stats.d.ts +8 -0
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +45 -13
- package/dist/stats.js.map +1 -1
- package/dist/subscriptions/cache.d.ts +3 -0
- package/dist/subscriptions/cache.d.ts.map +1 -1
- package/dist/subscriptions/cache.js +44 -0
- package/dist/subscriptions/cache.js.map +1 -1
- package/dist/subscriptions/index.js +2 -2
- package/dist/subscriptions/resolve.d.ts +3 -1
- package/dist/subscriptions/resolve.d.ts.map +1 -1
- package/dist/subscriptions/resolve.js +91 -52
- package/dist/subscriptions/resolve.js.map +1 -1
- package/dist/sync.d.ts +3 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +9 -5
- package/dist/sync.js.map +1 -1
- package/package.json +297 -8
- package/src/auth-leases.ts +649 -0
- package/src/better-sqlite3.ts +35 -0
- package/src/blobs/access.ts +244 -0
- package/src/blobs/adapters/database.ts +125 -43
- package/src/blobs/index.ts +1 -0
- package/src/blobs/manager.ts +366 -65
- package/src/blobs/migrate.ts +16 -8
- package/src/blobs/types.ts +4 -0
- package/src/bun-sqlite-ambient.d.ts +19 -0
- package/src/bun-sqlite.ts +27 -0
- package/src/clients.ts +1 -0
- package/src/cloudflare/durable-object.ts +289 -0
- package/src/cloudflare/index.ts +22 -0
- package/src/cloudflare/r2.ts +526 -0
- package/src/cloudflare/scope-cache.ts +341 -0
- package/src/cloudflare/sentry.ts +230 -0
- package/src/cloudflare/worker.ts +77 -0
- package/src/commit-integrity.ts +371 -0
- package/src/crdt-yjs/index.ts +931 -0
- package/src/d1.ts +16 -0
- package/src/dialect/base.ts +71 -5
- package/src/dialect/helpers.ts +31 -0
- package/src/dialect/types.ts +47 -0
- package/src/encrypted-crdt.ts +786 -0
- package/src/errors.ts +22 -0
- package/src/filesystem/index.ts +262 -0
- package/src/handlers/collection.ts +78 -78
- package/src/handlers/create-handler.ts +540 -147
- package/src/handlers/types.ts +116 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/scope-authorization.ts +27 -0
- package/src/helpers/scope-commit-index.ts +52 -0
- package/src/hono/api-key-auth.ts +177 -0
- package/src/hono/audit-redaction.ts +135 -0
- package/src/hono/blobs.ts +851 -0
- package/src/hono/console/gateway.ts +3046 -0
- package/src/hono/console/live-auth.ts +46 -0
- package/src/hono/console/route-descriptor.ts +22 -0
- package/src/hono/console/routes/api-keys.ts +721 -0
- package/src/hono/console/routes/clients.ts +447 -0
- package/src/hono/console/routes/commits.ts +1137 -0
- package/src/hono/console/routes/context.ts +956 -0
- package/src/hono/console/routes/events.ts +669 -0
- package/src/hono/console/routes/maintenance.ts +461 -0
- package/src/hono/console/routes/shared.ts +816 -0
- package/src/hono/console/routes/stats.ts +392 -0
- package/src/hono/console/routes/storage.ts +159 -0
- package/src/hono/console/routes.ts +146 -0
- package/src/hono/console/schema-errors.ts +23 -0
- package/src/hono/console/schemas.ts +914 -0
- package/src/hono/console/types.ts +223 -0
- package/src/hono/console/ui.ts +100 -0
- package/src/hono/create-server.ts +230 -0
- package/src/hono/errors.ts +50 -0
- package/src/hono/index.ts +54 -0
- package/src/hono/openapi.ts +139 -0
- package/src/hono/proxy/connection-manager.ts +340 -0
- package/src/hono/proxy/index.ts +8 -0
- package/src/hono/proxy/routes.ts +272 -0
- package/src/hono/rate-limit.ts +319 -0
- package/src/hono/realtime-sync-packs.ts +354 -0
- package/src/hono/routes/audit.ts +499 -0
- package/src/hono/routes/auth-leases.ts +119 -0
- package/src/hono/routes/combined.ts +583 -0
- package/src/hono/routes/context.ts +1629 -0
- package/src/hono/routes/health.ts +26 -0
- package/src/hono/routes/realtime.ts +808 -0
- package/src/hono/routes/shared.ts +1626 -0
- package/src/hono/routes/snapshots.ts +345 -0
- package/src/hono/routes.ts +68 -0
- package/src/hono/validation.ts +81 -0
- package/src/hono/websocket-origin.ts +131 -0
- package/src/hono/ws.ts +1134 -0
- package/src/index.ts +6 -0
- package/src/libsql.ts +51 -0
- package/src/neon.ts +28 -0
- package/src/notify.ts +224 -44
- package/src/pglite.ts +68 -0
- package/src/plugins/index.ts +1 -0
- package/src/plugins/types.ts +144 -0
- package/src/postgres/index.ts +1291 -0
- package/src/proxy/collection.ts +5 -27
- package/src/proxy/handler.ts +2 -2
- package/src/proxy/index.ts +0 -2
- package/src/proxy/oplog.ts +41 -10
- package/src/prune.ts +137 -36
- package/src/pull.ts +1504 -591
- package/src/push.ts +881 -443
- package/src/realtime/index.ts +2 -0
- package/src/realtime/types.ts +35 -0
- package/src/relay/bun-types.d.ts +50 -0
- package/src/relay/client-role/forward-engine.ts +355 -0
- package/src/relay/client-role/index.ts +9 -0
- package/src/relay/client-role/pull-engine.ts +329 -0
- package/src/relay/client-role/sequence-mapper.ts +201 -0
- package/src/relay/evaluation/relay-paths.ts +699 -0
- package/src/relay/evaluation/rust-boundary.ts +464 -0
- package/src/relay/index.ts +50 -0
- package/src/relay/migrate.ts +113 -0
- package/src/relay/mode-manager.ts +142 -0
- package/src/relay/realtime.ts +207 -0
- package/src/relay/relay.ts +431 -0
- package/src/relay/schema.ts +171 -0
- package/src/relay/server-role/index.ts +338 -0
- package/src/relay/server-role/pull.ts +43 -0
- package/src/relay/server-role/push.ts +164 -0
- package/src/s3/index.ts +346 -0
- package/src/schema.ts +141 -1
- package/src/service-worker/index.ts +773 -0
- package/src/snapshot-artifacts/sqlite-bun.ts +168 -0
- package/src/snapshot-artifacts.ts +896 -0
- package/src/snapshot-chunks/db-metadata.ts +131 -72
- package/src/snapshot-chunks/types.ts +2 -0
- package/src/snapshot-chunks.ts +194 -70
- package/src/sqlite/index.ts +1064 -0
- package/src/sqlite3.ts +137 -0
- package/src/stats.ts +76 -13
- package/src/subscriptions/cache.ts +58 -0
- package/src/subscriptions/resolve.ts +99 -58
- package/src/sync.ts +16 -6
- package/src/blobs/adapters/database.test.ts +0 -67
- package/src/notify.test.ts +0 -520
- package/src/proxy/handler.test.ts +0 -126
- package/src/proxy/mutation-detector.test.ts +0 -71
- package/src/snapshot-chunks/db-metadata.test.ts +0 -172
- package/src/subscriptions/resolve.test.ts +0 -180
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BinarySnapshotColumn,
|
|
3
|
+
BinarySnapshotRowsEncoder,
|
|
4
|
+
ScopePattern,
|
|
5
|
+
ScopeValues,
|
|
6
|
+
StoredScopes,
|
|
7
|
+
SyncOperation,
|
|
8
|
+
SyncularErrorCode,
|
|
9
|
+
} from '@syncular/core';
|
|
10
|
+
import { BinarySnapshotTableWriter, collectScopeVars } from '@syncular/core';
|
|
11
|
+
import { sql } from 'kysely';
|
|
12
|
+
import { parseScopes } from './dialect/helpers';
|
|
13
|
+
import type { DbExecutor } from './dialect/types';
|
|
14
|
+
import type {
|
|
15
|
+
ApplyOperationResult,
|
|
16
|
+
EmittedChange,
|
|
17
|
+
ServerApplyOperationContext,
|
|
18
|
+
ServerSnapshotContext,
|
|
19
|
+
ServerTableHandler,
|
|
20
|
+
SyncServerAuth,
|
|
21
|
+
} from './handlers/types';
|
|
22
|
+
import { rowScopesAllowed } from './helpers/scope-authorization';
|
|
23
|
+
import type { SyncCoreDb } from './schema';
|
|
24
|
+
|
|
25
|
+
export const SYNC_CRDT_UPDATES_TABLE = 'sync_crdt_updates';
|
|
26
|
+
export const SYNC_CRDT_CHECKPOINTS_TABLE = 'sync_crdt_checkpoints';
|
|
27
|
+
|
|
28
|
+
type SystemTableName =
|
|
29
|
+
| typeof SYNC_CRDT_UPDATES_TABLE
|
|
30
|
+
| typeof SYNC_CRDT_CHECKPOINTS_TABLE;
|
|
31
|
+
|
|
32
|
+
type RequiredStringField =
|
|
33
|
+
| 'stream_id'
|
|
34
|
+
| 'app_table'
|
|
35
|
+
| 'row_id'
|
|
36
|
+
| 'field_name'
|
|
37
|
+
| 'key_id'
|
|
38
|
+
| 'ciphertext';
|
|
39
|
+
|
|
40
|
+
export interface EncryptedCrdtSystemHandlersOptions<
|
|
41
|
+
DB extends SyncCoreDb = SyncCoreDb,
|
|
42
|
+
Auth extends SyncServerAuth = SyncServerAuth,
|
|
43
|
+
> {
|
|
44
|
+
scopePatterns?: ScopePattern[];
|
|
45
|
+
resolveScopes: (ctx: {
|
|
46
|
+
db: DbExecutor<DB>;
|
|
47
|
+
actorId: string;
|
|
48
|
+
auth: Auth;
|
|
49
|
+
}) => Promise<ScopeValues> | ScopeValues;
|
|
50
|
+
authorizeUpdate?: (args: {
|
|
51
|
+
ctx: ServerApplyOperationContext<DB, Auth>;
|
|
52
|
+
row: EncryptedCrdtUpdateRow;
|
|
53
|
+
}) => Promise<boolean> | boolean;
|
|
54
|
+
authorizeCheckpoint?: (args: {
|
|
55
|
+
ctx: ServerApplyOperationContext<DB, Auth>;
|
|
56
|
+
row: EncryptedCrdtCheckpointRow;
|
|
57
|
+
}) => Promise<boolean> | boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface EncryptedCrdtUpdateRow {
|
|
61
|
+
partition_id: string;
|
|
62
|
+
stream_id: string;
|
|
63
|
+
app_table: string;
|
|
64
|
+
row_id: string;
|
|
65
|
+
field_name: string;
|
|
66
|
+
update_id: string;
|
|
67
|
+
actor_id: string | null;
|
|
68
|
+
client_id: string | null;
|
|
69
|
+
key_id: string;
|
|
70
|
+
ciphertext: string;
|
|
71
|
+
scopes: StoredScopes;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface EncryptedCrdtCheckpointRow {
|
|
75
|
+
partition_id: string;
|
|
76
|
+
stream_id: string;
|
|
77
|
+
app_table: string;
|
|
78
|
+
row_id: string;
|
|
79
|
+
field_name: string;
|
|
80
|
+
checkpoint_id: string;
|
|
81
|
+
covers_seq: number;
|
|
82
|
+
actor_id: string | null;
|
|
83
|
+
client_id: string | null;
|
|
84
|
+
key_id: string;
|
|
85
|
+
ciphertext: string;
|
|
86
|
+
scopes: StoredScopes;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface EncryptedCrdtPruneOptions {
|
|
90
|
+
partitionId?: string;
|
|
91
|
+
streamId?: string;
|
|
92
|
+
pruneCoveredUpdates?: boolean;
|
|
93
|
+
maxCheckpointsPerStream?: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface EncryptedCrdtPruneReport {
|
|
97
|
+
updatesDeleted: number;
|
|
98
|
+
checkpointsDeleted: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const CRDT_UPDATE_BINARY_COLUMNS = [
|
|
102
|
+
{ name: 'seq', type: 'integer' },
|
|
103
|
+
{ name: 'partition_id', type: 'string' },
|
|
104
|
+
{ name: 'stream_id', type: 'string' },
|
|
105
|
+
{ name: 'app_table', type: 'string' },
|
|
106
|
+
{ name: 'row_id', type: 'string' },
|
|
107
|
+
{ name: 'field_name', type: 'string' },
|
|
108
|
+
{ name: 'update_id', type: 'string' },
|
|
109
|
+
{ name: 'actor_id', type: 'string', nullable: true },
|
|
110
|
+
{ name: 'client_id', type: 'string', nullable: true },
|
|
111
|
+
{ name: 'key_id', type: 'string' },
|
|
112
|
+
{ name: 'ciphertext', type: 'string' },
|
|
113
|
+
{ name: 'scopes', type: 'json' },
|
|
114
|
+
] satisfies readonly BinarySnapshotColumn[];
|
|
115
|
+
|
|
116
|
+
const CRDT_CHECKPOINT_BINARY_COLUMNS = [
|
|
117
|
+
{ name: 'seq', type: 'integer' },
|
|
118
|
+
{ name: 'partition_id', type: 'string' },
|
|
119
|
+
{ name: 'stream_id', type: 'string' },
|
|
120
|
+
{ name: 'app_table', type: 'string' },
|
|
121
|
+
{ name: 'row_id', type: 'string' },
|
|
122
|
+
{ name: 'field_name', type: 'string' },
|
|
123
|
+
{ name: 'checkpoint_id', type: 'string' },
|
|
124
|
+
{ name: 'covers_seq', type: 'integer' },
|
|
125
|
+
{ name: 'actor_id', type: 'string', nullable: true },
|
|
126
|
+
{ name: 'client_id', type: 'string', nullable: true },
|
|
127
|
+
{ name: 'key_id', type: 'string' },
|
|
128
|
+
{ name: 'ciphertext', type: 'string' },
|
|
129
|
+
{ name: 'scopes', type: 'json' },
|
|
130
|
+
] satisfies readonly BinarySnapshotColumn[];
|
|
131
|
+
|
|
132
|
+
const CRDT_UPDATE_BINARY_ENCODER: BinarySnapshotRowsEncoder = (rows) =>
|
|
133
|
+
encodeEncryptedCrdtUpdateRows(rows);
|
|
134
|
+
|
|
135
|
+
const CRDT_CHECKPOINT_BINARY_ENCODER: BinarySnapshotRowsEncoder = (rows) =>
|
|
136
|
+
encodeEncryptedCrdtCheckpointRows(rows);
|
|
137
|
+
|
|
138
|
+
function createSystemRowScopeAuthorizer<
|
|
139
|
+
DB extends SyncCoreDb,
|
|
140
|
+
Auth extends SyncServerAuth,
|
|
141
|
+
>(options: EncryptedCrdtSystemHandlersOptions<DB, Auth>) {
|
|
142
|
+
const requiredScopeKeys = Array.from(
|
|
143
|
+
collectScopeVars(options.scopePatterns ?? [])
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return async (
|
|
147
|
+
ctx: ServerApplyOperationContext<DB, Auth>,
|
|
148
|
+
rowScopes: StoredScopes
|
|
149
|
+
): Promise<boolean> => {
|
|
150
|
+
if (requiredScopeKeys.length === 0) return true;
|
|
151
|
+
|
|
152
|
+
let allowedScopes: ScopeValues;
|
|
153
|
+
try {
|
|
154
|
+
allowedScopes = await options.resolveScopes({
|
|
155
|
+
db: ctx.db,
|
|
156
|
+
actorId: ctx.actorId,
|
|
157
|
+
auth: ctx.auth,
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return rowScopesAllowed({
|
|
164
|
+
rowScopes,
|
|
165
|
+
allowedScopes,
|
|
166
|
+
requiredScopeKeys,
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function encryptedCrdtStreamId(args: {
|
|
172
|
+
table: string;
|
|
173
|
+
rowId: string;
|
|
174
|
+
field: string;
|
|
175
|
+
}): string {
|
|
176
|
+
return `${escapeStreamPart(args.table)}:${escapeStreamPart(args.rowId)}:${escapeStreamPart(args.field)}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function createEncryptedCrdtSystemHandlers<
|
|
180
|
+
DB extends SyncCoreDb = SyncCoreDb,
|
|
181
|
+
Auth extends SyncServerAuth = SyncServerAuth,
|
|
182
|
+
>(
|
|
183
|
+
options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
|
|
184
|
+
): ServerTableHandler<DB, Auth>[] {
|
|
185
|
+
return [
|
|
186
|
+
createEncryptedCrdtUpdateHandler(options),
|
|
187
|
+
createEncryptedCrdtCheckpointHandler(options),
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function pruneEncryptedCrdtSystemRows<DB extends SyncCoreDb>(
|
|
192
|
+
db: DbExecutor<DB>,
|
|
193
|
+
options: EncryptedCrdtPruneOptions = {}
|
|
194
|
+
): Promise<EncryptedCrdtPruneReport> {
|
|
195
|
+
const partitionId = options.partitionId ?? 'default';
|
|
196
|
+
const streamFilter = options.streamId
|
|
197
|
+
? sql`and stream_id = ${options.streamId}`
|
|
198
|
+
: sql``;
|
|
199
|
+
const updateStreamFilter = options.streamId
|
|
200
|
+
? sql`and sync_crdt_updates.stream_id = ${options.streamId}`
|
|
201
|
+
: sql``;
|
|
202
|
+
const checkpointStreamFilter = options.streamId
|
|
203
|
+
? sql`and sync_crdt_checkpoints.stream_id = ${options.streamId}`
|
|
204
|
+
: sql``;
|
|
205
|
+
|
|
206
|
+
let updatesDeleted = 0;
|
|
207
|
+
if (options.pruneCoveredUpdates !== false) {
|
|
208
|
+
const deleted = await sql`
|
|
209
|
+
delete from sync_crdt_updates
|
|
210
|
+
where partition_id = ${partitionId}
|
|
211
|
+
${updateStreamFilter}
|
|
212
|
+
and exists (
|
|
213
|
+
select 1
|
|
214
|
+
from sync_crdt_checkpoints
|
|
215
|
+
where sync_crdt_checkpoints.partition_id = sync_crdt_updates.partition_id
|
|
216
|
+
and sync_crdt_checkpoints.stream_id = sync_crdt_updates.stream_id
|
|
217
|
+
and sync_crdt_checkpoints.key_id = sync_crdt_updates.key_id
|
|
218
|
+
and sync_crdt_checkpoints.covers_seq >= sync_crdt_updates.seq
|
|
219
|
+
)
|
|
220
|
+
`.execute(db);
|
|
221
|
+
updatesDeleted = affectedRows(deleted);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let checkpointsDeleted = 0;
|
|
225
|
+
if (options.maxCheckpointsPerStream != null) {
|
|
226
|
+
if (
|
|
227
|
+
!Number.isInteger(options.maxCheckpointsPerStream) ||
|
|
228
|
+
options.maxCheckpointsPerStream < 1
|
|
229
|
+
) {
|
|
230
|
+
throw new Error('maxCheckpointsPerStream must be an integer >= 1');
|
|
231
|
+
}
|
|
232
|
+
const deleted = await sql`
|
|
233
|
+
delete from sync_crdt_checkpoints
|
|
234
|
+
where checkpoint_id in (
|
|
235
|
+
select checkpoint_id
|
|
236
|
+
from (
|
|
237
|
+
select
|
|
238
|
+
checkpoint_id,
|
|
239
|
+
row_number() over (
|
|
240
|
+
partition by partition_id, stream_id, key_id
|
|
241
|
+
order by covers_seq desc, seq desc
|
|
242
|
+
) as checkpoint_rank
|
|
243
|
+
from sync_crdt_checkpoints
|
|
244
|
+
where partition_id = ${partitionId}
|
|
245
|
+
${streamFilter}
|
|
246
|
+
) ranked
|
|
247
|
+
where checkpoint_rank > ${options.maxCheckpointsPerStream}
|
|
248
|
+
)
|
|
249
|
+
and partition_id = ${partitionId}
|
|
250
|
+
${checkpointStreamFilter}
|
|
251
|
+
`.execute(db);
|
|
252
|
+
checkpointsDeleted = affectedRows(deleted);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return { updatesDeleted, checkpointsDeleted };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function createEncryptedCrdtUpdateHandler<
|
|
259
|
+
DB extends SyncCoreDb,
|
|
260
|
+
Auth extends SyncServerAuth,
|
|
261
|
+
>(
|
|
262
|
+
options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
|
|
263
|
+
): ServerTableHandler<DB, Auth> {
|
|
264
|
+
const authorizeRowScopes = createSystemRowScopeAuthorizer(options);
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
table: SYNC_CRDT_UPDATES_TABLE,
|
|
268
|
+
primaryKeyColumn: 'update_id',
|
|
269
|
+
snapshotBinaryColumns: CRDT_UPDATE_BINARY_COLUMNS,
|
|
270
|
+
snapshotBinaryEncoder: CRDT_UPDATE_BINARY_ENCODER,
|
|
271
|
+
scopePatterns: options.scopePatterns ?? [],
|
|
272
|
+
resolveScopes: async (ctx) => options.resolveScopes(ctx),
|
|
273
|
+
extractScopes: (row) => parseScopes(row.scopes),
|
|
274
|
+
snapshot: (ctx, _params) =>
|
|
275
|
+
snapshotSystemTable(ctx, SYNC_CRDT_UPDATES_TABLE, 'update_id'),
|
|
276
|
+
async applyOperation(ctx, op, opIndex) {
|
|
277
|
+
if (op.table !== SYNC_CRDT_UPDATES_TABLE) {
|
|
278
|
+
return errorResult(
|
|
279
|
+
opIndex,
|
|
280
|
+
`Unknown table: ${op.table}`,
|
|
281
|
+
'sync.unknown_table'
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
if (op.op !== 'upsert') {
|
|
285
|
+
return errorResult(
|
|
286
|
+
opIndex,
|
|
287
|
+
'Encrypted CRDT updates are append-only',
|
|
288
|
+
'sync.unsupported_operation'
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const payload = payloadRecord(op);
|
|
293
|
+
const row = updateRowFromPayload(ctx, op, payload);
|
|
294
|
+
if (!(await authorizeRowScopes(ctx, row.scopes))) {
|
|
295
|
+
return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
|
|
296
|
+
}
|
|
297
|
+
if (options.authorizeUpdate) {
|
|
298
|
+
const allowed = await options.authorizeUpdate({ ctx, row });
|
|
299
|
+
if (!allowed) {
|
|
300
|
+
return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const inserted = await insertSystemRow(
|
|
305
|
+
ctx.trx,
|
|
306
|
+
SYNC_CRDT_UPDATES_TABLE,
|
|
307
|
+
'update_id',
|
|
308
|
+
row.update_id,
|
|
309
|
+
{ ...row }
|
|
310
|
+
);
|
|
311
|
+
if (!inserted) {
|
|
312
|
+
return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return appliedResult(opIndex, SYNC_CRDT_UPDATES_TABLE, row.update_id, {
|
|
316
|
+
...row,
|
|
317
|
+
seq: inserted.seq,
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function createEncryptedCrdtCheckpointHandler<
|
|
324
|
+
DB extends SyncCoreDb,
|
|
325
|
+
Auth extends SyncServerAuth,
|
|
326
|
+
>(
|
|
327
|
+
options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
|
|
328
|
+
): ServerTableHandler<DB, Auth> {
|
|
329
|
+
const authorizeRowScopes = createSystemRowScopeAuthorizer(options);
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
table: SYNC_CRDT_CHECKPOINTS_TABLE,
|
|
333
|
+
primaryKeyColumn: 'checkpoint_id',
|
|
334
|
+
snapshotBinaryColumns: CRDT_CHECKPOINT_BINARY_COLUMNS,
|
|
335
|
+
snapshotBinaryEncoder: CRDT_CHECKPOINT_BINARY_ENCODER,
|
|
336
|
+
scopePatterns: options.scopePatterns ?? [],
|
|
337
|
+
resolveScopes: async (ctx) => options.resolveScopes(ctx),
|
|
338
|
+
extractScopes: (row) => parseScopes(row.scopes),
|
|
339
|
+
snapshot: (ctx, _params) =>
|
|
340
|
+
snapshotSystemTable(ctx, SYNC_CRDT_CHECKPOINTS_TABLE, 'checkpoint_id'),
|
|
341
|
+
async applyOperation(ctx, op, opIndex) {
|
|
342
|
+
if (op.table !== SYNC_CRDT_CHECKPOINTS_TABLE) {
|
|
343
|
+
return errorResult(
|
|
344
|
+
opIndex,
|
|
345
|
+
`Unknown table: ${op.table}`,
|
|
346
|
+
'sync.unknown_table'
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
if (op.op !== 'upsert') {
|
|
350
|
+
return errorResult(
|
|
351
|
+
opIndex,
|
|
352
|
+
'Encrypted CRDT checkpoints are append-only',
|
|
353
|
+
'sync.unsupported_operation'
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const payload = payloadRecord(op);
|
|
358
|
+
const row = checkpointRowFromPayload(ctx, op, payload);
|
|
359
|
+
if (!(await authorizeRowScopes(ctx, row.scopes))) {
|
|
360
|
+
return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
|
|
361
|
+
}
|
|
362
|
+
if (options.authorizeCheckpoint) {
|
|
363
|
+
const allowed = await options.authorizeCheckpoint({ ctx, row });
|
|
364
|
+
if (!allowed) {
|
|
365
|
+
return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const inserted = await insertSystemRow(
|
|
370
|
+
ctx.trx,
|
|
371
|
+
SYNC_CRDT_CHECKPOINTS_TABLE,
|
|
372
|
+
'checkpoint_id',
|
|
373
|
+
row.checkpoint_id,
|
|
374
|
+
{ ...row }
|
|
375
|
+
);
|
|
376
|
+
if (!inserted) {
|
|
377
|
+
return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return appliedResult(
|
|
381
|
+
opIndex,
|
|
382
|
+
SYNC_CRDT_CHECKPOINTS_TABLE,
|
|
383
|
+
row.checkpoint_id,
|
|
384
|
+
{ ...row, seq: inserted.seq }
|
|
385
|
+
);
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async function snapshotSystemTable<
|
|
391
|
+
DB extends SyncCoreDb,
|
|
392
|
+
Auth extends SyncServerAuth,
|
|
393
|
+
>(
|
|
394
|
+
ctx: ServerSnapshotContext<DB, string, Auth>,
|
|
395
|
+
table: SystemTableName,
|
|
396
|
+
cursorColumn: 'update_id' | 'checkpoint_id'
|
|
397
|
+
): Promise<{ rows: unknown[]; nextCursor: string | null }> {
|
|
398
|
+
const partitionId = ctx.auth.partitionId ?? 'default';
|
|
399
|
+
const cursor = ctx.cursor;
|
|
400
|
+
const rows = await sql<Record<string, unknown>>`
|
|
401
|
+
select *
|
|
402
|
+
from ${sql.table(table)}
|
|
403
|
+
where partition_id = ${partitionId}
|
|
404
|
+
and (${cursor} is null or ${sql.ref(cursorColumn)} > ${cursor})
|
|
405
|
+
order by ${sql.ref(cursorColumn)} asc
|
|
406
|
+
limit ${ctx.limit + 1}
|
|
407
|
+
`.execute(ctx.db);
|
|
408
|
+
|
|
409
|
+
const matched = rows.rows
|
|
410
|
+
.filter((row) => scopesMatch(parseScopes(row.scopes), ctx.scopeValues))
|
|
411
|
+
.slice(0, ctx.limit);
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
rows: matched.map(normalizeSystemRowForProtocol),
|
|
415
|
+
nextCursor:
|
|
416
|
+
matched.length === ctx.limit
|
|
417
|
+
? String(matched[matched.length - 1]?.[cursorColumn] ?? '')
|
|
418
|
+
: null,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async function insertSystemRow<DB extends SyncCoreDb>(
|
|
423
|
+
trx: DbExecutor<DB>,
|
|
424
|
+
table: SystemTableName,
|
|
425
|
+
identityColumn: 'update_id' | 'checkpoint_id',
|
|
426
|
+
identity: string,
|
|
427
|
+
row: Record<string, unknown>
|
|
428
|
+
): Promise<{ seq: number } | null> {
|
|
429
|
+
const insertable = {
|
|
430
|
+
...row,
|
|
431
|
+
scopes: JSON.stringify(scopesField(row.scopes)),
|
|
432
|
+
};
|
|
433
|
+
const result = await (trx.insertInto(table) as never as any)
|
|
434
|
+
.values(insertable)
|
|
435
|
+
.onConflict((oc: any) =>
|
|
436
|
+
oc.columns(['partition_id', identityColumn]).doNothing()
|
|
437
|
+
)
|
|
438
|
+
.returning(['seq', identityColumn])
|
|
439
|
+
.executeTakeFirst();
|
|
440
|
+
if (result) return { seq: Number(result.seq) };
|
|
441
|
+
|
|
442
|
+
const existing = await sql<{ identity: string }>`
|
|
443
|
+
select ${sql.ref(identityColumn)} as identity
|
|
444
|
+
from ${sql.table(table)}
|
|
445
|
+
where partition_id = ${String(row.partition_id)}
|
|
446
|
+
and ${sql.ref(identityColumn)} = ${identity}
|
|
447
|
+
limit 1
|
|
448
|
+
`.execute(trx);
|
|
449
|
+
if (existing.rows.length > 0) return null;
|
|
450
|
+
throw new Error(`Encrypted CRDT insert did not return ${identityColumn}`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function updateRowFromPayload<
|
|
454
|
+
DB extends SyncCoreDb,
|
|
455
|
+
Auth extends SyncServerAuth,
|
|
456
|
+
>(
|
|
457
|
+
ctx: ServerApplyOperationContext<DB, Auth>,
|
|
458
|
+
op: SyncOperation,
|
|
459
|
+
payload: Record<string, unknown>
|
|
460
|
+
): EncryptedCrdtUpdateRow {
|
|
461
|
+
return {
|
|
462
|
+
partition_id: ctx.auth.partitionId ?? 'default',
|
|
463
|
+
stream_id: stringField(payload, 'stream_id'),
|
|
464
|
+
app_table: stringField(payload, 'app_table'),
|
|
465
|
+
row_id: stringField(payload, 'row_id'),
|
|
466
|
+
field_name: stringField(payload, 'field_name'),
|
|
467
|
+
update_id: stringField(payload, 'update_id', op.row_id),
|
|
468
|
+
actor_id: ctx.actorId,
|
|
469
|
+
client_id: ctx.clientId,
|
|
470
|
+
key_id: stringField(payload, 'key_id'),
|
|
471
|
+
ciphertext: stringField(payload, 'ciphertext'),
|
|
472
|
+
scopes: scopesField(payload.scopes),
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function checkpointRowFromPayload<
|
|
477
|
+
DB extends SyncCoreDb,
|
|
478
|
+
Auth extends SyncServerAuth,
|
|
479
|
+
>(
|
|
480
|
+
ctx: ServerApplyOperationContext<DB, Auth>,
|
|
481
|
+
op: SyncOperation,
|
|
482
|
+
payload: Record<string, unknown>
|
|
483
|
+
): EncryptedCrdtCheckpointRow {
|
|
484
|
+
const coversSeq = Number(payload.covers_seq);
|
|
485
|
+
if (!Number.isInteger(coversSeq) || coversSeq < 0) {
|
|
486
|
+
throw new Error(
|
|
487
|
+
'Encrypted CRDT checkpoint covers_seq must be a non-negative integer'
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
partition_id: ctx.auth.partitionId ?? 'default',
|
|
492
|
+
stream_id: stringField(payload, 'stream_id'),
|
|
493
|
+
app_table: stringField(payload, 'app_table'),
|
|
494
|
+
row_id: stringField(payload, 'row_id'),
|
|
495
|
+
field_name: stringField(payload, 'field_name'),
|
|
496
|
+
checkpoint_id: stringField(payload, 'checkpoint_id', op.row_id),
|
|
497
|
+
covers_seq: coversSeq,
|
|
498
|
+
actor_id: ctx.actorId,
|
|
499
|
+
client_id: ctx.clientId,
|
|
500
|
+
key_id: stringField(payload, 'key_id'),
|
|
501
|
+
ciphertext: stringField(payload, 'ciphertext'),
|
|
502
|
+
scopes: scopesField(payload.scopes),
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function appliedResult(
|
|
507
|
+
opIndex: number,
|
|
508
|
+
table: SystemTableName,
|
|
509
|
+
rowId: string,
|
|
510
|
+
row: Record<string, unknown>
|
|
511
|
+
): ApplyOperationResult {
|
|
512
|
+
const emitted: EmittedChange = {
|
|
513
|
+
table,
|
|
514
|
+
row_id: rowId,
|
|
515
|
+
op: 'upsert',
|
|
516
|
+
row_json: normalizeSystemRowForProtocol(row),
|
|
517
|
+
row_version: numberOrNull(row.seq),
|
|
518
|
+
scopes: scopesField(row.scopes),
|
|
519
|
+
};
|
|
520
|
+
return {
|
|
521
|
+
result: { opIndex, status: 'applied' },
|
|
522
|
+
emittedChanges: [emitted],
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function errorResult(
|
|
527
|
+
opIndex: number,
|
|
528
|
+
error: string,
|
|
529
|
+
code: SyncularErrorCode
|
|
530
|
+
): ApplyOperationResult {
|
|
531
|
+
return {
|
|
532
|
+
result: { opIndex, status: 'error', error, code, retriable: false },
|
|
533
|
+
emittedChanges: [],
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function payloadRecord(op: SyncOperation): Record<string, unknown> {
|
|
538
|
+
if (
|
|
539
|
+
!op.payload ||
|
|
540
|
+
typeof op.payload !== 'object' ||
|
|
541
|
+
Array.isArray(op.payload)
|
|
542
|
+
) {
|
|
543
|
+
throw new Error('Encrypted CRDT operation payload must be an object');
|
|
544
|
+
}
|
|
545
|
+
return op.payload as Record<string, unknown>;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function stringField(
|
|
549
|
+
payload: Record<string, unknown>,
|
|
550
|
+
field: RequiredStringField | 'update_id' | 'checkpoint_id',
|
|
551
|
+
fallback?: string
|
|
552
|
+
): string {
|
|
553
|
+
const value = payload[field] ?? fallback;
|
|
554
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
`Encrypted CRDT payload field ${field} must be a non-empty string`
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
return value;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function scopesField(value: unknown): StoredScopes {
|
|
563
|
+
const parsed = parseScopes(value);
|
|
564
|
+
return parsed;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function scopesMatch(
|
|
568
|
+
stored: StoredScopes,
|
|
569
|
+
requested: Record<string, unknown>
|
|
570
|
+
): boolean {
|
|
571
|
+
for (const [key, value] of Object.entries(requested)) {
|
|
572
|
+
if (Array.isArray(value)) {
|
|
573
|
+
if (value.length === 0 || !value.includes(stored[key])) return false;
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
if (stored[key] !== value) return false;
|
|
577
|
+
}
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function normalizeSystemRowForProtocol(
|
|
582
|
+
row: Record<string, unknown>
|
|
583
|
+
): Record<string, unknown> {
|
|
584
|
+
return {
|
|
585
|
+
...row,
|
|
586
|
+
scopes: scopesField(row.scopes),
|
|
587
|
+
seq: numberOrNull(row.seq),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function numberOrNull(value: unknown): number | null {
|
|
592
|
+
const number = Number(value);
|
|
593
|
+
return Number.isFinite(number) ? number : null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function affectedRows(result: {
|
|
597
|
+
numAffectedRows?: bigint | number | string;
|
|
598
|
+
}): number {
|
|
599
|
+
return Number(result.numAffectedRows ?? 0);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function encodeEncryptedCrdtUpdateRows(rows: readonly unknown[]): Uint8Array {
|
|
603
|
+
const writer = new BinarySnapshotTableWriter(
|
|
604
|
+
SYNC_CRDT_UPDATES_TABLE,
|
|
605
|
+
CRDT_UPDATE_BINARY_COLUMNS,
|
|
606
|
+
rows.length
|
|
607
|
+
);
|
|
608
|
+
for (const value of rows) {
|
|
609
|
+
const row = recordRow(value);
|
|
610
|
+
writer.beginRow();
|
|
611
|
+
writer.writeInteger(
|
|
612
|
+
rowInteger(row, 'seq'),
|
|
613
|
+
'binary snapshot sync_crdt_updates.seq'
|
|
614
|
+
);
|
|
615
|
+
writer.writeString(
|
|
616
|
+
rowString(row, 'partition_id'),
|
|
617
|
+
'binary snapshot sync_crdt_updates.partition_id'
|
|
618
|
+
);
|
|
619
|
+
writer.writeString(
|
|
620
|
+
rowString(row, 'stream_id'),
|
|
621
|
+
'binary snapshot sync_crdt_updates.stream_id'
|
|
622
|
+
);
|
|
623
|
+
writer.writeString(
|
|
624
|
+
rowString(row, 'app_table'),
|
|
625
|
+
'binary snapshot sync_crdt_updates.app_table'
|
|
626
|
+
);
|
|
627
|
+
writer.writeString(
|
|
628
|
+
rowString(row, 'row_id'),
|
|
629
|
+
'binary snapshot sync_crdt_updates.row_id'
|
|
630
|
+
);
|
|
631
|
+
writer.writeString(
|
|
632
|
+
rowString(row, 'field_name'),
|
|
633
|
+
'binary snapshot sync_crdt_updates.field_name'
|
|
634
|
+
);
|
|
635
|
+
writer.writeString(
|
|
636
|
+
rowString(row, 'update_id'),
|
|
637
|
+
'binary snapshot sync_crdt_updates.update_id'
|
|
638
|
+
);
|
|
639
|
+
writeNullableString(
|
|
640
|
+
writer,
|
|
641
|
+
7,
|
|
642
|
+
row.actor_id,
|
|
643
|
+
'binary snapshot sync_crdt_updates.actor_id'
|
|
644
|
+
);
|
|
645
|
+
writeNullableString(
|
|
646
|
+
writer,
|
|
647
|
+
8,
|
|
648
|
+
row.client_id,
|
|
649
|
+
'binary snapshot sync_crdt_updates.client_id'
|
|
650
|
+
);
|
|
651
|
+
writer.writeString(
|
|
652
|
+
rowString(row, 'key_id'),
|
|
653
|
+
'binary snapshot sync_crdt_updates.key_id'
|
|
654
|
+
);
|
|
655
|
+
writer.writeString(
|
|
656
|
+
rowString(row, 'ciphertext'),
|
|
657
|
+
'binary snapshot sync_crdt_updates.ciphertext'
|
|
658
|
+
);
|
|
659
|
+
writer.writeJson(
|
|
660
|
+
scopesField(row.scopes),
|
|
661
|
+
'binary snapshot sync_crdt_updates.scopes'
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
return writer.finish();
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function encodeEncryptedCrdtCheckpointRows(
|
|
668
|
+
rows: readonly unknown[]
|
|
669
|
+
): Uint8Array {
|
|
670
|
+
const writer = new BinarySnapshotTableWriter(
|
|
671
|
+
SYNC_CRDT_CHECKPOINTS_TABLE,
|
|
672
|
+
CRDT_CHECKPOINT_BINARY_COLUMNS,
|
|
673
|
+
rows.length
|
|
674
|
+
);
|
|
675
|
+
for (const value of rows) {
|
|
676
|
+
const row = recordRow(value);
|
|
677
|
+
writer.beginRow();
|
|
678
|
+
writer.writeInteger(
|
|
679
|
+
rowInteger(row, 'seq'),
|
|
680
|
+
'binary snapshot sync_crdt_checkpoints.seq'
|
|
681
|
+
);
|
|
682
|
+
writer.writeString(
|
|
683
|
+
rowString(row, 'partition_id'),
|
|
684
|
+
'binary snapshot sync_crdt_checkpoints.partition_id'
|
|
685
|
+
);
|
|
686
|
+
writer.writeString(
|
|
687
|
+
rowString(row, 'stream_id'),
|
|
688
|
+
'binary snapshot sync_crdt_checkpoints.stream_id'
|
|
689
|
+
);
|
|
690
|
+
writer.writeString(
|
|
691
|
+
rowString(row, 'app_table'),
|
|
692
|
+
'binary snapshot sync_crdt_checkpoints.app_table'
|
|
693
|
+
);
|
|
694
|
+
writer.writeString(
|
|
695
|
+
rowString(row, 'row_id'),
|
|
696
|
+
'binary snapshot sync_crdt_checkpoints.row_id'
|
|
697
|
+
);
|
|
698
|
+
writer.writeString(
|
|
699
|
+
rowString(row, 'field_name'),
|
|
700
|
+
'binary snapshot sync_crdt_checkpoints.field_name'
|
|
701
|
+
);
|
|
702
|
+
writer.writeString(
|
|
703
|
+
rowString(row, 'checkpoint_id'),
|
|
704
|
+
'binary snapshot sync_crdt_checkpoints.checkpoint_id'
|
|
705
|
+
);
|
|
706
|
+
writer.writeInteger(
|
|
707
|
+
rowInteger(row, 'covers_seq'),
|
|
708
|
+
'binary snapshot sync_crdt_checkpoints.covers_seq'
|
|
709
|
+
);
|
|
710
|
+
writeNullableString(
|
|
711
|
+
writer,
|
|
712
|
+
8,
|
|
713
|
+
row.actor_id,
|
|
714
|
+
'binary snapshot sync_crdt_checkpoints.actor_id'
|
|
715
|
+
);
|
|
716
|
+
writeNullableString(
|
|
717
|
+
writer,
|
|
718
|
+
9,
|
|
719
|
+
row.client_id,
|
|
720
|
+
'binary snapshot sync_crdt_checkpoints.client_id'
|
|
721
|
+
);
|
|
722
|
+
writer.writeString(
|
|
723
|
+
rowString(row, 'key_id'),
|
|
724
|
+
'binary snapshot sync_crdt_checkpoints.key_id'
|
|
725
|
+
);
|
|
726
|
+
writer.writeString(
|
|
727
|
+
rowString(row, 'ciphertext'),
|
|
728
|
+
'binary snapshot sync_crdt_checkpoints.ciphertext'
|
|
729
|
+
);
|
|
730
|
+
writer.writeJson(
|
|
731
|
+
scopesField(row.scopes),
|
|
732
|
+
'binary snapshot sync_crdt_checkpoints.scopes'
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
return writer.finish();
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
function recordRow(value: unknown): Record<string, unknown> {
|
|
739
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
740
|
+
throw new Error('Encrypted CRDT binary rows must be objects');
|
|
741
|
+
}
|
|
742
|
+
return value as Record<string, unknown>;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function rowString(row: Record<string, unknown>, field: string): string {
|
|
746
|
+
const value = row[field];
|
|
747
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
748
|
+
throw new Error(
|
|
749
|
+
`Encrypted CRDT binary row field ${field} must be a non-empty string`
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
return value;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function rowInteger(
|
|
756
|
+
row: Record<string, unknown>,
|
|
757
|
+
field: string
|
|
758
|
+
): number | bigint {
|
|
759
|
+
const value = row[field];
|
|
760
|
+
if (typeof value === 'bigint') return value;
|
|
761
|
+
if (typeof value === 'number' && Number.isSafeInteger(value)) return value;
|
|
762
|
+
if (typeof value === 'string' && /^-?\d+$/.test(value)) return BigInt(value);
|
|
763
|
+
throw new Error(
|
|
764
|
+
`Encrypted CRDT binary row field ${field} must be an integer`
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function writeNullableString(
|
|
769
|
+
writer: BinarySnapshotTableWriter,
|
|
770
|
+
columnIndex: number,
|
|
771
|
+
value: unknown,
|
|
772
|
+
label: string
|
|
773
|
+
): void {
|
|
774
|
+
if (value == null) {
|
|
775
|
+
writer.writeNull(columnIndex);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (typeof value !== 'string') {
|
|
779
|
+
throw new Error(`${label} expected string`);
|
|
780
|
+
}
|
|
781
|
+
writer.writeString(value, label);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function escapeStreamPart(value: string): string {
|
|
785
|
+
return encodeURIComponent(value);
|
|
786
|
+
}
|