@syncular/server 0.0.1-100

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.
Files changed (225) hide show
  1. package/dist/blobs/adapters/database.d.ts +83 -0
  2. package/dist/blobs/adapters/database.d.ts.map +1 -0
  3. package/dist/blobs/adapters/database.js +202 -0
  4. package/dist/blobs/adapters/database.js.map +1 -0
  5. package/dist/blobs/adapters/s3.d.ts +82 -0
  6. package/dist/blobs/adapters/s3.d.ts.map +1 -0
  7. package/dist/blobs/adapters/s3.js +170 -0
  8. package/dist/blobs/adapters/s3.js.map +1 -0
  9. package/dist/blobs/index.d.ts +9 -0
  10. package/dist/blobs/index.d.ts.map +1 -0
  11. package/dist/blobs/index.js +9 -0
  12. package/dist/blobs/index.js.map +1 -0
  13. package/dist/blobs/manager.d.ts +195 -0
  14. package/dist/blobs/manager.d.ts.map +1 -0
  15. package/dist/blobs/manager.js +440 -0
  16. package/dist/blobs/manager.js.map +1 -0
  17. package/dist/blobs/migrate.d.ts +27 -0
  18. package/dist/blobs/migrate.d.ts.map +1 -0
  19. package/dist/blobs/migrate.js +119 -0
  20. package/dist/blobs/migrate.js.map +1 -0
  21. package/dist/blobs/types.d.ts +54 -0
  22. package/dist/blobs/types.d.ts.map +1 -0
  23. package/dist/blobs/types.js +5 -0
  24. package/dist/blobs/types.js.map +1 -0
  25. package/dist/clients.d.ts +14 -0
  26. package/dist/clients.d.ts.map +1 -0
  27. package/dist/clients.js +7 -0
  28. package/dist/clients.js.map +1 -0
  29. package/dist/compaction.d.ts +27 -0
  30. package/dist/compaction.d.ts.map +1 -0
  31. package/dist/compaction.js +49 -0
  32. package/dist/compaction.js.map +1 -0
  33. package/dist/dialect/base.d.ts +83 -0
  34. package/dist/dialect/base.d.ts.map +1 -0
  35. package/dist/dialect/base.js +144 -0
  36. package/dist/dialect/base.js.map +1 -0
  37. package/dist/dialect/helpers.d.ts +10 -0
  38. package/dist/dialect/helpers.d.ts.map +1 -0
  39. package/dist/dialect/helpers.js +59 -0
  40. package/dist/dialect/helpers.js.map +1 -0
  41. package/dist/dialect/index.d.ts +7 -0
  42. package/dist/dialect/index.d.ts.map +1 -0
  43. package/dist/dialect/index.js +7 -0
  44. package/dist/dialect/index.js.map +1 -0
  45. package/dist/dialect/types.d.ts +149 -0
  46. package/dist/dialect/types.d.ts.map +1 -0
  47. package/dist/dialect/types.js +8 -0
  48. package/dist/dialect/types.js.map +1 -0
  49. package/dist/helpers/conflict.d.ts +52 -0
  50. package/dist/helpers/conflict.d.ts.map +1 -0
  51. package/dist/helpers/conflict.js +49 -0
  52. package/dist/helpers/conflict.js.map +1 -0
  53. package/dist/helpers/emitted-change.d.ts +56 -0
  54. package/dist/helpers/emitted-change.d.ts.map +1 -0
  55. package/dist/helpers/emitted-change.js +46 -0
  56. package/dist/helpers/emitted-change.js.map +1 -0
  57. package/dist/helpers/index.d.ts +10 -0
  58. package/dist/helpers/index.d.ts.map +1 -0
  59. package/dist/helpers/index.js +10 -0
  60. package/dist/helpers/index.js.map +1 -0
  61. package/dist/helpers/paginate.d.ts +49 -0
  62. package/dist/helpers/paginate.d.ts.map +1 -0
  63. package/dist/helpers/paginate.js +54 -0
  64. package/dist/helpers/paginate.js.map +1 -0
  65. package/dist/helpers/scope-strings.d.ts +74 -0
  66. package/dist/helpers/scope-strings.d.ts.map +1 -0
  67. package/dist/helpers/scope-strings.js +82 -0
  68. package/dist/helpers/scope-strings.js.map +1 -0
  69. package/dist/index.d.ts +28 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +27 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/migrate.d.ts +14 -0
  74. package/dist/migrate.d.ts.map +1 -0
  75. package/dist/migrate.js +13 -0
  76. package/dist/migrate.js.map +1 -0
  77. package/dist/proxy/handler.d.ts +42 -0
  78. package/dist/proxy/handler.d.ts.map +1 -0
  79. package/dist/proxy/handler.js +102 -0
  80. package/dist/proxy/handler.js.map +1 -0
  81. package/dist/proxy/index.d.ts +9 -0
  82. package/dist/proxy/index.d.ts.map +1 -0
  83. package/dist/proxy/index.js +14 -0
  84. package/dist/proxy/index.js.map +1 -0
  85. package/dist/proxy/mutation-detector.d.ts +35 -0
  86. package/dist/proxy/mutation-detector.d.ts.map +1 -0
  87. package/dist/proxy/mutation-detector.js +246 -0
  88. package/dist/proxy/mutation-detector.js.map +1 -0
  89. package/dist/proxy/oplog.d.ts +30 -0
  90. package/dist/proxy/oplog.d.ts.map +1 -0
  91. package/dist/proxy/oplog.js +110 -0
  92. package/dist/proxy/oplog.js.map +1 -0
  93. package/dist/proxy/registry.d.ts +35 -0
  94. package/dist/proxy/registry.d.ts.map +1 -0
  95. package/dist/proxy/registry.js +49 -0
  96. package/dist/proxy/registry.js.map +1 -0
  97. package/dist/proxy/types.d.ts +44 -0
  98. package/dist/proxy/types.d.ts.map +1 -0
  99. package/dist/proxy/types.js +7 -0
  100. package/dist/proxy/types.js.map +1 -0
  101. package/dist/prune.d.ts +37 -0
  102. package/dist/prune.d.ts.map +1 -0
  103. package/dist/prune.js +112 -0
  104. package/dist/prune.js.map +1 -0
  105. package/dist/pull.d.ts +31 -0
  106. package/dist/pull.d.ts.map +1 -0
  107. package/dist/pull.js +608 -0
  108. package/dist/pull.js.map +1 -0
  109. package/dist/push.d.ts +33 -0
  110. package/dist/push.d.ts.map +1 -0
  111. package/dist/push.js +412 -0
  112. package/dist/push.js.map +1 -0
  113. package/dist/realtime/in-memory.d.ts +13 -0
  114. package/dist/realtime/in-memory.d.ts.map +1 -0
  115. package/dist/realtime/in-memory.js +28 -0
  116. package/dist/realtime/in-memory.js.map +1 -0
  117. package/dist/realtime/index.d.ts +3 -0
  118. package/dist/realtime/index.d.ts.map +1 -0
  119. package/dist/realtime/index.js +2 -0
  120. package/dist/realtime/index.js.map +1 -0
  121. package/dist/realtime/types.d.ts +50 -0
  122. package/dist/realtime/types.d.ts.map +1 -0
  123. package/dist/realtime/types.js +7 -0
  124. package/dist/realtime/types.js.map +1 -0
  125. package/dist/schema.d.ts +164 -0
  126. package/dist/schema.d.ts.map +1 -0
  127. package/dist/schema.js +10 -0
  128. package/dist/schema.js.map +1 -0
  129. package/dist/shapes/create-handler.d.ts +119 -0
  130. package/dist/shapes/create-handler.d.ts.map +1 -0
  131. package/dist/shapes/create-handler.js +327 -0
  132. package/dist/shapes/create-handler.js.map +1 -0
  133. package/dist/shapes/index.d.ts +4 -0
  134. package/dist/shapes/index.d.ts.map +1 -0
  135. package/dist/shapes/index.js +4 -0
  136. package/dist/shapes/index.js.map +1 -0
  137. package/dist/shapes/registry.d.ts +20 -0
  138. package/dist/shapes/registry.d.ts.map +1 -0
  139. package/dist/shapes/registry.js +88 -0
  140. package/dist/shapes/registry.js.map +1 -0
  141. package/dist/shapes/types.d.ts +204 -0
  142. package/dist/shapes/types.d.ts.map +1 -0
  143. package/dist/shapes/types.js +2 -0
  144. package/dist/shapes/types.js.map +1 -0
  145. package/dist/snapshot-chunks/adapters/s3.d.ts +74 -0
  146. package/dist/snapshot-chunks/adapters/s3.d.ts.map +1 -0
  147. package/dist/snapshot-chunks/adapters/s3.js +50 -0
  148. package/dist/snapshot-chunks/adapters/s3.js.map +1 -0
  149. package/dist/snapshot-chunks/db-metadata.d.ts +38 -0
  150. package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -0
  151. package/dist/snapshot-chunks/db-metadata.js +324 -0
  152. package/dist/snapshot-chunks/db-metadata.js.map +1 -0
  153. package/dist/snapshot-chunks/index.d.ts +9 -0
  154. package/dist/snapshot-chunks/index.d.ts.map +1 -0
  155. package/dist/snapshot-chunks/index.js +9 -0
  156. package/dist/snapshot-chunks/index.js.map +1 -0
  157. package/dist/snapshot-chunks/types.d.ts +78 -0
  158. package/dist/snapshot-chunks/types.d.ts.map +1 -0
  159. package/dist/snapshot-chunks/types.js +8 -0
  160. package/dist/snapshot-chunks/types.js.map +1 -0
  161. package/dist/snapshot-chunks.d.ts +60 -0
  162. package/dist/snapshot-chunks.d.ts.map +1 -0
  163. package/dist/snapshot-chunks.js +223 -0
  164. package/dist/snapshot-chunks.js.map +1 -0
  165. package/dist/stats.d.ts +19 -0
  166. package/dist/stats.d.ts.map +1 -0
  167. package/dist/stats.js +57 -0
  168. package/dist/stats.js.map +1 -0
  169. package/dist/subscriptions/index.d.ts +2 -0
  170. package/dist/subscriptions/index.d.ts.map +1 -0
  171. package/dist/subscriptions/index.js +2 -0
  172. package/dist/subscriptions/index.js.map +1 -0
  173. package/dist/subscriptions/resolve.d.ts +35 -0
  174. package/dist/subscriptions/resolve.d.ts.map +1 -0
  175. package/dist/subscriptions/resolve.js +134 -0
  176. package/dist/subscriptions/resolve.js.map +1 -0
  177. package/package.json +80 -0
  178. package/src/blobs/adapters/database.test.ts +67 -0
  179. package/src/blobs/adapters/database.ts +315 -0
  180. package/src/blobs/adapters/s3.ts +271 -0
  181. package/src/blobs/index.ts +9 -0
  182. package/src/blobs/manager.ts +600 -0
  183. package/src/blobs/migrate.ts +150 -0
  184. package/src/blobs/types.ts +70 -0
  185. package/src/clients.ts +21 -0
  186. package/src/compaction.ts +77 -0
  187. package/src/dialect/base.ts +292 -0
  188. package/src/dialect/helpers.ts +61 -0
  189. package/src/dialect/index.ts +7 -0
  190. package/src/dialect/types.ts +197 -0
  191. package/src/helpers/conflict.ts +64 -0
  192. package/src/helpers/emitted-change.ts +69 -0
  193. package/src/helpers/index.ts +10 -0
  194. package/src/helpers/paginate.ts +82 -0
  195. package/src/helpers/scope-strings.ts +101 -0
  196. package/src/index.ts +28 -0
  197. package/src/migrate.ts +20 -0
  198. package/src/proxy/handler.test.ts +120 -0
  199. package/src/proxy/handler.ts +159 -0
  200. package/src/proxy/index.ts +18 -0
  201. package/src/proxy/mutation-detector.test.ts +71 -0
  202. package/src/proxy/mutation-detector.ts +281 -0
  203. package/src/proxy/oplog.ts +146 -0
  204. package/src/proxy/registry.ts +56 -0
  205. package/src/proxy/types.ts +46 -0
  206. package/src/prune.ts +200 -0
  207. package/src/pull.ts +858 -0
  208. package/src/push.ts +583 -0
  209. package/src/realtime/in-memory.ts +33 -0
  210. package/src/realtime/index.ts +5 -0
  211. package/src/realtime/types.ts +55 -0
  212. package/src/schema.ts +172 -0
  213. package/src/shapes/create-handler.ts +590 -0
  214. package/src/shapes/index.ts +3 -0
  215. package/src/shapes/registry.ts +109 -0
  216. package/src/shapes/types.ts +267 -0
  217. package/src/snapshot-chunks/adapters/s3.ts +68 -0
  218. package/src/snapshot-chunks/db-metadata.test.ts +100 -0
  219. package/src/snapshot-chunks/db-metadata.ts +466 -0
  220. package/src/snapshot-chunks/index.ts +9 -0
  221. package/src/snapshot-chunks/types.ts +103 -0
  222. package/src/snapshot-chunks.ts +329 -0
  223. package/src/stats.ts +104 -0
  224. package/src/subscriptions/index.ts +1 -0
  225. package/src/subscriptions/resolve.ts +185 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dialect/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @syncular/server - Dialect exports
