@syncular/server 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +773 -13
- package/dist/admin.d.ts +136 -0
- package/dist/admin.js +168 -0
- package/dist/blob-handlers.d.ts +69 -0
- package/dist/blob-handlers.js +245 -0
- package/dist/blob-store.d.ts +111 -0
- package/dist/blob-store.js +0 -0
- package/dist/content-encoding.d.ts +27 -0
- package/dist/content-encoding.js +69 -0
- package/dist/context.d.ts +151 -0
- package/dist/context.js +21 -0
- package/dist/crdt-merger.d.ts +28 -0
- package/dist/crdt-merger.js +11 -0
- package/dist/d1-storage.d.ts +50 -0
- package/dist/d1-storage.js +0 -0
- package/dist/errors.d.ts +35 -9
- package/dist/errors.js +220 -11
- package/dist/events-ring.d.ts +55 -0
- package/dist/events-ring.js +96 -0
- package/dist/events.d.ts +231 -0
- package/dist/events.js +22 -0
- package/dist/frame-bytes.d.ts +20 -0
- package/dist/frame-bytes.js +75 -0
- package/dist/handler.d.ts +9 -0
- package/dist/handler.js +490 -0
- package/dist/index.d.ts +42 -33
- package/dist/index.js +45 -27
- package/dist/lease-store.d.ts +50 -0
- package/dist/lease-store.js +0 -0
- package/dist/pg-executor-pglite.d.ts +27 -0
- package/dist/pg-executor-pglite.js +33 -0
- package/dist/pg-executor.d.ts +67 -0
- package/dist/pg-executor.js +56 -0
- package/dist/postgres-fanout.d.ts +83 -0
- package/dist/postgres-fanout.js +71 -0
- package/dist/postgres-storage.d.ts +69 -0
- package/dist/postgres-storage.js +766 -0
- package/dist/prune.d.ts +24 -39
- package/dist/prune.js +44 -146
- package/dist/pull.d.ts +42 -67
- package/dist/pull.js +387 -1187
- package/dist/push.d.ts +31 -66
- package/dist/push.js +406 -655
- package/dist/realtime.d.ts +197 -0
- package/dist/realtime.js +848 -0
- package/dist/relational-rows.d.ts +229 -0
- package/dist/relational-rows.js +514 -0
- package/dist/s3-blob-store.d.ts +142 -0
- package/dist/s3-blob-store.js +458 -0
- package/dist/s3-segment-store.d.ts +95 -0
- package/dist/s3-segment-store.js +380 -0
- package/dist/schema.d.ts +82 -286
- package/dist/schema.js +133 -9
- package/dist/scopes.d.ts +48 -0
- package/dist/scopes.js +98 -0
- package/dist/segment-download.d.ts +14 -0
- package/dist/segment-download.js +125 -0
- package/dist/segment-store.d.ts +81 -0
- package/dist/segment-store.js +63 -0
- package/dist/signed-url.d.ts +139 -0
- package/dist/signed-url.js +143 -0
- package/dist/sigv4.d.ts +97 -0
- package/dist/sigv4.js +161 -0
- package/dist/sqlite-blob-store.d.ts +22 -0
- package/dist/sqlite-blob-store.js +86 -0
- package/dist/sqlite-dialect.d.ts +101 -0
- package/dist/sqlite-dialect.js +250 -0
- package/dist/sqlite-image.d.ts +27 -0
- package/dist/sqlite-image.js +83 -0
- package/dist/sqlite-lease-store.d.ts +21 -0
- package/dist/sqlite-lease-store.js +94 -0
- package/dist/sqlite-segment-store.d.ts +25 -0
- package/dist/sqlite-segment-store.js +115 -0
- package/dist/sqlite-storage.d.ts +47 -0
- package/dist/sqlite-storage.js +477 -0
- package/dist/storage.d.ts +252 -0
- package/dist/storage.js +1 -0
- package/dist/validate.d.ts +83 -0
- package/dist/validate.js +44 -0
- package/package.json +17 -325
- package/src/admin.ts +312 -0
- package/src/blob-handlers.ts +340 -0
- package/src/blob-store.ts +0 -0
- package/src/content-encoding.ts +94 -0
- package/src/context.ts +176 -0
- package/src/crdt-merger.ts +33 -0
- package/src/d1-storage.ts +0 -0
- package/src/errors.ts +241 -19
- package/src/events-ring.ts +116 -0
- package/src/events.ts +291 -0
- package/src/frame-bytes.ts +94 -0
- package/src/handler.ts +678 -0
- package/src/index.ts +44 -27
- package/src/lease-store.ts +0 -0
- package/src/pg-executor-pglite.ts +63 -0
- package/src/pg-executor.ts +87 -0
- package/src/postgres-fanout.ts +143 -0
- package/src/postgres-storage.ts +1182 -0
- package/src/prune.ts +63 -289
- package/src/pull.ts +505 -1805
- package/src/push.ts +623 -1006
- package/src/realtime.ts +1082 -0
- package/src/relational-rows.ts +633 -0
- package/src/s3-blob-store.ts +616 -0
- package/src/s3-segment-store.ts +519 -0
- package/src/schema.ts +242 -281
- package/src/scopes.ts +127 -0
- package/src/segment-download.ts +169 -0
- package/src/segment-store.ts +154 -0
- package/src/signed-url.ts +308 -0
- package/src/sigv4.ts +267 -0
- package/src/sqlite-blob-store.ts +125 -0
- package/src/sqlite-dialect.ts +337 -0
- package/src/sqlite-image.ts +124 -0
- package/src/sqlite-lease-store.ts +144 -0
- package/src/sqlite-segment-store.ts +204 -0
- package/src/sqlite-storage.ts +792 -0
- package/src/storage.ts +316 -0
- package/src/validate.ts +123 -0
- package/dist/auth-leases.d.ts +0 -85
- package/dist/auth-leases.d.ts.map +0 -1
- package/dist/auth-leases.js +0 -368
- package/dist/auth-leases.js.map +0 -1
- package/dist/better-sqlite3.d.ts +0 -22
- package/dist/better-sqlite3.d.ts.map +0 -1
- package/dist/better-sqlite3.js +0 -16
- package/dist/better-sqlite3.js.map +0 -1
- package/dist/blobs/access.d.ts +0 -35
- package/dist/blobs/access.d.ts.map +0 -1
- package/dist/blobs/access.js +0 -149
- package/dist/blobs/access.js.map +0 -1
- package/dist/blobs/adapters/database.d.ts +0 -100
- package/dist/blobs/adapters/database.d.ts.map +0 -1
- package/dist/blobs/adapters/database.js +0 -247
- package/dist/blobs/adapters/database.js.map +0 -1
- package/dist/blobs/index.d.ts +0 -9
- package/dist/blobs/index.d.ts.map +0 -1
- package/dist/blobs/index.js +0 -9
- package/dist/blobs/index.js.map +0 -1
- package/dist/blobs/manager.d.ts +0 -220
- package/dist/blobs/manager.d.ts.map +0 -1
- package/dist/blobs/manager.js +0 -625
- package/dist/blobs/manager.js.map +0 -1
- package/dist/blobs/migrate.d.ts +0 -27
- package/dist/blobs/migrate.d.ts.map +0 -1
- package/dist/blobs/migrate.js +0 -127
- package/dist/blobs/migrate.js.map +0 -1
- package/dist/blobs/types.d.ts +0 -58
- package/dist/blobs/types.d.ts.map +0 -1
- package/dist/blobs/types.js +0 -5
- package/dist/blobs/types.js.map +0 -1
- package/dist/bun-sqlite.d.ts +0 -19
- package/dist/bun-sqlite.d.ts.map +0 -1
- package/dist/bun-sqlite.js +0 -19
- package/dist/bun-sqlite.js.map +0 -1
- package/dist/clients.d.ts +0 -15
- package/dist/clients.d.ts.map +0 -1
- package/dist/clients.js +0 -7
- package/dist/clients.js.map +0 -1
- package/dist/cloudflare/durable-object.d.ts +0 -93
- package/dist/cloudflare/durable-object.d.ts.map +0 -1
- package/dist/cloudflare/durable-object.js +0 -210
- package/dist/cloudflare/durable-object.js.map +0 -1
- package/dist/cloudflare/index.d.ts +0 -22
- package/dist/cloudflare/index.d.ts.map +0 -1
- package/dist/cloudflare/index.js +0 -22
- package/dist/cloudflare/index.js.map +0 -1
- package/dist/cloudflare/r2.d.ts +0 -180
- package/dist/cloudflare/r2.d.ts.map +0 -1
- package/dist/cloudflare/r2.js +0 -258
- package/dist/cloudflare/r2.js.map +0 -1
- package/dist/cloudflare/scope-cache.d.ts +0 -54
- package/dist/cloudflare/scope-cache.d.ts.map +0 -1
- package/dist/cloudflare/scope-cache.js +0 -223
- package/dist/cloudflare/scope-cache.js.map +0 -1
- package/dist/cloudflare/sentry.d.ts +0 -47
- package/dist/cloudflare/sentry.d.ts.map +0 -1
- package/dist/cloudflare/sentry.js +0 -163
- package/dist/cloudflare/sentry.js.map +0 -1
- package/dist/cloudflare/worker.d.ts +0 -46
- package/dist/cloudflare/worker.d.ts.map +0 -1
- package/dist/cloudflare/worker.js +0 -63
- package/dist/cloudflare/worker.js.map +0 -1
- package/dist/commit-integrity.d.ts +0 -38
- package/dist/commit-integrity.d.ts.map +0 -1
- package/dist/commit-integrity.js +0 -260
- package/dist/commit-integrity.js.map +0 -1
- package/dist/compaction.d.ts +0 -27
- package/dist/compaction.d.ts.map +0 -1
- package/dist/compaction.js +0 -49
- package/dist/compaction.js.map +0 -1
- package/dist/crdt-yjs/index.d.ts +0 -99
- package/dist/crdt-yjs/index.d.ts.map +0 -1
- package/dist/crdt-yjs/index.js +0 -629
- package/dist/crdt-yjs/index.js.map +0 -1
- package/dist/d1.d.ts +0 -13
- package/dist/d1.d.ts.map +0 -1
- package/dist/d1.js +0 -14
- package/dist/d1.js.map +0 -1
- package/dist/dialect/base.d.ts +0 -93
- package/dist/dialect/base.d.ts.map +0 -1
- package/dist/dialect/base.js +0 -181
- package/dist/dialect/base.js.map +0 -1
- package/dist/dialect/helpers.d.ts +0 -16
- package/dist/dialect/helpers.d.ts.map +0 -1
- package/dist/dialect/helpers.js +0 -83
- package/dist/dialect/helpers.js.map +0 -1
- package/dist/dialect/index.d.ts +0 -7
- package/dist/dialect/index.d.ts.map +0 -1
- package/dist/dialect/index.js +0 -7
- package/dist/dialect/index.js.map +0 -1
- package/dist/dialect/types.d.ts +0 -187
- package/dist/dialect/types.d.ts.map +0 -1
- package/dist/dialect/types.js +0 -8
- package/dist/dialect/types.js.map +0 -1
- package/dist/encrypted-crdt.d.ts +0 -67
- package/dist/encrypted-crdt.d.ts.map +0 -1
- package/dist/encrypted-crdt.js +0 -426
- package/dist/encrypted-crdt.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/filesystem/index.d.ts +0 -44
- package/dist/filesystem/index.d.ts.map +0 -1
- package/dist/filesystem/index.js +0 -164
- package/dist/filesystem/index.js.map +0 -1
- package/dist/handlers/collection.d.ts +0 -20
- package/dist/handlers/collection.d.ts.map +0 -1
- package/dist/handlers/collection.js +0 -42
- package/dist/handlers/collection.js.map +0 -1
- package/dist/handlers/create-handler.d.ts +0 -156
- package/dist/handlers/create-handler.d.ts.map +0 -1
- package/dist/handlers/create-handler.js +0 -626
- package/dist/handlers/create-handler.js.map +0 -1
- package/dist/handlers/index.d.ts +0 -4
- package/dist/handlers/index.d.ts.map +0 -1
- package/dist/handlers/index.js +0 -4
- package/dist/handlers/index.js.map +0 -1
- package/dist/handlers/types.d.ts +0 -295
- package/dist/handlers/types.d.ts.map +0 -1
- package/dist/handlers/types.js +0 -2
- package/dist/handlers/types.js.map +0 -1
- package/dist/helpers/conflict.d.ts +0 -52
- package/dist/helpers/conflict.d.ts.map +0 -1
- package/dist/helpers/conflict.js +0 -49
- package/dist/helpers/conflict.js.map +0 -1
- package/dist/helpers/emitted-change.d.ts +0 -56
- package/dist/helpers/emitted-change.d.ts.map +0 -1
- package/dist/helpers/emitted-change.js +0 -46
- package/dist/helpers/emitted-change.js.map +0 -1
- package/dist/helpers/index.d.ts +0 -12
- package/dist/helpers/index.d.ts.map +0 -1
- package/dist/helpers/index.js +0 -12
- package/dist/helpers/index.js.map +0 -1
- package/dist/helpers/paginate.d.ts +0 -49
- package/dist/helpers/paginate.d.ts.map +0 -1
- package/dist/helpers/paginate.js +0 -54
- package/dist/helpers/paginate.js.map +0 -1
- package/dist/helpers/scope-authorization.d.ts +0 -7
- package/dist/helpers/scope-authorization.d.ts.map +0 -1
- package/dist/helpers/scope-authorization.js +0 -19
- package/dist/helpers/scope-authorization.js.map +0 -1
- package/dist/helpers/scope-commit-index.d.ts +0 -12
- package/dist/helpers/scope-commit-index.d.ts.map +0 -1
- package/dist/helpers/scope-commit-index.js +0 -35
- package/dist/helpers/scope-commit-index.js.map +0 -1
- package/dist/helpers/scope-strings.d.ts +0 -74
- package/dist/helpers/scope-strings.d.ts.map +0 -1
- package/dist/helpers/scope-strings.js +0 -82
- package/dist/helpers/scope-strings.js.map +0 -1
- package/dist/hono/api-key-auth.d.ts +0 -49
- package/dist/hono/api-key-auth.d.ts.map +0 -1
- package/dist/hono/api-key-auth.js +0 -108
- package/dist/hono/api-key-auth.js.map +0 -1
- package/dist/hono/audit-redaction.d.ts +0 -20
- package/dist/hono/audit-redaction.d.ts.map +0 -1
- package/dist/hono/audit-redaction.js +0 -85
- package/dist/hono/audit-redaction.js.map +0 -1
- package/dist/hono/blobs.d.ts +0 -75
- package/dist/hono/blobs.d.ts.map +0 -1
- package/dist/hono/blobs.js +0 -586
- package/dist/hono/blobs.js.map +0 -1
- package/dist/hono/console/gateway.d.ts +0 -42
- package/dist/hono/console/gateway.d.ts.map +0 -1
- package/dist/hono/console/gateway.js +0 -2158
- package/dist/hono/console/gateway.js.map +0 -1
- package/dist/hono/console/live-auth.d.ts +0 -7
- package/dist/hono/console/live-auth.d.ts.map +0 -1
- package/dist/hono/console/live-auth.js +0 -39
- package/dist/hono/console/live-auth.js.map +0 -1
- package/dist/hono/console/route-descriptor.d.ts +0 -6
- package/dist/hono/console/route-descriptor.d.ts.map +0 -1
- package/dist/hono/console/route-descriptor.js +0 -16
- package/dist/hono/console/route-descriptor.js.map +0 -1
- package/dist/hono/console/routes/api-keys.d.ts +0 -8
- package/dist/hono/console/routes/api-keys.d.ts.map +0 -1
- package/dist/hono/console/routes/api-keys.js +0 -575
- package/dist/hono/console/routes/api-keys.js.map +0 -1
- package/dist/hono/console/routes/clients.d.ts +0 -8
- package/dist/hono/console/routes/clients.d.ts.map +0 -1
- package/dist/hono/console/routes/clients.js +0 -322
- package/dist/hono/console/routes/clients.js.map +0 -1
- package/dist/hono/console/routes/commits.d.ts +0 -8
- package/dist/hono/console/routes/commits.d.ts.map +0 -1
- package/dist/hono/console/routes/commits.js +0 -882
- package/dist/hono/console/routes/commits.js.map +0 -1
- package/dist/hono/console/routes/context.d.ts +0 -188
- package/dist/hono/console/routes/context.d.ts.map +0 -1
- package/dist/hono/console/routes/context.js +0 -633
- package/dist/hono/console/routes/context.js.map +0 -1
- package/dist/hono/console/routes/events.d.ts +0 -8
- package/dist/hono/console/routes/events.d.ts.map +0 -1
- package/dist/hono/console/routes/events.js +0 -501
- package/dist/hono/console/routes/events.js.map +0 -1
- package/dist/hono/console/routes/maintenance.d.ts +0 -8
- package/dist/hono/console/routes/maintenance.d.ts.map +0 -1
- package/dist/hono/console/routes/maintenance.js +0 -341
- package/dist/hono/console/routes/maintenance.js.map +0 -1
- package/dist/hono/console/routes/shared.d.ts +0 -174
- package/dist/hono/console/routes/shared.d.ts.map +0 -1
- package/dist/hono/console/routes/shared.js +0 -583
- package/dist/hono/console/routes/shared.js.map +0 -1
- package/dist/hono/console/routes/stats.d.ts +0 -8
- package/dist/hono/console/routes/stats.d.ts.map +0 -1
- package/dist/hono/console/routes/stats.js +0 -295
- package/dist/hono/console/routes/stats.js.map +0 -1
- package/dist/hono/console/routes/storage.d.ts +0 -8
- package/dist/hono/console/routes/storage.d.ts.map +0 -1
- package/dist/hono/console/routes/storage.js +0 -121
- package/dist/hono/console/routes/storage.js.map +0 -1
- package/dist/hono/console/routes.d.ts +0 -36
- package/dist/hono/console/routes.d.ts.map +0 -1
- package/dist/hono/console/routes.js +0 -112
- package/dist/hono/console/routes.js.map +0 -1
- package/dist/hono/console/schema-errors.d.ts +0 -2
- package/dist/hono/console/schema-errors.d.ts.map +0 -1
- package/dist/hono/console/schema-errors.js +0 -17
- package/dist/hono/console/schema-errors.js.map +0 -1
- package/dist/hono/console/schemas.d.ts +0 -1515
- package/dist/hono/console/schemas.d.ts.map +0 -1
- package/dist/hono/console/schemas.js +0 -661
- package/dist/hono/console/schemas.js.map +0 -1
- package/dist/hono/console/types.d.ts +0 -213
- package/dist/hono/console/types.d.ts.map +0 -1
- package/dist/hono/console/types.js +0 -2
- package/dist/hono/console/types.js.map +0 -1
- package/dist/hono/console/ui.d.ts +0 -38
- package/dist/hono/console/ui.d.ts.map +0 -1
- package/dist/hono/console/ui.js +0 -43
- package/dist/hono/console/ui.js.map +0 -1
- package/dist/hono/create-server.d.ts +0 -71
- package/dist/hono/create-server.d.ts.map +0 -1
- package/dist/hono/create-server.js +0 -121
- package/dist/hono/create-server.js.map +0 -1
- package/dist/hono/errors.d.ts +0 -13
- package/dist/hono/errors.d.ts.map +0 -1
- package/dist/hono/errors.js +0 -21
- package/dist/hono/errors.js.map +0 -1
- package/dist/hono/index.d.ts +0 -20
- package/dist/hono/index.d.ts.map +0 -1
- package/dist/hono/index.js +0 -31
- package/dist/hono/index.js.map +0 -1
- package/dist/hono/openapi.d.ts +0 -72
- package/dist/hono/openapi.d.ts.map +0 -1
- package/dist/hono/openapi.js +0 -99
- package/dist/hono/openapi.js.map +0 -1
- package/dist/hono/proxy/connection-manager.d.ts +0 -78
- package/dist/hono/proxy/connection-manager.d.ts.map +0 -1
- package/dist/hono/proxy/connection-manager.js +0 -251
- package/dist/hono/proxy/connection-manager.js.map +0 -1
- package/dist/hono/proxy/index.d.ts +0 -8
- package/dist/hono/proxy/index.d.ts.map +0 -1
- package/dist/hono/proxy/index.js +0 -8
- package/dist/hono/proxy/index.js.map +0 -1
- package/dist/hono/proxy/routes.d.ts +0 -86
- package/dist/hono/proxy/routes.d.ts.map +0 -1
- package/dist/hono/proxy/routes.js +0 -183
- package/dist/hono/proxy/routes.js.map +0 -1
- package/dist/hono/rate-limit.d.ts +0 -101
- package/dist/hono/rate-limit.d.ts.map +0 -1
- package/dist/hono/rate-limit.js +0 -184
- package/dist/hono/rate-limit.js.map +0 -1
- package/dist/hono/realtime-sync-packs.d.ts +0 -43
- package/dist/hono/realtime-sync-packs.d.ts.map +0 -1
- package/dist/hono/realtime-sync-packs.js +0 -219
- package/dist/hono/realtime-sync-packs.js.map +0 -1
- package/dist/hono/routes/audit.d.ts +0 -12
- package/dist/hono/routes/audit.d.ts.map +0 -1
- package/dist/hono/routes/audit.js +0 -385
- package/dist/hono/routes/audit.js.map +0 -1
- package/dist/hono/routes/auth-leases.d.ts +0 -8
- package/dist/hono/routes/auth-leases.d.ts.map +0 -1
- package/dist/hono/routes/auth-leases.js +0 -88
- package/dist/hono/routes/auth-leases.js.map +0 -1
- package/dist/hono/routes/combined.d.ts +0 -8
- package/dist/hono/routes/combined.d.ts.map +0 -1
- package/dist/hono/routes/combined.js +0 -392
- package/dist/hono/routes/combined.js.map +0 -1
- package/dist/hono/routes/context.d.ts +0 -314
- package/dist/hono/routes/context.d.ts.map +0 -1
- package/dist/hono/routes/context.js +0 -1147
- package/dist/hono/routes/context.js.map +0 -1
- package/dist/hono/routes/health.d.ts +0 -8
- package/dist/hono/routes/health.d.ts.map +0 -1
- package/dist/hono/routes/health.js +0 -16
- package/dist/hono/routes/health.js.map +0 -1
- package/dist/hono/routes/realtime.d.ts +0 -9
- package/dist/hono/routes/realtime.d.ts.map +0 -1
- package/dist/hono/routes/realtime.js +0 -626
- package/dist/hono/routes/realtime.js.map +0 -1
- package/dist/hono/routes/shared.d.ts +0 -689
- package/dist/hono/routes/shared.d.ts.map +0 -1
- package/dist/hono/routes/shared.js +0 -972
- package/dist/hono/routes/shared.js.map +0 -1
- package/dist/hono/routes/snapshots.d.ts +0 -10
- package/dist/hono/routes/snapshots.d.ts.map +0 -1
- package/dist/hono/routes/snapshots.js +0 -281
- package/dist/hono/routes/snapshots.js.map +0 -1
- package/dist/hono/routes.d.ts +0 -19
- package/dist/hono/routes.d.ts.map +0 -1
- package/dist/hono/routes.js +0 -37
- package/dist/hono/routes.js.map +0 -1
- package/dist/hono/validation.d.ts +0 -5
- package/dist/hono/validation.d.ts.map +0 -1
- package/dist/hono/validation.js +0 -47
- package/dist/hono/validation.js.map +0 -1
- package/dist/hono/websocket-origin.d.ts +0 -9
- package/dist/hono/websocket-origin.d.ts.map +0 -1
- package/dist/hono/websocket-origin.js +0 -96
- package/dist/hono/websocket-origin.js.map +0 -1
- package/dist/hono/ws.d.ts +0 -341
- package/dist/hono/ws.d.ts.map +0 -1
- package/dist/hono/ws.js +0 -711
- package/dist/hono/ws.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/libsql.d.ts +0 -29
- package/dist/libsql.d.ts.map +0 -1
- package/dist/libsql.js +0 -25
- package/dist/libsql.js.map +0 -1
- package/dist/migrate.d.ts +0 -14
- package/dist/migrate.d.ts.map +0 -1
- package/dist/migrate.js +0 -13
- package/dist/migrate.js.map +0 -1
- package/dist/neon.d.ts +0 -21
- package/dist/neon.d.ts.map +0 -1
- package/dist/neon.js +0 -22
- package/dist/neon.js.map +0 -1
- package/dist/notify.d.ts +0 -77
- package/dist/notify.d.ts.map +0 -1
- package/dist/notify.js +0 -233
- package/dist/notify.js.map +0 -1
- package/dist/pglite.d.ts +0 -37
- package/dist/pglite.d.ts.map +0 -1
- package/dist/pglite.js +0 -37
- package/dist/pglite.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -2
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -2
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/types.d.ts +0 -73
- package/dist/plugins/types.d.ts.map +0 -1
- package/dist/plugins/types.js +0 -30
- package/dist/plugins/types.js.map +0 -1
- package/dist/postgres/index.d.ts +0 -68
- package/dist/postgres/index.d.ts.map +0 -1
- package/dist/postgres/index.js +0 -924
- package/dist/postgres/index.js.map +0 -1
- package/dist/proxy/collection.d.ts +0 -7
- package/dist/proxy/collection.d.ts.map +0 -1
- package/dist/proxy/collection.js +0 -6
- package/dist/proxy/collection.js.map +0 -1
- package/dist/proxy/handler.d.ts +0 -42
- package/dist/proxy/handler.d.ts.map +0 -1
- package/dist/proxy/handler.js +0 -102
- package/dist/proxy/handler.js.map +0 -1
- package/dist/proxy/index.d.ts +0 -9
- package/dist/proxy/index.d.ts.map +0 -1
- package/dist/proxy/index.js +0 -14
- package/dist/proxy/index.js.map +0 -1
- package/dist/proxy/mutation-detector.d.ts +0 -35
- package/dist/proxy/mutation-detector.d.ts.map +0 -1
- package/dist/proxy/mutation-detector.js +0 -246
- package/dist/proxy/mutation-detector.js.map +0 -1
- package/dist/proxy/oplog.d.ts +0 -30
- package/dist/proxy/oplog.d.ts.map +0 -1
- package/dist/proxy/oplog.js +0 -137
- package/dist/proxy/oplog.js.map +0 -1
- package/dist/proxy/types.d.ts +0 -44
- package/dist/proxy/types.d.ts.map +0 -1
- package/dist/proxy/types.js +0 -7
- package/dist/proxy/types.js.map +0 -1
- package/dist/prune.d.ts.map +0 -1
- package/dist/prune.js.map +0 -1
- package/dist/pull.d.ts.map +0 -1
- package/dist/pull.js.map +0 -1
- package/dist/push.d.ts.map +0 -1
- package/dist/push.js.map +0 -1
- package/dist/realtime/in-memory.d.ts +0 -13
- package/dist/realtime/in-memory.d.ts.map +0 -1
- package/dist/realtime/in-memory.js +0 -28
- package/dist/realtime/in-memory.js.map +0 -1
- package/dist/realtime/index.d.ts +0 -4
- package/dist/realtime/index.d.ts.map +0 -1
- package/dist/realtime/index.js +0 -3
- package/dist/realtime/index.js.map +0 -1
- package/dist/realtime/types.d.ts +0 -62
- package/dist/realtime/types.d.ts.map +0 -1
- package/dist/realtime/types.js +0 -19
- package/dist/realtime/types.js.map +0 -1
- package/dist/relay/client-role/forward-engine.d.ts +0 -63
- package/dist/relay/client-role/forward-engine.d.ts.map +0 -1
- package/dist/relay/client-role/forward-engine.js +0 -267
- package/dist/relay/client-role/forward-engine.js.map +0 -1
- package/dist/relay/client-role/index.d.ts +0 -9
- package/dist/relay/client-role/index.d.ts.map +0 -1
- package/dist/relay/client-role/index.js +0 -9
- package/dist/relay/client-role/index.js.map +0 -1
- package/dist/relay/client-role/pull-engine.d.ts +0 -72
- package/dist/relay/client-role/pull-engine.d.ts.map +0 -1
- package/dist/relay/client-role/pull-engine.js +0 -249
- package/dist/relay/client-role/pull-engine.js.map +0 -1
- package/dist/relay/client-role/sequence-mapper.d.ts +0 -65
- package/dist/relay/client-role/sequence-mapper.d.ts.map +0 -1
- package/dist/relay/client-role/sequence-mapper.js +0 -161
- package/dist/relay/client-role/sequence-mapper.js.map +0 -1
- package/dist/relay/evaluation/relay-paths.d.ts +0 -41
- package/dist/relay/evaluation/relay-paths.d.ts.map +0 -1
- package/dist/relay/evaluation/relay-paths.js +0 -504
- package/dist/relay/evaluation/relay-paths.js.map +0 -1
- package/dist/relay/evaluation/rust-boundary.d.ts +0 -47
- package/dist/relay/evaluation/rust-boundary.d.ts.map +0 -1
- package/dist/relay/evaluation/rust-boundary.js +0 -220
- package/dist/relay/evaluation/rust-boundary.js.map +0 -1
- package/dist/relay/index.d.ts +0 -37
- package/dist/relay/index.d.ts.map +0 -1
- package/dist/relay/index.js +0 -44
- package/dist/relay/index.js.map +0 -1
- package/dist/relay/migrate.d.ts +0 -18
- package/dist/relay/migrate.d.ts.map +0 -1
- package/dist/relay/migrate.js +0 -99
- package/dist/relay/migrate.js.map +0 -1
- package/dist/relay/mode-manager.d.ts +0 -60
- package/dist/relay/mode-manager.d.ts.map +0 -1
- package/dist/relay/mode-manager.js +0 -114
- package/dist/relay/mode-manager.js.map +0 -1
- package/dist/relay/realtime.d.ts +0 -90
- package/dist/relay/realtime.d.ts.map +0 -1
- package/dist/relay/realtime.js +0 -147
- package/dist/relay/realtime.js.map +0 -1
- package/dist/relay/relay.d.ts +0 -190
- package/dist/relay/relay.d.ts.map +0 -1
- package/dist/relay/relay.js +0 -320
- package/dist/relay/relay.js.map +0 -1
- package/dist/relay/schema.d.ts +0 -158
- package/dist/relay/schema.d.ts.map +0 -1
- package/dist/relay/schema.js +0 -7
- package/dist/relay/schema.js.map +0 -1
- package/dist/relay/server-role/index.d.ts +0 -56
- package/dist/relay/server-role/index.d.ts.map +0 -1
- package/dist/relay/server-role/index.js +0 -193
- package/dist/relay/server-role/index.js.map +0 -1
- package/dist/relay/server-role/pull.d.ts +0 -27
- package/dist/relay/server-role/pull.d.ts.map +0 -1
- package/dist/relay/server-role/pull.js +0 -24
- package/dist/relay/server-role/pull.js.map +0 -1
- package/dist/relay/server-role/push.d.ts +0 -29
- package/dist/relay/server-role/push.d.ts.map +0 -1
- package/dist/relay/server-role/push.js +0 -122
- package/dist/relay/server-role/push.js.map +0 -1
- package/dist/s3/index.d.ts +0 -83
- package/dist/s3/index.d.ts.map +0 -1
- package/dist/s3/index.js +0 -223
- package/dist/s3/index.js.map +0 -1
- package/dist/schema.d.ts.map +0 -1
- package/dist/schema.js.map +0 -1
- package/dist/service-worker/index.d.ts +0 -114
- package/dist/service-worker/index.d.ts.map +0 -1
- package/dist/service-worker/index.js +0 -487
- package/dist/service-worker/index.js.map +0 -1
- package/dist/snapshot-artifacts/sqlite-bun.d.ts +0 -15
- package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +0 -1
- package/dist/snapshot-artifacts/sqlite-bun.js +0 -128
- package/dist/snapshot-artifacts/sqlite-bun.js.map +0 -1
- package/dist/snapshot-artifacts.d.ts +0 -206
- package/dist/snapshot-artifacts.d.ts.map +0 -1
- package/dist/snapshot-artifacts.js +0 -545
- package/dist/snapshot-artifacts.js.map +0 -1
- package/dist/snapshot-chunks/db-metadata.d.ts +0 -56
- package/dist/snapshot-chunks/db-metadata.d.ts.map +0 -1
- package/dist/snapshot-chunks/db-metadata.js +0 -360
- package/dist/snapshot-chunks/db-metadata.js.map +0 -1
- package/dist/snapshot-chunks/index.d.ts +0 -8
- package/dist/snapshot-chunks/index.d.ts.map +0 -1
- package/dist/snapshot-chunks/index.js +0 -8
- package/dist/snapshot-chunks/index.js.map +0 -1
- package/dist/snapshot-chunks/types.d.ts +0 -80
- package/dist/snapshot-chunks/types.d.ts.map +0 -1
- package/dist/snapshot-chunks/types.js +0 -8
- package/dist/snapshot-chunks/types.js.map +0 -1
- package/dist/snapshot-chunks.d.ts +0 -90
- package/dist/snapshot-chunks.d.ts.map +0 -1
- package/dist/snapshot-chunks.js +0 -304
- package/dist/snapshot-chunks.js.map +0 -1
- package/dist/sqlite/index.d.ts +0 -53
- package/dist/sqlite/index.d.ts.map +0 -1
- package/dist/sqlite/index.js +0 -795
- package/dist/sqlite/index.js.map +0 -1
- package/dist/sqlite3.d.ts +0 -22
- package/dist/sqlite3.d.ts.map +0 -1
- package/dist/sqlite3.js +0 -99
- package/dist/sqlite3.js.map +0 -1
- package/dist/stats.d.ts +0 -28
- package/dist/stats.d.ts.map +0 -1
- package/dist/stats.js +0 -93
- package/dist/stats.js.map +0 -1
- package/dist/subscriptions/cache.d.ts +0 -58
- package/dist/subscriptions/cache.d.ts.map +0 -1
- package/dist/subscriptions/cache.js +0 -250
- package/dist/subscriptions/cache.js.map +0 -1
- package/dist/subscriptions/index.d.ts +0 -3
- package/dist/subscriptions/index.d.ts.map +0 -1
- package/dist/subscriptions/index.js +0 -3
- package/dist/subscriptions/index.js.map +0 -1
- package/dist/subscriptions/resolve.d.ts +0 -40
- package/dist/subscriptions/resolve.d.ts.map +0 -1
- package/dist/subscriptions/resolve.js +0 -275
- package/dist/subscriptions/resolve.js.map +0 -1
- package/dist/sync.d.ts +0 -24
- package/dist/sync.d.ts.map +0 -1
- package/dist/sync.js +0 -27
- package/dist/sync.js.map +0 -1
- package/src/auth-leases.ts +0 -649
- package/src/better-sqlite3.ts +0 -35
- package/src/blobs/access.ts +0 -244
- package/src/blobs/adapters/database.ts +0 -397
- package/src/blobs/index.ts +0 -9
- package/src/blobs/manager.ts +0 -901
- package/src/blobs/migrate.ts +0 -158
- package/src/blobs/types.ts +0 -74
- package/src/bun-sqlite-ambient.d.ts +0 -19
- package/src/bun-sqlite.ts +0 -27
- package/src/clients.ts +0 -22
- package/src/cloudflare/durable-object.ts +0 -289
- package/src/cloudflare/index.ts +0 -22
- package/src/cloudflare/r2.ts +0 -526
- package/src/cloudflare/scope-cache.ts +0 -341
- package/src/cloudflare/sentry.ts +0 -230
- package/src/cloudflare/worker.ts +0 -77
- package/src/commit-integrity.ts +0 -371
- package/src/compaction.ts +0 -77
- package/src/crdt-yjs/index.ts +0 -931
- package/src/d1.ts +0 -16
- package/src/dialect/base.ts +0 -360
- package/src/dialect/helpers.ts +0 -92
- package/src/dialect/index.ts +0 -7
- package/src/dialect/types.ts +0 -247
- package/src/encrypted-crdt.ts +0 -786
- package/src/filesystem/index.ts +0 -262
- package/src/handlers/collection.ts +0 -121
- package/src/handlers/create-handler.ts +0 -1134
- package/src/handlers/index.ts +0 -3
- package/src/handlers/types.ts +0 -403
- package/src/helpers/conflict.ts +0 -64
- package/src/helpers/emitted-change.ts +0 -69
- package/src/helpers/index.ts +0 -12
- package/src/helpers/paginate.ts +0 -82
- package/src/helpers/scope-authorization.ts +0 -27
- package/src/helpers/scope-commit-index.ts +0 -52
- package/src/helpers/scope-strings.ts +0 -101
- package/src/hono/api-key-auth.ts +0 -177
- package/src/hono/audit-redaction.ts +0 -135
- package/src/hono/blobs.ts +0 -851
- package/src/hono/console/gateway.ts +0 -3046
- package/src/hono/console/live-auth.ts +0 -46
- package/src/hono/console/route-descriptor.ts +0 -22
- package/src/hono/console/routes/api-keys.ts +0 -721
- package/src/hono/console/routes/clients.ts +0 -447
- package/src/hono/console/routes/commits.ts +0 -1137
- package/src/hono/console/routes/context.ts +0 -956
- package/src/hono/console/routes/events.ts +0 -669
- package/src/hono/console/routes/maintenance.ts +0 -461
- package/src/hono/console/routes/shared.ts +0 -816
- package/src/hono/console/routes/stats.ts +0 -392
- package/src/hono/console/routes/storage.ts +0 -159
- package/src/hono/console/routes.ts +0 -146
- package/src/hono/console/schema-errors.ts +0 -23
- package/src/hono/console/schemas.ts +0 -914
- package/src/hono/console/types.ts +0 -223
- package/src/hono/console/ui.ts +0 -100
- package/src/hono/create-server.ts +0 -230
- package/src/hono/errors.ts +0 -50
- package/src/hono/index.ts +0 -54
- package/src/hono/openapi.ts +0 -139
- package/src/hono/proxy/connection-manager.ts +0 -340
- package/src/hono/proxy/index.ts +0 -8
- package/src/hono/proxy/routes.ts +0 -272
- package/src/hono/rate-limit.ts +0 -319
- package/src/hono/realtime-sync-packs.ts +0 -354
- package/src/hono/routes/audit.ts +0 -499
- package/src/hono/routes/auth-leases.ts +0 -119
- package/src/hono/routes/combined.ts +0 -583
- package/src/hono/routes/context.ts +0 -1629
- package/src/hono/routes/health.ts +0 -26
- package/src/hono/routes/realtime.ts +0 -808
- package/src/hono/routes/shared.ts +0 -1626
- package/src/hono/routes/snapshots.ts +0 -345
- package/src/hono/routes.ts +0 -68
- package/src/hono/validation.ts +0 -81
- package/src/hono/websocket-origin.ts +0 -131
- package/src/hono/ws.ts +0 -1134
- package/src/libsql.ts +0 -51
- package/src/migrate.ts +0 -20
- package/src/neon.ts +0 -28
- package/src/notify.ts +0 -341
- package/src/pglite.ts +0 -68
- package/src/plugins/index.ts +0 -1
- package/src/plugins/types.ts +0 -144
- package/src/postgres/index.ts +0 -1291
- package/src/proxy/collection.ts +0 -17
- package/src/proxy/handler.ts +0 -159
- package/src/proxy/index.ts +0 -21
- package/src/proxy/mutation-detector.ts +0 -281
- package/src/proxy/oplog.ts +0 -181
- package/src/proxy/types.ts +0 -46
- package/src/realtime/in-memory.ts +0 -33
- package/src/realtime/index.ts +0 -7
- package/src/realtime/types.ts +0 -90
- package/src/relay/bun-types.d.ts +0 -50
- package/src/relay/client-role/forward-engine.ts +0 -355
- package/src/relay/client-role/index.ts +0 -9
- package/src/relay/client-role/pull-engine.ts +0 -329
- package/src/relay/client-role/sequence-mapper.ts +0 -201
- package/src/relay/evaluation/relay-paths.ts +0 -699
- package/src/relay/evaluation/rust-boundary.ts +0 -464
- package/src/relay/index.ts +0 -50
- package/src/relay/migrate.ts +0 -113
- package/src/relay/mode-manager.ts +0 -142
- package/src/relay/realtime.ts +0 -207
- package/src/relay/relay.ts +0 -431
- package/src/relay/schema.ts +0 -171
- package/src/relay/server-role/index.ts +0 -338
- package/src/relay/server-role/pull.ts +0 -43
- package/src/relay/server-role/push.ts +0 -164
- package/src/s3/index.ts +0 -346
- package/src/service-worker/index.ts +0 -773
- package/src/snapshot-artifacts/sqlite-bun.ts +0 -168
- package/src/snapshot-artifacts.ts +0 -896
- package/src/snapshot-chunks/db-metadata.ts +0 -537
- package/src/snapshot-chunks/index.ts +0 -8
- package/src/snapshot-chunks/types.ts +0 -105
- package/src/snapshot-chunks.ts +0 -453
- package/src/sqlite/index.ts +0 -1064
- package/src/sqlite3.ts +0 -137
- package/src/stats.ts +0 -180
- package/src/subscriptions/cache.ts +0 -376
- package/src/subscriptions/index.ts +0 -2
- package/src/subscriptions/resolve.ts +0 -357
- package/src/sync.ts +0 -111
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite storage via `bun:sqlite` (dev-speed, dependency-free).
|
|
3
|
+
*
|
|
4
|
+
* Scope fanout is index-first (REVISE B2): both the commit log and the
|
|
5
|
+
* current-row table carry a (table, variable, value) inverted index; reads
|
|
6
|
+
* select candidates from the index and verify the full multi-variable
|
|
7
|
+
* match against the stored scope map — never a log scan.
|
|
8
|
+
*/
|
|
9
|
+
import { Database } from 'bun:sqlite';
|
|
10
|
+
import { syncError } from './errors';
|
|
11
|
+
import {
|
|
12
|
+
commitWindowPageSql,
|
|
13
|
+
deleteRowSql,
|
|
14
|
+
layoutsOf,
|
|
15
|
+
migratePayload,
|
|
16
|
+
parseLayouts,
|
|
17
|
+
rewritePlan,
|
|
18
|
+
rewriteRowSql,
|
|
19
|
+
rewriteValues,
|
|
20
|
+
SCHEMA_META_DDL_SQLITE,
|
|
21
|
+
type StoredColumnLayout,
|
|
22
|
+
scanRowPageSql,
|
|
23
|
+
schemaDdl,
|
|
24
|
+
selectRowScopesSql,
|
|
25
|
+
selectRowSql,
|
|
26
|
+
selectRowsForRewriteSql,
|
|
27
|
+
upsertSql,
|
|
28
|
+
upsertValues,
|
|
29
|
+
} from './relational-rows';
|
|
30
|
+
import type { CompiledSchema, CompiledTable } from './schema';
|
|
31
|
+
import { matchesEffective } from './scopes';
|
|
32
|
+
import {
|
|
33
|
+
collectCommitWindowPage,
|
|
34
|
+
deserializePushResult,
|
|
35
|
+
SQLITE_DDL,
|
|
36
|
+
type SqliteCommitWindowRecord,
|
|
37
|
+
type SqliteRowRecord,
|
|
38
|
+
serializePushResult,
|
|
39
|
+
toStoredRow,
|
|
40
|
+
} from './sqlite-dialect';
|
|
41
|
+
import type {
|
|
42
|
+
ClientCursorInfo,
|
|
43
|
+
ClientRecord,
|
|
44
|
+
ClientSubscription,
|
|
45
|
+
CommitMetadata,
|
|
46
|
+
CommitMetadataQuery,
|
|
47
|
+
CommitWindowQuery,
|
|
48
|
+
NewCommit,
|
|
49
|
+
RowScanQuery,
|
|
50
|
+
ScopeActivityQuery,
|
|
51
|
+
ScopeCommitActivity,
|
|
52
|
+
ServerStorage,
|
|
53
|
+
StorageTransaction,
|
|
54
|
+
StoredCommit,
|
|
55
|
+
StoredPushResult,
|
|
56
|
+
StoredRow,
|
|
57
|
+
} from './storage';
|
|
58
|
+
|
|
59
|
+
class SqliteTransaction implements StorageTransaction {
|
|
60
|
+
#storage: SqliteServerStorage;
|
|
61
|
+
#partition: string;
|
|
62
|
+
#open = true;
|
|
63
|
+
|
|
64
|
+
constructor(storage: SqliteServerStorage, partition: string) {
|
|
65
|
+
this.#storage = storage;
|
|
66
|
+
this.#partition = partition;
|
|
67
|
+
storage.db.exec('BEGIN IMMEDIATE');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#assertOpen(): void {
|
|
71
|
+
if (!this.#open) throw new Error('transaction already finished');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getRow(table: string, rowId: string): Promise<StoredRow | undefined> {
|
|
75
|
+
this.#assertOpen();
|
|
76
|
+
return this.#storage.getRow(this.#partition, table, rowId);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async upsertRow(table: string, row: StoredRow): Promise<void> {
|
|
80
|
+
this.#assertOpen();
|
|
81
|
+
this.#storage.writeRow(this.#partition, table, row);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async deleteRow(table: string, rowId: string): Promise<void> {
|
|
85
|
+
this.#assertOpen();
|
|
86
|
+
const db = this.#storage.db;
|
|
87
|
+
db.query(deleteRowSql(this.#storage.table(table), 'sqlite')).run(
|
|
88
|
+
this.#partition,
|
|
89
|
+
rowId,
|
|
90
|
+
);
|
|
91
|
+
db.query(
|
|
92
|
+
'DELETE FROM sync_row_scopes WHERE partition=? AND tbl=? AND row_id=?',
|
|
93
|
+
).run(this.#partition, table, rowId);
|
|
94
|
+
// §5.9.4: a deleted row references no blobs.
|
|
95
|
+
db.query(
|
|
96
|
+
'DELETE FROM sync_blob_refs WHERE partition=? AND tbl=? AND row_id=?',
|
|
97
|
+
).run(this.#partition, table, rowId);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async setBlobRefs(
|
|
101
|
+
table: string,
|
|
102
|
+
rowId: string,
|
|
103
|
+
blobIds: readonly string[],
|
|
104
|
+
): Promise<void> {
|
|
105
|
+
this.#assertOpen();
|
|
106
|
+
const db = this.#storage.db;
|
|
107
|
+
// Replace the row's reference set atomically (§5.9.4).
|
|
108
|
+
db.query(
|
|
109
|
+
'DELETE FROM sync_blob_refs WHERE partition=? AND tbl=? AND row_id=?',
|
|
110
|
+
).run(this.#partition, table, rowId);
|
|
111
|
+
for (const blobId of blobIds) {
|
|
112
|
+
db.query(
|
|
113
|
+
'INSERT OR IGNORE INTO sync_blob_refs(partition, tbl, row_id, blob_id) VALUES (?,?,?,?)',
|
|
114
|
+
).run(this.#partition, table, rowId, blobId);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async appendCommit(commit: NewCommit): Promise<number> {
|
|
119
|
+
this.#assertOpen();
|
|
120
|
+
const db = this.#storage.db;
|
|
121
|
+
const p = this.#partition;
|
|
122
|
+
db.query('INSERT OR IGNORE INTO sync_partitions(partition) VALUES (?)').run(
|
|
123
|
+
p,
|
|
124
|
+
);
|
|
125
|
+
const row = db
|
|
126
|
+
.query<{ max_commit_seq: number }, [string]>(
|
|
127
|
+
'SELECT max_commit_seq FROM sync_partitions WHERE partition=?',
|
|
128
|
+
)
|
|
129
|
+
.get(p);
|
|
130
|
+
const commitSeq = (row?.max_commit_seq ?? 0) + 1;
|
|
131
|
+
db.query(
|
|
132
|
+
'UPDATE sync_partitions SET max_commit_seq=? WHERE partition=?',
|
|
133
|
+
).run(commitSeq, p);
|
|
134
|
+
db.query(
|
|
135
|
+
'INSERT INTO sync_commits(partition, commit_seq, client_id, client_commit_id, actor_id, created_at_ms) VALUES (?,?,?,?,?,?)',
|
|
136
|
+
).run(
|
|
137
|
+
p,
|
|
138
|
+
commitSeq,
|
|
139
|
+
commit.clientId,
|
|
140
|
+
commit.clientCommitId,
|
|
141
|
+
commit.actorId,
|
|
142
|
+
commit.createdAtMs,
|
|
143
|
+
);
|
|
144
|
+
commit.changes.forEach((change, idx) => {
|
|
145
|
+
db.query(
|
|
146
|
+
'INSERT INTO sync_changes(partition, commit_seq, idx, tbl, row_id, op, row_version, scopes, payload) VALUES (?,?,?,?,?,?,?,?,?)',
|
|
147
|
+
).run(
|
|
148
|
+
p,
|
|
149
|
+
commitSeq,
|
|
150
|
+
idx,
|
|
151
|
+
change.table,
|
|
152
|
+
change.rowId,
|
|
153
|
+
change.op === 'upsert' ? 1 : 2,
|
|
154
|
+
change.rowVersion ?? null,
|
|
155
|
+
JSON.stringify(change.scopes),
|
|
156
|
+
change.payload ?? null,
|
|
157
|
+
);
|
|
158
|
+
for (const [variable, value] of Object.entries(change.scopes)) {
|
|
159
|
+
db.query(
|
|
160
|
+
'INSERT OR IGNORE INTO sync_change_scopes(partition, tbl, var, value, commit_seq) VALUES (?,?,?,?,?)',
|
|
161
|
+
).run(p, change.table, variable, value, commitSeq);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return commitSeq;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async putPushResult(
|
|
168
|
+
clientId: string,
|
|
169
|
+
clientCommitId: string,
|
|
170
|
+
result: StoredPushResult,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
this.#assertOpen();
|
|
173
|
+
this.#storage.db
|
|
174
|
+
.query(
|
|
175
|
+
'INSERT OR REPLACE INTO sync_push_results(partition, client_id, client_commit_id, result) VALUES (?,?,?,?)',
|
|
176
|
+
)
|
|
177
|
+
.run(
|
|
178
|
+
this.#partition,
|
|
179
|
+
clientId,
|
|
180
|
+
clientCommitId,
|
|
181
|
+
serializePushResult(result),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async commit(): Promise<void> {
|
|
186
|
+
this.#assertOpen();
|
|
187
|
+
this.#open = false;
|
|
188
|
+
this.#storage.db.exec('COMMIT');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async rollback(): Promise<void> {
|
|
192
|
+
if (!this.#open) return;
|
|
193
|
+
this.#open = false;
|
|
194
|
+
this.#storage.db.exec('ROLLBACK');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export class SqliteServerStorage implements ServerStorage {
|
|
199
|
+
readonly db: Database;
|
|
200
|
+
/** Set by `ensureSchema`: app-table lookup for the relational row store. */
|
|
201
|
+
#tables: ReadonlyMap<string, CompiledTable> | undefined;
|
|
202
|
+
#schemaVersion: number | undefined;
|
|
203
|
+
|
|
204
|
+
constructor(db: Database | string = ':memory:') {
|
|
205
|
+
this.db = typeof db === 'string' ? new Database(db) : db;
|
|
206
|
+
this.db.exec(SQLITE_DDL);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Resolve a table's compiled schema; row operations require `ensureSchema`. */
|
|
210
|
+
table(name: string): CompiledTable {
|
|
211
|
+
const table = this.#tables?.get(name);
|
|
212
|
+
if (table === undefined) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`unknown table ${JSON.stringify(name)} — ensureSchema(schema) must run before row operations`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return table;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async ensureSchema(schema: CompiledSchema): Promise<void> {
|
|
221
|
+
// Memoized fast path: same instance, same schema version.
|
|
222
|
+
if (this.#schemaVersion === schema.version) return;
|
|
223
|
+
this.db.exec(SCHEMA_META_DDL_SQLITE);
|
|
224
|
+
const marker = this.db
|
|
225
|
+
.query<{ schema_version: number; layouts: string }, []>(
|
|
226
|
+
'SELECT schema_version, layouts FROM sync_schema_meta WHERE id=1',
|
|
227
|
+
)
|
|
228
|
+
.get();
|
|
229
|
+
if (marker !== null && marker.schema_version > schema.version) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`stored schema version ${marker.schema_version} is newer than the configured schema (${schema.version}) — refusing to run an older server against a migrated database`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (marker === null || marker.schema_version < schema.version) {
|
|
235
|
+
// Introspect existing app tables, then apply the migration subset
|
|
236
|
+
// (CREATE TABLE / ADD COLUMN / CREATE INDEX) to reach `schema`, then
|
|
237
|
+
// rewrite stored rows (payload re-encode for layout changes, and/or
|
|
238
|
+
// projection backfill for flipped-on materialization). One
|
|
239
|
+
// transaction: a failed bump leaves no half-state.
|
|
240
|
+
const layouts = parseLayouts(marker?.layouts);
|
|
241
|
+
const existing = new Map<string, ReadonlySet<string>>();
|
|
242
|
+
for (const table of schema.tables.values()) {
|
|
243
|
+
const columns = this.db
|
|
244
|
+
.query<{ name: string }, []>(
|
|
245
|
+
`PRAGMA table_info("${table.name.replaceAll('"', '""')}")`,
|
|
246
|
+
)
|
|
247
|
+
.all();
|
|
248
|
+
if (columns.length > 0) {
|
|
249
|
+
existing.set(table.name, new Set(columns.map((c) => c.name)));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
253
|
+
try {
|
|
254
|
+
for (const statement of schemaDdl(schema, existing, 'sqlite')) {
|
|
255
|
+
this.db.exec(statement);
|
|
256
|
+
}
|
|
257
|
+
for (const table of schema.tables.values()) {
|
|
258
|
+
const oldLayout = layouts[table.name];
|
|
259
|
+
const plan = rewritePlan(table, oldLayout, existing.get(table.name));
|
|
260
|
+
if (!plan.migrate && !plan.backfill) continue;
|
|
261
|
+
this.#rewriteRows(table, plan.migrate ? oldLayout : undefined);
|
|
262
|
+
}
|
|
263
|
+
this.db
|
|
264
|
+
.query(
|
|
265
|
+
'INSERT INTO sync_schema_meta(id, schema_version, layouts) VALUES (1, ?, ?) ON CONFLICT(id) DO UPDATE SET schema_version=excluded.schema_version, layouts=excluded.layouts',
|
|
266
|
+
)
|
|
267
|
+
.run(schema.version, layoutsOf(schema));
|
|
268
|
+
this.db.exec('COMMIT');
|
|
269
|
+
} catch (error) {
|
|
270
|
+
this.db.exec('ROLLBACK');
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
this.#tables = schema.tables;
|
|
275
|
+
this.#schemaVersion = schema.version;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Migration rewrite (DESIGN "optional materialization"): keyset-paged walk
|
|
280
|
+
* of a row table; when `oldLayout` is given every payload re-encodes under
|
|
281
|
+
* the current columns, and the projection (when materialized) refreshes
|
|
282
|
+
* from the payload either way.
|
|
283
|
+
*/
|
|
284
|
+
#rewriteRows(
|
|
285
|
+
table: CompiledTable,
|
|
286
|
+
oldLayout: readonly StoredColumnLayout[] | undefined,
|
|
287
|
+
): void {
|
|
288
|
+
const select = selectRowsForRewriteSql(table, 'sqlite');
|
|
289
|
+
const update = this.db.query(rewriteRowSql(table, 'sqlite'));
|
|
290
|
+
const BATCH = 500;
|
|
291
|
+
let afterPartition = '';
|
|
292
|
+
let afterRowId = '';
|
|
293
|
+
for (;;) {
|
|
294
|
+
const rows = this.db
|
|
295
|
+
.query<
|
|
296
|
+
{ partition: string; row_id: string; payload: Uint8Array },
|
|
297
|
+
[string, string, number]
|
|
298
|
+
>(select)
|
|
299
|
+
.all(afterPartition, afterRowId, BATCH);
|
|
300
|
+
if (rows.length === 0) break;
|
|
301
|
+
for (const row of rows) {
|
|
302
|
+
const payload =
|
|
303
|
+
oldLayout !== undefined
|
|
304
|
+
? migratePayload(oldLayout, table, row.payload)
|
|
305
|
+
: row.payload;
|
|
306
|
+
update.run(
|
|
307
|
+
...(rewriteValues(
|
|
308
|
+
table,
|
|
309
|
+
row.partition,
|
|
310
|
+
row.row_id,
|
|
311
|
+
payload,
|
|
312
|
+
'sqlite',
|
|
313
|
+
) as (string | number | boolean | Uint8Array | null)[]),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const last = rows[rows.length - 1];
|
|
317
|
+
if (last === undefined || rows.length < BATCH) break;
|
|
318
|
+
afterPartition = last.partition;
|
|
319
|
+
afterRowId = last.row_id;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async begin(partition: string): Promise<StorageTransaction> {
|
|
324
|
+
return new SqliteTransaction(this, partition);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Internal: write a row + refresh its scope-index entries. */
|
|
328
|
+
writeRow(partition: string, table: string, row: StoredRow): void {
|
|
329
|
+
const compiled = this.table(table);
|
|
330
|
+
this.db
|
|
331
|
+
.query(upsertSql(compiled, 'sqlite'))
|
|
332
|
+
.run(
|
|
333
|
+
...(upsertValues(compiled, partition, row, 'sqlite') as (
|
|
334
|
+
| string
|
|
335
|
+
| number
|
|
336
|
+
| boolean
|
|
337
|
+
| Uint8Array
|
|
338
|
+
| null
|
|
339
|
+
)[]),
|
|
340
|
+
);
|
|
341
|
+
this.db
|
|
342
|
+
.query(
|
|
343
|
+
'DELETE FROM sync_row_scopes WHERE partition=? AND tbl=? AND row_id=?',
|
|
344
|
+
)
|
|
345
|
+
.run(partition, table, row.rowId);
|
|
346
|
+
for (const [variable, value] of Object.entries(row.scopes)) {
|
|
347
|
+
this.db
|
|
348
|
+
.query(
|
|
349
|
+
'INSERT OR IGNORE INTO sync_row_scopes(partition, tbl, var, value, row_id) VALUES (?,?,?,?,?)',
|
|
350
|
+
)
|
|
351
|
+
.run(partition, table, variable, value, row.rowId);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async getMaxCommitSeq(partition: string): Promise<number> {
|
|
356
|
+
const row = this.db
|
|
357
|
+
.query<{ max_commit_seq: number }, [string]>(
|
|
358
|
+
'SELECT max_commit_seq FROM sync_partitions WHERE partition=?',
|
|
359
|
+
)
|
|
360
|
+
.get(partition);
|
|
361
|
+
return row?.max_commit_seq ?? 0;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async getHorizonSeq(partition: string): Promise<number> {
|
|
365
|
+
const row = this.db
|
|
366
|
+
.query<{ horizon_seq: number }, [string]>(
|
|
367
|
+
'SELECT horizon_seq FROM sync_partitions WHERE partition=?',
|
|
368
|
+
)
|
|
369
|
+
.get(partition);
|
|
370
|
+
return row?.horizon_seq ?? 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async setHorizonSeq(partition: string, seq: number): Promise<void> {
|
|
374
|
+
this.db
|
|
375
|
+
.query('INSERT OR IGNORE INTO sync_partitions(partition) VALUES (?)')
|
|
376
|
+
.run(partition);
|
|
377
|
+
this.db
|
|
378
|
+
.query('UPDATE sync_partitions SET horizon_seq=? WHERE partition=?')
|
|
379
|
+
.run(seq, partition);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async pruneCommitsThrough(partition: string, seq: number): Promise<number> {
|
|
383
|
+
const removed = this.db
|
|
384
|
+
.query('DELETE FROM sync_commits WHERE partition=? AND commit_seq<=?')
|
|
385
|
+
.run(partition, seq);
|
|
386
|
+
this.db
|
|
387
|
+
.query('DELETE FROM sync_changes WHERE partition=? AND commit_seq<=?')
|
|
388
|
+
.run(partition, seq);
|
|
389
|
+
this.db
|
|
390
|
+
.query(
|
|
391
|
+
'DELETE FROM sync_change_scopes WHERE partition=? AND commit_seq<=?',
|
|
392
|
+
)
|
|
393
|
+
.run(partition, seq);
|
|
394
|
+
return Number(removed.changes);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async getCommitSeqBefore(
|
|
398
|
+
partition: string,
|
|
399
|
+
createdBeforeMs: number,
|
|
400
|
+
): Promise<number> {
|
|
401
|
+
const row = this.db
|
|
402
|
+
.query<{ seq: number | null }, [string, number]>(
|
|
403
|
+
'SELECT max(commit_seq) AS seq FROM sync_commits WHERE partition=? AND created_at_ms<?',
|
|
404
|
+
)
|
|
405
|
+
.get(partition, createdBeforeMs);
|
|
406
|
+
return row?.seq ?? 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async getRow(
|
|
410
|
+
partition: string,
|
|
411
|
+
table: string,
|
|
412
|
+
rowId: string,
|
|
413
|
+
): Promise<StoredRow | undefined> {
|
|
414
|
+
const record = this.db
|
|
415
|
+
.query<SqliteRowRecord, [string, string]>(
|
|
416
|
+
selectRowSql(this.table(table), 'sqlite'),
|
|
417
|
+
)
|
|
418
|
+
.get(partition, rowId);
|
|
419
|
+
return record === null ? undefined : toStoredRow(record);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async getPushResult(
|
|
423
|
+
partition: string,
|
|
424
|
+
clientId: string,
|
|
425
|
+
clientCommitId: string,
|
|
426
|
+
): Promise<StoredPushResult | undefined> {
|
|
427
|
+
const record = this.db
|
|
428
|
+
.query<{ result: string }, [string, string, string]>(
|
|
429
|
+
'SELECT result FROM sync_push_results WHERE partition=? AND client_id=? AND client_commit_id=?',
|
|
430
|
+
)
|
|
431
|
+
.get(partition, clientId, clientCommitId);
|
|
432
|
+
if (record === null) return undefined;
|
|
433
|
+
try {
|
|
434
|
+
return deserializePushResult(record.result);
|
|
435
|
+
} catch {
|
|
436
|
+
throw syncError(
|
|
437
|
+
'sync.idempotency_cache_miss',
|
|
438
|
+
'persisted push result unreadable (§6.3)',
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async readCommitWindow(
|
|
444
|
+
partition: string,
|
|
445
|
+
query: CommitWindowQuery,
|
|
446
|
+
): Promise<StoredCommit[]> {
|
|
447
|
+
const variables = Object.keys(query.scopeFilter).sort();
|
|
448
|
+
const firstVariable = variables[0];
|
|
449
|
+
if (firstVariable === undefined) return [];
|
|
450
|
+
const firstValues = query.scopeFilter[firstVariable] ?? [];
|
|
451
|
+
if (firstValues.length === 0) return [];
|
|
452
|
+
// Candidates via the inverted index (one variable) LEFT JOINed to the
|
|
453
|
+
// commit meta + the table's changes — one statement per page, never two
|
|
454
|
+
// per candidate (see `commitWindowPageSql`). Exact multi-variable
|
|
455
|
+
// verification against the stored scope map in `collectCommitWindowPage`.
|
|
456
|
+
const sql = commitWindowPageSql(firstValues.length, 'sqlite');
|
|
457
|
+
const commits: StoredCommit[] = [];
|
|
458
|
+
let deliveredChanges = 0;
|
|
459
|
+
let afterSeq = query.afterSeq;
|
|
460
|
+
const batchSize = Math.max(64, query.limitChanges);
|
|
461
|
+
while (deliveredChanges < query.limitChanges) {
|
|
462
|
+
const records = this.db
|
|
463
|
+
.query<SqliteCommitWindowRecord, (string | number)[]>(sql)
|
|
464
|
+
.all(
|
|
465
|
+
partition,
|
|
466
|
+
query.table,
|
|
467
|
+
firstVariable,
|
|
468
|
+
...firstValues,
|
|
469
|
+
afterSeq,
|
|
470
|
+
query.throughSeq,
|
|
471
|
+
batchSize,
|
|
472
|
+
partition,
|
|
473
|
+
partition,
|
|
474
|
+
query.table,
|
|
475
|
+
);
|
|
476
|
+
if (records.length === 0) break;
|
|
477
|
+
const page = collectCommitWindowPage(
|
|
478
|
+
records,
|
|
479
|
+
query.scopeFilter,
|
|
480
|
+
query.limitChanges - deliveredChanges,
|
|
481
|
+
);
|
|
482
|
+
commits.push(...page.commits);
|
|
483
|
+
deliveredChanges += page.delivered;
|
|
484
|
+
afterSeq = page.lastSeq;
|
|
485
|
+
if (page.candidateCount < batchSize) break;
|
|
486
|
+
}
|
|
487
|
+
return commits;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async scanRows(partition: string, query: RowScanQuery): Promise<StoredRow[]> {
|
|
491
|
+
const variables = Object.keys(query.scopeFilter).sort();
|
|
492
|
+
const firstVariable = variables[0];
|
|
493
|
+
if (firstVariable === undefined) return [];
|
|
494
|
+
const firstValues = query.scopeFilter[firstVariable] ?? [];
|
|
495
|
+
if (firstValues.length === 0) return [];
|
|
496
|
+
// Candidates via the inverted index LEFT JOINed to the row table — one
|
|
497
|
+
// statement per page, never one per row (see `scanRowPageSql`). Exact
|
|
498
|
+
// multi-variable verification against the stored scope map below.
|
|
499
|
+
const sql = scanRowPageSql(
|
|
500
|
+
this.table(query.table),
|
|
501
|
+
firstValues.length,
|
|
502
|
+
'sqlite',
|
|
503
|
+
);
|
|
504
|
+
const rows: StoredRow[] = [];
|
|
505
|
+
let afterRowId = query.afterRowId ?? '';
|
|
506
|
+
const batchSize = Math.max(64, query.limit);
|
|
507
|
+
while (rows.length < query.limit) {
|
|
508
|
+
const records = this.db
|
|
509
|
+
.query<
|
|
510
|
+
SqliteRowRecord & { payload: Uint8Array | null },
|
|
511
|
+
(string | number)[]
|
|
512
|
+
>(sql)
|
|
513
|
+
.all(
|
|
514
|
+
partition,
|
|
515
|
+
query.table,
|
|
516
|
+
firstVariable,
|
|
517
|
+
...firstValues,
|
|
518
|
+
afterRowId,
|
|
519
|
+
batchSize,
|
|
520
|
+
partition,
|
|
521
|
+
);
|
|
522
|
+
if (records.length === 0) break;
|
|
523
|
+
for (const record of records) {
|
|
524
|
+
afterRowId = record.row_id;
|
|
525
|
+
// NULL payload: an index candidate whose row vanished — it still
|
|
526
|
+
// advances the keyset cursor (LEFT JOIN contract) but yields no row.
|
|
527
|
+
if (record.payload === null) continue;
|
|
528
|
+
const stored = toStoredRow(record);
|
|
529
|
+
if (!matchesEffective(stored.scopes, query.scopeFilter)) continue;
|
|
530
|
+
rows.push(stored);
|
|
531
|
+
if (rows.length >= query.limit) break;
|
|
532
|
+
}
|
|
533
|
+
if (records.length < batchSize) break;
|
|
534
|
+
}
|
|
535
|
+
return rows;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async getClientRecord(
|
|
539
|
+
partition: string,
|
|
540
|
+
clientId: string,
|
|
541
|
+
): Promise<ClientRecord | undefined> {
|
|
542
|
+
const record = this.db
|
|
543
|
+
.query<
|
|
544
|
+
{
|
|
545
|
+
client_id: string;
|
|
546
|
+
actor_id: string;
|
|
547
|
+
cursor: number;
|
|
548
|
+
subscriptions: string;
|
|
549
|
+
updated_at_ms: number;
|
|
550
|
+
},
|
|
551
|
+
[string, string]
|
|
552
|
+
>(
|
|
553
|
+
'SELECT client_id, actor_id, cursor, subscriptions, updated_at_ms FROM sync_clients WHERE partition=? AND client_id=?',
|
|
554
|
+
)
|
|
555
|
+
.get(partition, clientId);
|
|
556
|
+
if (record === null) return undefined;
|
|
557
|
+
return {
|
|
558
|
+
clientId: record.client_id,
|
|
559
|
+
actorId: record.actor_id,
|
|
560
|
+
cursor: record.cursor,
|
|
561
|
+
updatedAtMs: record.updated_at_ms,
|
|
562
|
+
subscriptions: JSON.parse(record.subscriptions) as ClientSubscription[],
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async putClientRecord(
|
|
567
|
+
partition: string,
|
|
568
|
+
record: ClientRecord,
|
|
569
|
+
): Promise<void> {
|
|
570
|
+
this.db
|
|
571
|
+
.query(
|
|
572
|
+
'INSERT OR REPLACE INTO sync_clients(partition, client_id, actor_id, cursor, subscriptions, updated_at_ms) VALUES (?,?,?,?,?,?)',
|
|
573
|
+
)
|
|
574
|
+
.run(
|
|
575
|
+
partition,
|
|
576
|
+
record.clientId,
|
|
577
|
+
record.actorId,
|
|
578
|
+
record.cursor,
|
|
579
|
+
JSON.stringify(record.subscriptions),
|
|
580
|
+
record.updatedAtMs,
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async listClientCursors(partition: string): Promise<ClientCursorInfo[]> {
|
|
585
|
+
const records = this.db
|
|
586
|
+
.query<
|
|
587
|
+
{ client_id: string; cursor: number; updated_at_ms: number },
|
|
588
|
+
[string]
|
|
589
|
+
>(
|
|
590
|
+
'SELECT client_id, cursor, updated_at_ms FROM sync_clients WHERE partition=?',
|
|
591
|
+
)
|
|
592
|
+
.all(partition);
|
|
593
|
+
return records.map((r) => ({
|
|
594
|
+
clientId: r.client_id,
|
|
595
|
+
cursor: r.cursor,
|
|
596
|
+
updatedAtMs: r.updated_at_ms,
|
|
597
|
+
}));
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
async listRowsReferencingBlob(
|
|
601
|
+
partition: string,
|
|
602
|
+
blobId: string,
|
|
603
|
+
): Promise<
|
|
604
|
+
{
|
|
605
|
+
readonly table: string;
|
|
606
|
+
readonly rowId: string;
|
|
607
|
+
readonly scopes: Record<string, string>;
|
|
608
|
+
}[]
|
|
609
|
+
> {
|
|
610
|
+
// Candidate rows via the by-blob index (§5.9.4/§5.9.5); each row's
|
|
611
|
+
// stored scopes come from sync_rows for the §3.4 authorization test.
|
|
612
|
+
const refs = this.db
|
|
613
|
+
.query<{ tbl: string; row_id: string }, [string, string]>(
|
|
614
|
+
'SELECT tbl, row_id FROM sync_blob_refs WHERE partition=? AND blob_id=?',
|
|
615
|
+
)
|
|
616
|
+
.all(partition, blobId);
|
|
617
|
+
const out: {
|
|
618
|
+
table: string;
|
|
619
|
+
rowId: string;
|
|
620
|
+
scopes: Record<string, string>;
|
|
621
|
+
}[] = [];
|
|
622
|
+
for (const ref of refs) {
|
|
623
|
+
const compiled = this.#tables?.get(ref.tbl);
|
|
624
|
+
if (compiled === undefined) continue; // table no longer in the schema
|
|
625
|
+
const row = this.db
|
|
626
|
+
.query<{ scopes: string }, [string, string]>(
|
|
627
|
+
selectRowScopesSql(compiled, 'sqlite'),
|
|
628
|
+
)
|
|
629
|
+
.get(partition, ref.row_id);
|
|
630
|
+
if (row === null) continue;
|
|
631
|
+
out.push({
|
|
632
|
+
table: ref.tbl,
|
|
633
|
+
rowId: ref.row_id,
|
|
634
|
+
scopes: JSON.parse(row.scopes) as Record<string, string>,
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
return out;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
async listReferencedBlobIds(partition: string): Promise<string[]> {
|
|
641
|
+
const rows = this.db
|
|
642
|
+
.query<{ blob_id: string }, [string]>(
|
|
643
|
+
'SELECT DISTINCT blob_id FROM sync_blob_refs WHERE partition=?',
|
|
644
|
+
)
|
|
645
|
+
.all(partition);
|
|
646
|
+
return rows.map((r) => r.blob_id);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// -- admin/console read surface (TODO §2.5) --------------------------------
|
|
650
|
+
|
|
651
|
+
async listClientRecords(partition: string): Promise<ClientRecord[]> {
|
|
652
|
+
const records = this.db
|
|
653
|
+
.query<
|
|
654
|
+
{
|
|
655
|
+
client_id: string;
|
|
656
|
+
actor_id: string;
|
|
657
|
+
cursor: number;
|
|
658
|
+
subscriptions: string;
|
|
659
|
+
updated_at_ms: number;
|
|
660
|
+
},
|
|
661
|
+
[string]
|
|
662
|
+
>(
|
|
663
|
+
'SELECT client_id, actor_id, cursor, subscriptions, updated_at_ms FROM sync_clients WHERE partition=? ORDER BY updated_at_ms DESC',
|
|
664
|
+
)
|
|
665
|
+
.all(partition);
|
|
666
|
+
return records.map((record) => ({
|
|
667
|
+
clientId: record.client_id,
|
|
668
|
+
actorId: record.actor_id,
|
|
669
|
+
cursor: record.cursor,
|
|
670
|
+
updatedAtMs: record.updated_at_ms,
|
|
671
|
+
subscriptions: JSON.parse(record.subscriptions) as ClientSubscription[],
|
|
672
|
+
}));
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async listCommitMetadata(
|
|
676
|
+
partition: string,
|
|
677
|
+
query: CommitMetadataQuery,
|
|
678
|
+
): Promise<CommitMetadata[]> {
|
|
679
|
+
// Newest-first window, resumed by `afterSeq` (exclusive lower bound).
|
|
680
|
+
const rows = query.table
|
|
681
|
+
? this.db
|
|
682
|
+
.query<
|
|
683
|
+
{
|
|
684
|
+
commit_seq: number;
|
|
685
|
+
client_id: string;
|
|
686
|
+
client_commit_id: string;
|
|
687
|
+
actor_id: string;
|
|
688
|
+
created_at_ms: number;
|
|
689
|
+
},
|
|
690
|
+
[string, number, string, number]
|
|
691
|
+
>(
|
|
692
|
+
`SELECT c.commit_seq, c.client_id, c.client_commit_id, c.actor_id, c.created_at_ms
|
|
693
|
+
FROM sync_commits c
|
|
694
|
+
WHERE c.partition=? AND c.commit_seq>?
|
|
695
|
+
AND EXISTS (SELECT 1 FROM sync_changes ch
|
|
696
|
+
WHERE ch.partition=c.partition AND ch.commit_seq=c.commit_seq AND ch.tbl=?)
|
|
697
|
+
ORDER BY c.commit_seq DESC LIMIT ?`,
|
|
698
|
+
)
|
|
699
|
+
.all(partition, query.afterSeq, query.table, query.limit)
|
|
700
|
+
: this.db
|
|
701
|
+
.query<
|
|
702
|
+
{
|
|
703
|
+
commit_seq: number;
|
|
704
|
+
client_id: string;
|
|
705
|
+
client_commit_id: string;
|
|
706
|
+
actor_id: string;
|
|
707
|
+
created_at_ms: number;
|
|
708
|
+
},
|
|
709
|
+
[string, number, number]
|
|
710
|
+
>(
|
|
711
|
+
`SELECT commit_seq, client_id, client_commit_id, actor_id, created_at_ms
|
|
712
|
+
FROM sync_commits
|
|
713
|
+
WHERE partition=? AND commit_seq>?
|
|
714
|
+
ORDER BY commit_seq DESC LIMIT ?`,
|
|
715
|
+
)
|
|
716
|
+
.all(partition, query.afterSeq, query.limit);
|
|
717
|
+
return rows.map((row) => {
|
|
718
|
+
const changes = this.db
|
|
719
|
+
.query<{ tbl: string; n: number }, [string, number]>(
|
|
720
|
+
'SELECT tbl, count(*) AS n FROM sync_changes WHERE partition=? AND commit_seq=? GROUP BY tbl',
|
|
721
|
+
)
|
|
722
|
+
.all(partition, row.commit_seq);
|
|
723
|
+
return {
|
|
724
|
+
commitSeq: row.commit_seq,
|
|
725
|
+
clientId: row.client_id,
|
|
726
|
+
clientCommitId: row.client_commit_id,
|
|
727
|
+
actorId: row.actor_id,
|
|
728
|
+
createdAtMs: row.created_at_ms,
|
|
729
|
+
changeCount: changes.reduce((sum, c) => sum + c.n, 0),
|
|
730
|
+
tables: changes.map((c) => c.tbl),
|
|
731
|
+
};
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
async scopeActivity(
|
|
736
|
+
partition: string,
|
|
737
|
+
query: ScopeActivityQuery,
|
|
738
|
+
): Promise<ScopeCommitActivity[]> {
|
|
739
|
+
// Candidate commits via the change-scope index (§3.1) — never a scan.
|
|
740
|
+
const rows = this.db
|
|
741
|
+
.query<
|
|
742
|
+
{ commit_seq: number; tbl: string },
|
|
743
|
+
[string, string, string, number]
|
|
744
|
+
>(
|
|
745
|
+
`SELECT DISTINCT commit_seq, tbl FROM sync_change_scopes
|
|
746
|
+
WHERE partition=? AND var=? AND value=?
|
|
747
|
+
ORDER BY commit_seq DESC LIMIT ?`,
|
|
748
|
+
)
|
|
749
|
+
.all(partition, query.variable, query.value, query.limit);
|
|
750
|
+
const out: ScopeCommitActivity[] = [];
|
|
751
|
+
for (const row of rows) {
|
|
752
|
+
const meta = this.db
|
|
753
|
+
.query<{ actor_id: string; created_at_ms: number }, [string, number]>(
|
|
754
|
+
'SELECT actor_id, created_at_ms FROM sync_commits WHERE partition=? AND commit_seq=?',
|
|
755
|
+
)
|
|
756
|
+
.get(partition, row.commit_seq);
|
|
757
|
+
if (meta === null) continue;
|
|
758
|
+
const count = this.db
|
|
759
|
+
.query<{ n: number }, [string, number, string]>(
|
|
760
|
+
'SELECT count(*) AS n FROM sync_changes WHERE partition=? AND commit_seq=? AND tbl=?',
|
|
761
|
+
)
|
|
762
|
+
.get(partition, row.commit_seq, row.tbl);
|
|
763
|
+
out.push({
|
|
764
|
+
commitSeq: row.commit_seq,
|
|
765
|
+
table: row.tbl,
|
|
766
|
+
createdAtMs: meta.created_at_ms,
|
|
767
|
+
actorId: meta.actor_id,
|
|
768
|
+
changeCount: count?.n ?? 0,
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
return out;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async getRowScopes(
|
|
775
|
+
partition: string,
|
|
776
|
+
table: string,
|
|
777
|
+
rowId: string,
|
|
778
|
+
): Promise<
|
|
779
|
+
{ serverVersion: number; scopes: Record<string, string> } | undefined
|
|
780
|
+
> {
|
|
781
|
+
const record = this.db
|
|
782
|
+
.query<{ server_version: number; scopes: string }, [string, string]>(
|
|
783
|
+
selectRowScopesSql(this.table(table), 'sqlite'),
|
|
784
|
+
)
|
|
785
|
+
.get(partition, rowId);
|
|
786
|
+
if (record === null) return undefined;
|
|
787
|
+
return {
|
|
788
|
+
serverVersion: record.server_version,
|
|
789
|
+
scopes: JSON.parse(record.scopes) as Record<string, string>,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
}
|