3
+ */
4
+ export * from './base.js';
5
+ export * from './helpers.js';
6
+ export * from './types.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dialect/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @syncular/server - Server Sync Dialect Interface
3
+ *
4
+ * Abstracts database-specific operations for commit-log sync.
5
+ * Supports the new JSONB scopes model.
6
+ */
7
+ import type { ScopeValues, StoredScopes, SyncOp } from '@syncular/core';
8
+ import type { Kysely, Transaction } from 'kysely';
9
+ import type { SyncChangeRow, SyncCommitRow, SyncCoreDb } from '../schema';
10
+ /**
11
+ * Common database executor type that works with both Kysely and Transaction.
12
+ * Generic version allows for extended database types that include sync tables.
13
+ */
14
+ export type DbExecutor<DB extends SyncCoreDb = SyncCoreDb> = Kysely<DB> | Transaction<DB>;
15
+ /**
16
+ * Supported dialect names.
17
+ */
18
+ export type ServerSyncDialectName = string;
19
+ export interface IncrementalPullRowsArgs {
20
+ table: string;
21
+ scopes: ScopeValues;
22
+ cursor: number;
23
+ limitCommits: number;
24
+ partitionId?: string;
25
+ batchSize?: number;
26
+ }
27
+ export interface IncrementalPullRow {
28
+ commit_seq: number;
29
+ actor_id: string;
30
+ created_at: string;
31
+ change_id: number;
32
+ table: string;
33
+ row_id: string;
34
+ op: SyncOp;
35
+ row_json: unknown | null;
36
+ row_version: number | null;
37
+ scopes: StoredScopes;
38
+ }
39
+ export interface ServerSyncDialect {
40
+ readonly name: ServerSyncDialectName;
41
+ /** Create sync tables + indexes (idempotent) */
42
+ ensureSyncSchema<DB extends SyncCoreDb>(db: Kysely<DB>): Promise<void>;
43
+ /** Create console-specific tables (e.g., sync_request_events) - optional */
44
+ ensureConsoleSchema?<DB extends SyncCoreDb>(db: Kysely<DB>): Promise<void>;
45
+ /** Execute callback in a transaction (or directly if transactions not supported). */
46
+ executeInTransaction<DB extends SyncCoreDb, T>(db: Kysely<DB>, fn: (executor: DbExecutor<DB>) => Promise<T>): Promise<T>;
47
+ /** Set REPEATABLE READ (or closest equivalent) */
48
+ setRepeatableRead<DB extends SyncCoreDb>(trx: DbExecutor<DB>): Promise<void>;
49
+ /** Read the maximum committed commit_seq (0 if none) */
50
+ readMaxCommitSeq<DB extends SyncCoreDb>(db: DbExecutor<DB>, options?: {
51
+ partitionId?: string;
52
+ }): Promise<number>;
53
+ /** Read the minimum committed commit_seq (0 if none) */
54
+ readMinCommitSeq<DB extends SyncCoreDb>(db: DbExecutor<DB>, options?: {
55
+ partitionId?: string;
56
+ }): Promise<number>;
57
+ /**
58
+ * Read the next commit sequence numbers that have changes for the given tables.
59
+ * Must return commit_seq values in ascending order.
60
+ */
61
+ readCommitSeqsForPull<DB extends SyncCoreDb>(db: DbExecutor<DB>, args: {
62
+ cursor: number;
63
+ limitCommits: number;
64
+ tables: string[];
65
+ partitionId?: string;
66
+ }): Promise<number[]>;
67
+ /** Read commit metadata for commit_seq values */
68
+ readCommits<DB extends SyncCoreDb>(db: DbExecutor<DB>, commitSeqs: number[], options?: {
69
+ partitionId?: string;
70
+ }): Promise<SyncCommitRow[]>;
71
+ /**
72
+ * Read changes for commit_seq values, filtered by table and scopes.
73
+ * Uses JSONB filtering for scope matching.
74
+ */
75
+ readChangesForCommits<DB extends SyncCoreDb>(db: DbExecutor<DB>, args: {
76
+ commitSeqs: number[];
77
+ table: string;
78
+ scopes: ScopeValues;
79
+ partitionId?: string;
80
+ }): Promise<SyncChangeRow[]>;
81
+ /**
82
+ * Incremental pull iterator for a subscription.
83
+ *
84
+ * Yields change rows joined with commit metadata and filtered by
85
+ * the subscription's table and scope values.
86
+ */
87
+ iterateIncrementalPullRows<DB extends SyncCoreDb>(db: DbExecutor<DB>, args: IncrementalPullRowsArgs): AsyncGenerator<IncrementalPullRow>;
88
+ /**
89
+ * Optional compaction of the change log to reduce storage.
90
+ *
91
+ * Keeps full history for the most recent N hours.
92
+ * For older history, keeps only the newest change per (table, row_id, scopes).
93
+ */
94
+ compactChanges<DB extends SyncCoreDb>(db: DbExecutor<DB>, args: {
95
+ fullHistoryHours: number;
96
+ }): Promise<number>;
97
+ /**
98
+ * Record/update a client cursor for tracking and pruning.
99
+ */
100
+ recordClientCursor<DB extends SyncCoreDb>(db: DbExecutor<DB>, args: {
101
+ partitionId?: string;
102
+ clientId: string;
103
+ actorId: string;
104
+ cursor: number;
105
+ effectiveScopes: ScopeValues;
106
+ }): Promise<void>;
107
+ /**
108
+ * Convert a StoredScopes object to database representation.
109
+ * For Postgres: returns as-is (native JSONB)
110
+ * For SQLite: returns JSON.stringify()
111
+ */
112
+ scopesToDb(scopes: StoredScopes): unknown;
113
+ /**
114
+ * Convert database scopes representation to StoredScopes.
115
+ */
116
+ dbToScopes(value: unknown): StoredScopes;
117
+ /**
118
+ * Whether the dialect supports SELECT ... FOR UPDATE row locking.
119
+ * Postgres: true
120
+ * SQLite: false (uses database-level locking)
121
+ */
122
+ readonly supportsForUpdate: boolean;
123
+ /**
124
+ * Whether the dialect supports SAVEPOINT / ROLLBACK TO SAVEPOINT.
125
+ * Postgres/SQLite: true
126
+ * D1 (Durable Object): false (blocks raw SAVEPOINT statements)
127
+ */
128
+ readonly supportsSavepoints: boolean;
129
+ /**
130
+ * Read distinct tables from sync_changes for a given commit.
131
+ * Used for realtime notifications.
132
+ */
133
+ readAffectedTablesFromChanges<DB extends SyncCoreDb>(db: DbExecutor<DB>, commitSeq: number, options?: {
134
+ partitionId?: string;
135
+ }): Promise<string[]>;
136
+ /**
137
+ * Convert database array representation to string[].
138
+ * For Postgres: returns as-is (native array)
139
+ * For SQLite: returns JSON.parse() or empty array if null
140
+ */
141
+ dbToArray(value: unknown): string[];
142
+ /**
143
+ * Convert string[] to database array representation.
144
+ * For Postgres: returns as-is (native array)
145
+ * For SQLite: returns JSON.stringify()
146
+ */
147
+ arrayToDb(values: string[]): unknown;
148
+ }
149
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dialect/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @syncular/server - Server Sync Dialect Interface
3
+ *
4
+ * Abstracts database-specific operations for commit-log sync.
5
+ * Supports the new JSONB scopes model.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dialect/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @syncular/server - Conflict result builder
3
+ *
4
+ * Helper for building conflict results in server table handlers.
5
+ */
6
+ import type { ApplyOperationResult } from '../shapes/types';
7
+ export interface BuildConflictResultArgs {
8
+ /** Index of the operation in the batch */
9
+ opIndex: number;
10
+ /** Current server row data */
11
+ serverRow: unknown;
12
+ /** Current server version */
13
+ serverVersion: number;
14
+ /** Client's base version (what they thought they were updating) */
15
+ baseVersion: number | null;
16
+ }
17
+ /**
18
+ * Build a conflict result for applyOperation.
19
+ *
20
+ * Use this when the client's base version doesn't match the server's current version,
21
+ * indicating a concurrent modification conflict.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const handler: ServerTableHandler = {
26
+ * table: 'tasks',
27
+ * async applyOperation(ctx, op, opIndex) {
28
+ * const existing = await ctx.db
29
+ * .selectFrom('tasks')
30
+ * .selectAll()
31
+ * .where('id', '=', op.row_id)
32
+ * .executeTakeFirst();
33
+ *
34
+ * // Check for version conflict
35
+ * if (existing && op.base_version !== null && existing.version !== op.base_version) {
36
+ * return {
37
+ * result: buildConflictResult({
38
+ * opIndex,
39
+ * serverRow: existing,
40
+ * serverVersion: existing.version,
41
+ * baseVersion: op.base_version,
42
+ * }),
43
+ * };
44
+ * }
45
+ *
46
+ * // ... apply the operation
47
+ * },
48
+ * };
49
+ * ```
50
+ */
51
+ export declare function buildConflictResult(args: BuildConflictResultArgs): ApplyOperationResult['result'];
52
+ //# sourceMappingURL=conflict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict.d.ts","sourceRoot":"","sources":["../../src/helpers/conflict.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,uBAAuB,GAC5B,oBAAoB,CAAC,QAAQ,CAAC,CAQhC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @syncular/server - Conflict result builder
3
+ *
4
+ * Helper for building conflict results in server table handlers.
5
+ */
6
+ /**
7
+ * Build a conflict result for applyOperation.
8
+ *
9
+ * Use this when the client's base version doesn't match the server's current version,
10
+ * indicating a concurrent modification conflict.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const handler: ServerTableHandler = {
15
+ * table: 'tasks',
16
+ * async applyOperation(ctx, op, opIndex) {
17
+ * const existing = await ctx.db
18
+ * .selectFrom('tasks')
19
+ * .selectAll()
20
+ * .where('id', '=', op.row_id)
21
+ * .executeTakeFirst();
22
+ *
23
+ * // Check for version conflict
24
+ * if (existing && op.base_version !== null && existing.version !== op.base_version) {
25
+ * return {
26
+ * result: buildConflictResult({
27
+ * opIndex,
28
+ * serverRow: existing,
29
+ * serverVersion: existing.version,
30
+ * baseVersion: op.base_version,
31
+ * }),
32
+ * };
33
+ * }
34
+ *
35
+ * // ... apply the operation
36
+ * },
37
+ * };
38
+ * ```
39
+ */
40
+ export function buildConflictResult(args) {
41
+ return {
42
+ opIndex: args.opIndex,
43
+ status: 'conflict',
44
+ message: `Version conflict: server=${args.serverVersion}, base=${args.baseVersion}`,
45
+ server_version: args.serverVersion,
46
+ server_row: args.serverRow,
47
+ };
48
+ }
49
+ //# sourceMappingURL=conflict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict.js","sourceRoot":"","sources":["../../src/helpers/conflict.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA6B,EACG;IAChC,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,4BAA4B,IAAI,CAAC,aAAa,UAAU,IAAI,CAAC,WAAW,EAAE;QACnF,cAAc,EAAE,IAAI,CAAC,aAAa;QAClC,UAAU,EAAE,IAAI,CAAC,SAAS;KAC3B,CAAC;AAAA,CACH"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @syncular/server - Emitted change builder
3
+ *
4
+ * Helper for creating emitted changes in server table handlers.
5
+ */
6
+ import type { StoredScopes } from '@syncular/core';
7
+ import type { EmittedChange } from '../shapes/types';
8
+ export interface CreateEmittedChangeArgs {
9
+ /** Table name */
10
+ table: string;
11
+ /** Row primary key */
12
+ rowId: string;
13
+ /** Operation type */
14
+ op: 'upsert' | 'delete';
15
+ /** Row data (null for delete) */
16
+ row: unknown | null;
17
+ /** Row version (null if not versioned) */
18
+ version: number | null;
19
+ /**
20
+ * Scope values for this change (stored as JSONB).
21
+ * Example: { user_id: 'U1', project_id: 'P1' }
22
+ */
23
+ scopes: StoredScopes;
24
+ }
25
+ /**
26
+ * Create an emitted change for broadcasting to subscribed clients.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const handler: ServerTableHandler = {
31
+ * table: 'tasks',
32
+ * async applyOperation(ctx, op, opIndex) {
33
+ * // ... apply the operation ...
34
+ *
35
+ * const newVersion = await getTaskVersion(ctx.db, op.row_id);
36
+ * const updatedRow = await getTask(ctx.db, op.row_id);
37
+ *
38
+ * return {
39
+ * result: { opIndex, status: 'applied', newVersion },
40
+ * emittedChanges: [
41
+ * createEmittedChange({
42
+ * table: 'tasks',
43
+ * rowId: op.row_id,
44
+ * op: 'upsert',
45
+ * row: updatedRow,
46
+ * version: newVersion,
47
+ * scopes: { user_id: updatedRow.user_id },
48
+ * }),
49
+ * ],
50
+ * };
51
+ * },
52
+ * };
53
+ * ```
54
+ */
55
+ export declare function createEmittedChange(args: CreateEmittedChangeArgs): EmittedChange;
56
+ //# sourceMappingURL=emitted-change.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitted-change.d.ts","sourceRoot":"","sources":["../../src/helpers/emitted-change.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,EAAE,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxB,iCAAiC;IACjC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACpB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,uBAAuB,GAC5B,aAAa,CASf"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @syncular/server - Emitted change builder
3
+ *
4
+ * Helper for creating emitted changes in server table handlers.
5
+ */
6
+ /**
7
+ * Create an emitted change for broadcasting to subscribed clients.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const handler: ServerTableHandler = {
12
+ * table: 'tasks',
13
+ * async applyOperation(ctx, op, opIndex) {
14
+ * // ... apply the operation ...
15
+ *
16
+ * const newVersion = await getTaskVersion(ctx.db, op.row_id);
17
+ * const updatedRow = await getTask(ctx.db, op.row_id);
18
+ *
19
+ * return {
20
+ * result: { opIndex, status: 'applied', newVersion },
21
+ * emittedChanges: [
22
+ * createEmittedChange({
23
+ * table: 'tasks',
24
+ * rowId: op.row_id,
25
+ * op: 'upsert',
26
+ * row: updatedRow,
27
+ * version: newVersion,
28
+ * scopes: { user_id: updatedRow.user_id },
29
+ * }),
30
+ * ],
31
+ * };
32
+ * },
33
+ * };
34
+ * ```
35
+ */
36
+ export function createEmittedChange(args) {
37
+ return {
38
+ table: args.table,
39
+ row_id: args.rowId,
40
+ op: args.op,
41
+ row_json: args.op === 'delete' ? null : args.row,
42
+ row_version: args.version,
43
+ scopes: args.scopes,
44
+ };
45
+ }
46
+ //# sourceMappingURL=emitted-change.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitted-change.js","sourceRoot":"","sources":["../../src/helpers/emitted-change.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA6B,EACd;IACf,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,KAAK;QAClB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,QAAQ,EAAE,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;QAChD,WAAW,EAAE,IAAI,CAAC,OAAO;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AAAA,CACH"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @syncular/server - Helper utilities
3
+ *
4
+ * Convenience helpers for implementing server table handlers.
5
+ */
6
+ export * from './conflict';
7
+ export * from './emitted-change';
8
+ export * from './paginate';
9
+ export * from './scope-strings';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @syncular/server - Helper utilities
3
+ *
4
+ * Convenience helpers for implementing server table handlers.
5
+ */
6
+ export * from './conflict.js';
7
+ export * from './emitted-change.js';
8
+ export * from './paginate.js';
9
+ export * from './scope-strings.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @syncular/server - Pagination helper
3
+ *
4
+ * Simplifies cursor-based pagination for snapshot queries.
5
+ */
6
+ import type { SelectQueryBuilder } from 'kysely';
7
+ export interface PaginateOptions {
8
+ /** Cursor value to start from (null for first page) */
9
+ cursor: string | null;
10
+ /** Number of rows per page */
11
+ limit: number;
12
+ /** Column to use for cursor-based pagination (default: 'id') */
13
+ cursorColumn?: string;
14
+ }
15
+ export interface PaginateResult<T> {
16
+ /** Rows for this page */
17
+ rows: T[];
18
+ /** Cursor for next page (null if no more pages) */
19
+ nextCursor: string | null;
20
+ }
21
+ /**
22
+ * Apply cursor-based pagination to a Kysely query.
23
+ *
24
+ * This helper simplifies implementing snapshot pagination by:
25
+ * - Applying cursor filter if provided
26
+ * - Ordering by the cursor column
27
+ * - Fetching limit + 1 to determine if there's a next page
28
+ * - Computing the next cursor
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const handler: ServerTableHandler = {
33
+ * table: 'tasks',
34
+ * async snapshot(ctx) {
35
+ * const query = ctx.db
36
+ * .selectFrom('tasks')
37
+ * .selectAll()
38
+ * .where('user_id', '=', ctx.actorId);
39
+ *
40
+ * return paginate(query, {
41
+ * cursor: ctx.cursor,
42
+ * limit: ctx.limit,
43
+ * });
44
+ * },
45
+ * };
46
+ * ```
47
+ */
48
+ export declare function paginate<T>(query: SelectQueryBuilder<any, any, T>, options: PaginateOptions): Promise<PaginateResult<T>>;
49
+ //# sourceMappingURL=paginate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginate.d.ts","sourceRoot":"","sources":["../../src/helpers/paginate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,yBAAyB;IACzB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,KAAK,EAAE,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EACtC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CA2B5B"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @syncular/server - Pagination helper
3
+ *
4
+ * Simplifies cursor-based pagination for snapshot queries.
5
+ */
6
+ /**
7
+ * Apply cursor-based pagination to a Kysely query.
8
+ *
9
+ * This helper simplifies implementing snapshot pagination by:
10
+ * - Applying cursor filter if provided
11
+ * - Ordering by the cursor column
12
+ * - Fetching limit + 1 to determine if there's a next page
13
+ * - Computing the next cursor
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const handler: ServerTableHandler = {
18
+ * table: 'tasks',
19
+ * async snapshot(ctx) {
20
+ * const query = ctx.db
21
+ * .selectFrom('tasks')
22
+ * .selectAll()
23
+ * .where('user_id', '=', ctx.actorId);
24
+ *
25
+ * return paginate(query, {
26
+ * cursor: ctx.cursor,
27
+ * limit: ctx.limit,
28
+ * });
29
+ * },
30
+ * };
31
+ * ```
32
+ */
33
+ export async function paginate(query, options) {
34
+ const { cursor, limit, cursorColumn = 'id' } = options;
35
+ // Apply cursor filter if resuming from a previous page
36
+ let q = query;
37
+ if (cursor) {
38
+ q = q.where(cursorColumn, '>', cursor);
39
+ }
40
+ // Order by cursor column and fetch limit + 1 to check for more pages
41
+ const rows = await q
42
+ .orderBy(cursorColumn, 'asc')
43
+ .limit(limit + 1)
44
+ .execute();
45
+ // Determine if there are more pages
46
+ const hasMore = rows.length > limit;
47
+ const pageRows = hasMore ? rows.slice(0, limit) : rows;
48
+ // Compute next cursor from last row
49
+ const nextCursor = hasMore
50
+ ? (pageRows[pageRows.length - 1]?.[cursorColumn] ?? null)
51
+ : null;
52
+ return { rows: pageRows, nextCursor };
53
+ }
54
+ //# sourceMappingURL=paginate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginate.js","sourceRoot":"","sources":["../../src/helpers/paginate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAAsC,EACtC,OAAwB,EACI;IAC5B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAEvD,uDAAuD;IACvD,IAAI,CAAC,GAAG,KAAK,CAAC;IACd,IAAI,MAAM,EAAE,CAAC;QACX,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,CAAa,CAAC;IACrD,CAAC;IAED,qEAAqE;IACrE,MAAM,IAAI,GAAG,MAAM,CAAC;SACjB,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC;SAC5B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;SAChB,OAAO,EAAE,CAAC;IAEb,oCAAoC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEvD,oCAAoC;IACpC,MAAM,UAAU,GAAG,OAAO;QACxB,CAAC,CAAC,CAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAA6B,EAAE,CAC5D,YAAY,CACF,IAAI,IAAI,CAAC;QACvB,CAAC,CAAC,IAAI,CAAC;IAET,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AAAA,CACvC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @syncular/server - Scope string utilities
3
+ *
4
+ * Helpers for creating and parsing scope strings.
5
+ * Scope strings identify partitions of data for sync subscriptions.
6
+ */
7
+ /**
8
+ * Result from parsing a scope key
9
+ */
10
+ interface ParsedScopeKey {
11
+ /** The prefix (first segment) */
12
+ prefix: string;
13
+ /** The remaining values (segments after prefix) */
14
+ values: string[];
15
+ }
16
+ /**
17
+ * Create a scope string from a prefix and values.
18
+ *
19
+ * Scope strings use colon separators: `prefix:value1:value2`
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Simple scope string
24
+ * createScopeKey('user', 'alice')
25
+ * // => 'user:alice'
26
+ *
27
+ * // Multi-value scope string
28
+ * createScopeKey('user', 'alice', 'project', 'proj-1')
29
+ * // => 'user:alice:project:proj-1'
30
+ * ```
31
+ */
32
+ export declare function createScopeKey(prefix: string, ...values: string[]): string;
33
+ /**
34
+ * Parse a scope string into its prefix and values.
35
+ *
36
+ * Returns null if the key is invalid or doesn't match the expected prefix.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * // Parse any scope string
41
+ * parseScopeKey('user:alice')
42
+ * // => { prefix: 'user', values: ['alice'] }
43
+ *
44
+ * // Parse with expected prefix
45
+ * parseScopeKey('user:alice', 'user')
46
+ * // => { prefix: 'user', values: ['alice'] }
47
+ *
48
+ * // Returns null if prefix doesn't match
49
+ * parseScopeKey('user:alice', 'project')
50
+ * // => null
51
+ *
52
+ * // Multi-value scope string
53
+ * parseScopeKey('user:alice:project:proj-1')
54
+ * // => { prefix: 'user', values: ['alice', 'project', 'proj-1'] }
55
+ * ```
56
+ */
57
+ export declare function parseScopeKey(key: string, expectedPrefix?: string): ParsedScopeKey | null;
58
+ /**
59
+ * Extract a specific value from a scope string by index.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * // Get first value after prefix
64
+ * getScopeKeyValue('user:alice:project:proj-1', 0)
65
+ * // => 'alice'
66
+ *
67
+ * // Get second value
68
+ * getScopeKeyValue('user:alice:project:proj-1', 2)
69
+ * // => 'proj-1'
70
+ * ```
71
+ */
72
+ export declare function getScopeKeyValue(key: string, valueIndex: number): string | null;
73
+ export type { ParsedScopeKey };
74
+ //# sourceMappingURL=scope-strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-strings.d.ts","sourceRoot":"","sources":["../../src/helpers/scope-strings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,UAAU,cAAc;IACtB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,GACtB,cAAc,GAAG,IAAI,CAWvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAIf;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}