@syncular/client 0.0.1-60

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 (176) hide show
  1. package/dist/blobs/index.d.ts +7 -0
  2. package/dist/blobs/index.d.ts.map +1 -0
  3. package/dist/blobs/index.js +7 -0
  4. package/dist/blobs/index.js.map +1 -0
  5. package/dist/blobs/manager.d.ts +345 -0
  6. package/dist/blobs/manager.d.ts.map +1 -0
  7. package/dist/blobs/manager.js +749 -0
  8. package/dist/blobs/manager.js.map +1 -0
  9. package/dist/blobs/migrate.d.ts +14 -0
  10. package/dist/blobs/migrate.d.ts.map +1 -0
  11. package/dist/blobs/migrate.js +59 -0
  12. package/dist/blobs/migrate.js.map +1 -0
  13. package/dist/blobs/types.d.ts +62 -0
  14. package/dist/blobs/types.d.ts.map +1 -0
  15. package/dist/blobs/types.js +5 -0
  16. package/dist/blobs/types.js.map +1 -0
  17. package/dist/client.d.ts +338 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +834 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/conflicts.d.ts +31 -0
  22. package/dist/conflicts.d.ts.map +1 -0
  23. package/dist/conflicts.js +118 -0
  24. package/dist/conflicts.js.map +1 -0
  25. package/dist/create-client.d.ts +115 -0
  26. package/dist/create-client.d.ts.map +1 -0
  27. package/dist/create-client.js +162 -0
  28. package/dist/create-client.js.map +1 -0
  29. package/dist/engine/SyncEngine.d.ts +215 -0
  30. package/dist/engine/SyncEngine.d.ts.map +1 -0
  31. package/dist/engine/SyncEngine.js +1066 -0
  32. package/dist/engine/SyncEngine.js.map +1 -0
  33. package/dist/engine/index.d.ts +6 -0
  34. package/dist/engine/index.d.ts.map +1 -0
  35. package/dist/engine/index.js +6 -0
  36. package/dist/engine/index.js.map +1 -0
  37. package/dist/engine/types.d.ts +230 -0
  38. package/dist/engine/types.d.ts.map +1 -0
  39. package/dist/engine/types.js +7 -0
  40. package/dist/engine/types.js.map +1 -0
  41. package/dist/handlers/create-handler.d.ts +110 -0
  42. package/dist/handlers/create-handler.d.ts.map +1 -0
  43. package/dist/handlers/create-handler.js +140 -0
  44. package/dist/handlers/create-handler.js.map +1 -0
  45. package/dist/handlers/registry.d.ts +15 -0
  46. package/dist/handlers/registry.d.ts.map +1 -0
  47. package/dist/handlers/registry.js +29 -0
  48. package/dist/handlers/registry.js.map +1 -0
  49. package/dist/handlers/types.d.ts +83 -0
  50. package/dist/handlers/types.d.ts.map +1 -0
  51. package/dist/handlers/types.js +5 -0
  52. package/dist/handlers/types.js.map +1 -0
  53. package/dist/index.d.ts +24 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +24 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/migrate.d.ts +19 -0
  58. package/dist/migrate.d.ts.map +1 -0
  59. package/dist/migrate.js +106 -0
  60. package/dist/migrate.js.map +1 -0
  61. package/dist/mutations.d.ts +138 -0
  62. package/dist/mutations.d.ts.map +1 -0
  63. package/dist/mutations.js +611 -0
  64. package/dist/mutations.js.map +1 -0
  65. package/dist/outbox.d.ts +112 -0
  66. package/dist/outbox.d.ts.map +1 -0
  67. package/dist/outbox.js +304 -0
  68. package/dist/outbox.js.map +1 -0
  69. package/dist/plugins/incrementing-version.d.ts +34 -0
  70. package/dist/plugins/incrementing-version.d.ts.map +1 -0
  71. package/dist/plugins/incrementing-version.js +83 -0
  72. package/dist/plugins/incrementing-version.js.map +1 -0
  73. package/dist/plugins/index.d.ts +3 -0
  74. package/dist/plugins/index.d.ts.map +1 -0
  75. package/dist/plugins/index.js +3 -0
  76. package/dist/plugins/index.js.map +1 -0
  77. package/dist/plugins/types.d.ts +49 -0
  78. package/dist/plugins/types.d.ts.map +1 -0
  79. package/dist/plugins/types.js +15 -0
  80. package/dist/plugins/types.js.map +1 -0
  81. package/dist/proxy/connection.d.ts +33 -0
  82. package/dist/proxy/connection.d.ts.map +1 -0
  83. package/dist/proxy/connection.js +153 -0
  84. package/dist/proxy/connection.js.map +1 -0
  85. package/dist/proxy/dialect.d.ts +46 -0
  86. package/dist/proxy/dialect.d.ts.map +1 -0
  87. package/dist/proxy/dialect.js +58 -0
  88. package/dist/proxy/dialect.js.map +1 -0
  89. package/dist/proxy/driver.d.ts +42 -0
  90. package/dist/proxy/driver.d.ts.map +1 -0
  91. package/dist/proxy/driver.js +78 -0
  92. package/dist/proxy/driver.js.map +1 -0
  93. package/dist/proxy/index.d.ts +10 -0
  94. package/dist/proxy/index.d.ts.map +1 -0
  95. package/dist/proxy/index.js +10 -0
  96. package/dist/proxy/index.js.map +1 -0
  97. package/dist/proxy/mutations.d.ts +9 -0
  98. package/dist/proxy/mutations.d.ts.map +1 -0
  99. package/dist/proxy/mutations.js +11 -0
  100. package/dist/proxy/mutations.js.map +1 -0
  101. package/dist/pull-engine.d.ts +45 -0
  102. package/dist/pull-engine.d.ts.map +1 -0
  103. package/dist/pull-engine.js +391 -0
  104. package/dist/pull-engine.js.map +1 -0
  105. package/dist/push-engine.d.ts +18 -0
  106. package/dist/push-engine.d.ts.map +1 -0
  107. package/dist/push-engine.js +155 -0
  108. package/dist/push-engine.js.map +1 -0
  109. package/dist/query/FingerprintCollector.d.ts +18 -0
  110. package/dist/query/FingerprintCollector.d.ts.map +1 -0
  111. package/dist/query/FingerprintCollector.js +28 -0
  112. package/dist/query/FingerprintCollector.js.map +1 -0
  113. package/dist/query/QueryContext.d.ts +33 -0
  114. package/dist/query/QueryContext.d.ts.map +1 -0
  115. package/dist/query/QueryContext.js +16 -0
  116. package/dist/query/QueryContext.js.map +1 -0
  117. package/dist/query/fingerprint.d.ts +61 -0
  118. package/dist/query/fingerprint.d.ts.map +1 -0
  119. package/dist/query/fingerprint.js +91 -0
  120. package/dist/query/fingerprint.js.map +1 -0
  121. package/dist/query/index.d.ts +7 -0
  122. package/dist/query/index.d.ts.map +1 -0
  123. package/dist/query/index.js +7 -0
  124. package/dist/query/index.js.map +1 -0
  125. package/dist/query/tracked-select.d.ts +18 -0
  126. package/dist/query/tracked-select.d.ts.map +1 -0
  127. package/dist/query/tracked-select.js +90 -0
  128. package/dist/query/tracked-select.js.map +1 -0
  129. package/dist/schema.d.ts +83 -0
  130. package/dist/schema.d.ts.map +1 -0
  131. package/dist/schema.js +7 -0
  132. package/dist/schema.js.map +1 -0
  133. package/dist/sync-loop.d.ts +32 -0
  134. package/dist/sync-loop.d.ts.map +1 -0
  135. package/dist/sync-loop.js +249 -0
  136. package/dist/sync-loop.js.map +1 -0
  137. package/dist/utils/id.d.ts +8 -0
  138. package/dist/utils/id.d.ts.map +1 -0
  139. package/dist/utils/id.js +19 -0
  140. package/dist/utils/id.js.map +1 -0
  141. package/package.json +58 -0
  142. package/src/blobs/index.ts +7 -0
  143. package/src/blobs/manager.ts +1027 -0
  144. package/src/blobs/migrate.ts +67 -0
  145. package/src/blobs/types.ts +84 -0
  146. package/src/client.ts +1222 -0
  147. package/src/conflicts.ts +180 -0
  148. package/src/create-client.ts +297 -0
  149. package/src/engine/SyncEngine.ts +1337 -0
  150. package/src/engine/index.ts +6 -0
  151. package/src/engine/types.ts +268 -0
  152. package/src/handlers/create-handler.ts +287 -0
  153. package/src/handlers/registry.ts +36 -0
  154. package/src/handlers/types.ts +102 -0
  155. package/src/index.ts +25 -0
  156. package/src/migrate.ts +122 -0
  157. package/src/mutations.ts +926 -0
  158. package/src/outbox.ts +397 -0
  159. package/src/plugins/incrementing-version.ts +133 -0
  160. package/src/plugins/index.ts +2 -0
  161. package/src/plugins/types.ts +63 -0
  162. package/src/proxy/connection.ts +191 -0
  163. package/src/proxy/dialect.ts +76 -0
  164. package/src/proxy/driver.ts +126 -0
  165. package/src/proxy/index.ts +10 -0
  166. package/src/proxy/mutations.ts +18 -0
  167. package/src/pull-engine.ts +518 -0
  168. package/src/push-engine.ts +201 -0
  169. package/src/query/FingerprintCollector.ts +29 -0
  170. package/src/query/QueryContext.ts +54 -0
  171. package/src/query/fingerprint.ts +109 -0
  172. package/src/query/index.ts +10 -0
  173. package/src/query/tracked-select.ts +139 -0
  174. package/src/schema.ts +94 -0
  175. package/src/sync-loop.ts +368 -0
  176. package/src/utils/id.ts +20 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @syncular/client - Sync outbox (commit-based)
3
+ */
4
+ import type { SyncOperation } from '@syncular/core';
5
+ import type { Kysely } from 'kysely';
6
+ import type { OutboxCommitStatus, SyncClientDb } from './schema';
7
+ export interface OutboxCommit {
8
+ id: string;
9
+ client_commit_id: string;
10
+ status: OutboxCommitStatus;
11
+ operations: SyncOperation[];
12
+ last_response_json: string | null;
13
+ error: string | null;
14
+ created_at: number;
15
+ updated_at: number;
16
+ attempt_count: number;
17
+ acked_commit_seq: number | null;
18
+ /** Client schema version when commit was created */
19
+ schema_version: number;
20
+ }
21
+ export declare function enqueueOutboxCommit<DB extends SyncClientDb>(db: Kysely<DB>, args: {
22
+ operations: SyncOperation[];
23
+ clientCommitId?: string;
24
+ nowMs?: number;
25
+ /** Client schema version (default: 1) */
26
+ schemaVersion?: number;
27
+ }): Promise<{
28
+ id: string;
29
+ clientCommitId: string;
30
+ }>;
31
+ /**
32
+ * Atomically claim and return the next sendable outbox commit.
33
+ *
34
+ * Uses SELECT then UPDATE with status check to prevent race conditions.
35
+ * If another tab claims the same commit, retries with a different candidate.
36
+ */
37
+ export declare function getNextSendableOutboxCommit<DB extends SyncClientDb>(db: Kysely<DB>, options?: {
38
+ staleTimeoutMs?: number;
39
+ maxRetries?: number;
40
+ }): Promise<OutboxCommit | null>;
41
+ declare function markOutboxCommitSending<DB extends SyncClientDb>(db: Kysely<DB>, id: string): Promise<void>;
42
+ export declare function markOutboxCommitAcked<DB extends SyncClientDb>(db: Kysely<DB>, args: {
43
+ id: string;
44
+ commitSeq?: number | null;
45
+ responseJson?: string | null;
46
+ }): Promise<void>;
47
+ export declare function markOutboxCommitFailed<DB extends SyncClientDb>(db: Kysely<DB>, args: {
48
+ id: string;
49
+ error: string;
50
+ responseJson?: string | null;
51
+ }): Promise<void>;
52
+ export declare function markOutboxCommitPending<DB extends SyncClientDb>(db: Kysely<DB>, args: {
53
+ id: string;
54
+ error?: string | null;
55
+ responseJson?: string | null;
56
+ }): Promise<void>;
57
+ declare function deleteAckedOutboxCommits<DB extends SyncClientDb>(db: Kysely<DB>): Promise<number>;
58
+ declare function deleteFailedOutboxCommits<DB extends SyncClientDb>(db: Kysely<DB>): Promise<number>;
59
+ declare function clearAllOutboxCommits<DB extends SyncClientDb>(db: Kysely<DB>): Promise<number>;
60
+ /**
61
+ * Outbox namespace - organized API for outbox operations.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * import { outbox } from '@syncular/client';
66
+ *
67
+ * // Enqueue a new commit
68
+ * const { id } = await outbox.enqueue(db, { operations: [...] });
69
+ *
70
+ * // Get next sendable commit
71
+ * const commit = await outbox.getNextSendable(db);
72
+ *
73
+ * // Mark commit status
74
+ * await outbox.mark.acked(db, { id, commitSeq: 42 });
75
+ * await outbox.mark.failed(db, { id, error: 'Network error' });
76
+ * await outbox.mark.pending(db, { id });
77
+ * await outbox.mark.sending(db, id);
78
+ *
79
+ * // Cleanup commits
80
+ * await outbox.cleanup.acked(db);
81
+ * await outbox.cleanup.failed(db);
82
+ * await outbox.cleanup.all(db);
83
+ * ```
84
+ */
85
+ export declare const outbox: {
86
+ /** Enqueue a new commit to the outbox */
87
+ readonly enqueue: typeof enqueueOutboxCommit;
88
+ /** Get the next sendable commit (atomically claims it) */
89
+ readonly getNextSendable: typeof getNextSendableOutboxCommit;
90
+ /** Mark commit status */
91
+ readonly mark: {
92
+ /** Mark commit as sending (in progress) */
93
+ readonly sending: typeof markOutboxCommitSending;
94
+ /** Mark commit as acknowledged (successfully synced) */
95
+ readonly acked: typeof markOutboxCommitAcked;
96
+ /** Mark commit as failed (permanent error) */
97
+ readonly failed: typeof markOutboxCommitFailed;
98
+ /** Mark commit as pending (ready for retry) */
99
+ readonly pending: typeof markOutboxCommitPending;
100
+ };
101
+ /** Cleanup operations */
102
+ readonly cleanup: {
103
+ /** Delete all acknowledged commits */
104
+ readonly acked: typeof deleteAckedOutboxCommits;
105
+ /** Delete all failed commits */
106
+ readonly failed: typeof deleteFailedOutboxCommits;
107
+ /** Delete all commits (clear entire outbox) */
108
+ readonly all: typeof clearAllOutboxCommits;
109
+ };
110
+ };
111
+ export {};
112
+ //# sourceMappingURL=outbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../src/outbox.ts"],"names":[],"mappings":"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"}
package/dist/outbox.js ADDED
@@ -0,0 +1,304 @@
1
+ /**
2
+ * @syncular/client - Sync outbox (commit-based)
3
+ */
4
+ import { sql } from 'kysely';
5
+ function randomId() {
6
+ if (typeof crypto !== 'undefined' &&
7
+ typeof crypto.randomUUID === 'function') {
8
+ return crypto.randomUUID();
9
+ }
10
+ // Very small fallback; good enough for tests.
11
+ return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
12
+ }
13
+ function isRecord(value) {
14
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
15
+ }
16
+ function isSyncOperation(value) {
17
+ if (!isRecord(value))
18
+ return false;
19
+ if (typeof value.table !== 'string')
20
+ return false;
21
+ if (typeof value.row_id !== 'string')
22
+ return false;
23
+ if (value.op !== 'upsert' && value.op !== 'delete')
24
+ return false;
25
+ if (value.payload !== null && !isRecord(value.payload))
26
+ return false;
27
+ if (!('base_version' in value))
28
+ return true;
29
+ return (value.base_version === null ||
30
+ value.base_version === undefined ||
31
+ typeof value.base_version === 'number');
32
+ }
33
+ function parseOperations(value) {
34
+ let parsed = value;
35
+ if (typeof value === 'string') {
36
+ try {
37
+ parsed = JSON.parse(value);
38
+ }
39
+ catch {
40
+ return [];
41
+ }
42
+ }
43
+ if (!Array.isArray(parsed))
44
+ return [];
45
+ const out = [];
46
+ for (const item of parsed) {
47
+ if (!isSyncOperation(item))
48
+ continue;
49
+ out.push(item);
50
+ }
51
+ return out;
52
+ }
53
+ export async function enqueueOutboxCommit(db, args) {
54
+ const now = args.nowMs ?? Date.now();
55
+ const id = randomId();
56
+ const clientCommitId = args.clientCommitId ?? randomId();
57
+ const schemaVersion = args.schemaVersion ?? 1;
58
+ await sql `
59
+ insert into ${sql.table('sync_outbox_commits')} (
60
+ ${sql.join([
61
+ sql.ref('id'),
62
+ sql.ref('client_commit_id'),
63
+ sql.ref('status'),
64
+ sql.ref('operations_json'),
65
+ sql.ref('last_response_json'),
66
+ sql.ref('error'),
67
+ sql.ref('created_at'),
68
+ sql.ref('updated_at'),
69
+ sql.ref('attempt_count'),
70
+ sql.ref('acked_commit_seq'),
71
+ sql.ref('schema_version'),
72
+ ])}
73
+ ) values (
74
+ ${sql.join([
75
+ sql.val(id),
76
+ sql.val(clientCommitId),
77
+ sql.val('pending'),
78
+ sql.val(JSON.stringify(args.operations ?? [])),
79
+ sql.val(null),
80
+ sql.val(null),
81
+ sql.val(now),
82
+ sql.val(now),
83
+ sql.val(0),
84
+ sql.val(null),
85
+ sql.val(schemaVersion),
86
+ ])}
87
+ )
88
+ `.execute(db);
89
+ return { id, clientCommitId };
90
+ }
91
+ /**
92
+ * Atomically claim and return the next sendable outbox commit.
93
+ *
94
+ * Uses SELECT then UPDATE with status check to prevent race conditions.
95
+ * If another tab claims the same commit, retries with a different candidate.
96
+ */
97
+ export async function getNextSendableOutboxCommit(db, options) {
98
+ const staleTimeoutMs = options?.staleTimeoutMs ?? 30000;
99
+ const maxRetries = options?.maxRetries ?? 3;
100
+ // Track IDs we've already tried to claim (to avoid retrying the same one)
101
+ const attemptedIds = new Set();
102
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
103
+ const staleThreshold = Date.now() - staleTimeoutMs;
104
+ const now = Date.now();
105
+ // Find a candidate to claim, excluding ones we've already tried
106
+ const attempted = Array.from(attemptedIds);
107
+ const attemptedFilter = attempted.length === 0
108
+ ? sql ``
109
+ : sql `and ${sql.ref('id')} not in (${sql.join(attempted.map((id) => sql.val(id)), sql `, `)})`;
110
+ const candidateResult = await sql `
111
+ select ${sql.ref('id')}
112
+ from ${sql.table('sync_outbox_commits')}
113
+ where (
114
+ ${sql.ref('status')} = ${sql.val('pending')}
115
+ or (
116
+ ${sql.ref('status')} = ${sql.val('sending')}
117
+ and ${sql.ref('updated_at')} < ${sql.val(staleThreshold)}
118
+ )
119
+ )
120
+ ${attemptedFilter}
121
+ order by ${sql.ref('created_at')} asc
122
+ limit ${sql.val(1)}
123
+ `.execute(db);
124
+ const candidate = candidateResult.rows[0];
125
+ if (!candidate)
126
+ return null;
127
+ attemptedIds.add(candidate.id);
128
+ // Atomically claim the commit using UPDATE...WHERE with status check
129
+ const claimResult = await sql `
130
+ update ${sql.table('sync_outbox_commits')}
131
+ set
132
+ ${sql.ref('status')} = ${sql.val('sending')},
133
+ ${sql.ref('updated_at')} = ${sql.val(now)},
134
+ ${sql.ref('attempt_count')} = ${sql.ref('attempt_count')} + ${sql.val(1)},
135
+ ${sql.ref('error')} = ${sql.val(null)},
136
+ ${sql.ref('last_response_json')} = ${sql.val(null)}
137
+ where ${sql.ref('id')} = ${sql.val(candidate.id)}
138
+ and (
139
+ ${sql.ref('status')} = ${sql.val('pending')}
140
+ or (
141
+ ${sql.ref('status')} = ${sql.val('sending')}
142
+ and ${sql.ref('updated_at')} < ${sql.val(staleThreshold)}
143
+ )
144
+ )
145
+ `.execute(db);
146
+ const claimed = Number(claimResult.numAffectedRows ?? 0) > 0;
147
+ if (claimed) {
148
+ const rowResult = await sql `
149
+ select
150
+ ${sql.ref('id')},
151
+ ${sql.ref('client_commit_id')},
152
+ ${sql.ref('status')},
153
+ ${sql.ref('operations_json')},
154
+ ${sql.ref('last_response_json')},
155
+ ${sql.ref('error')},
156
+ ${sql.ref('created_at')},
157
+ ${sql.ref('updated_at')},
158
+ ${sql.ref('attempt_count')},
159
+ ${sql.ref('acked_commit_seq')},
160
+ ${sql.ref('schema_version')}
161
+ from ${sql.table('sync_outbox_commits')}
162
+ where ${sql.ref('id')} = ${sql.val(candidate.id)}
163
+ `.execute(db);
164
+ const row = rowResult.rows[0];
165
+ if (!row)
166
+ continue;
167
+ return {
168
+ id: row.id,
169
+ client_commit_id: row.client_commit_id,
170
+ status: row.status,
171
+ operations: parseOperations(row.operations_json),
172
+ last_response_json: row.last_response_json,
173
+ error: row.error,
174
+ created_at: row.created_at,
175
+ updated_at: row.updated_at,
176
+ attempt_count: row.attempt_count,
177
+ acked_commit_seq: row.acked_commit_seq,
178
+ schema_version: row.schema_version ?? 1,
179
+ };
180
+ }
181
+ // Another tab claimed it, retry with next candidate
182
+ }
183
+ return null;
184
+ }
185
+ async function markOutboxCommitSending(db, id) {
186
+ const now = Date.now();
187
+ await sql `
188
+ update ${sql.table('sync_outbox_commits')}
189
+ set
190
+ ${sql.ref('status')} = ${sql.val('sending')},
191
+ ${sql.ref('updated_at')} = ${sql.val(now)},
192
+ ${sql.ref('attempt_count')} = ${sql.ref('attempt_count')} + ${sql.val(1)},
193
+ ${sql.ref('error')} = ${sql.val(null)},
194
+ ${sql.ref('last_response_json')} = ${sql.val(null)}
195
+ where ${sql.ref('id')} = ${sql.val(id)}
196
+ `.execute(db);
197
+ }
198
+ export async function markOutboxCommitAcked(db, args) {
199
+ const now = Date.now();
200
+ await sql `
201
+ update ${sql.table('sync_outbox_commits')}
202
+ set
203
+ ${sql.ref('status')} = ${sql.val('acked')},
204
+ ${sql.ref('updated_at')} = ${sql.val(now)},
205
+ ${sql.ref('acked_commit_seq')} = ${sql.val(args.commitSeq ?? null)},
206
+ ${sql.ref('error')} = ${sql.val(null)},
207
+ ${sql.ref('last_response_json')} = ${sql.val(args.responseJson ?? null)}
208
+ where ${sql.ref('id')} = ${sql.val(args.id)}
209
+ `.execute(db);
210
+ }
211
+ export async function markOutboxCommitFailed(db, args) {
212
+ const now = Date.now();
213
+ await sql `
214
+ update ${sql.table('sync_outbox_commits')}
215
+ set
216
+ ${sql.ref('status')} = ${sql.val('failed')},
217
+ ${sql.ref('updated_at')} = ${sql.val(now)},
218
+ ${sql.ref('error')} = ${sql.val(args.error)},
219
+ ${sql.ref('last_response_json')} = ${sql.val(args.responseJson ?? null)}
220
+ where ${sql.ref('id')} = ${sql.val(args.id)}
221
+ `.execute(db);
222
+ }
223
+ export async function markOutboxCommitPending(db, args) {
224
+ const now = Date.now();
225
+ await sql `
226
+ update ${sql.table('sync_outbox_commits')}
227
+ set
228
+ ${sql.ref('status')} = ${sql.val('pending')},
229
+ ${sql.ref('updated_at')} = ${sql.val(now)},
230
+ ${sql.ref('error')} = ${sql.val(args.error ?? null)},
231
+ ${sql.ref('last_response_json')} = ${sql.val(args.responseJson ?? null)}
232
+ where ${sql.ref('id')} = ${sql.val(args.id)}
233
+ `.execute(db);
234
+ }
235
+ async function deleteAckedOutboxCommits(db) {
236
+ const res = await sql `
237
+ delete from ${sql.table('sync_outbox_commits')}
238
+ where ${sql.ref('status')} = ${sql.val('acked')}
239
+ `.execute(db);
240
+ return Number(res.numAffectedRows ?? 0);
241
+ }
242
+ async function deleteFailedOutboxCommits(db) {
243
+ const res = await sql `
244
+ delete from ${sql.table('sync_outbox_commits')}
245
+ where ${sql.ref('status')} = ${sql.val('failed')}
246
+ `.execute(db);
247
+ return Number(res.numAffectedRows ?? 0);
248
+ }
249
+ async function clearAllOutboxCommits(db) {
250
+ const res = await sql `delete from ${sql.table('sync_outbox_commits')}`.execute(db);
251
+ return Number(res.numAffectedRows ?? 0);
252
+ }
253
+ /**
254
+ * Outbox namespace - organized API for outbox operations.
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * import { outbox } from '@syncular/client';
259
+ *
260
+ * // Enqueue a new commit
261
+ * const { id } = await outbox.enqueue(db, { operations: [...] });
262
+ *
263
+ * // Get next sendable commit
264
+ * const commit = await outbox.getNextSendable(db);
265
+ *
266
+ * // Mark commit status
267
+ * await outbox.mark.acked(db, { id, commitSeq: 42 });
268
+ * await outbox.mark.failed(db, { id, error: 'Network error' });
269
+ * await outbox.mark.pending(db, { id });
270
+ * await outbox.mark.sending(db, id);
271
+ *
272
+ * // Cleanup commits
273
+ * await outbox.cleanup.acked(db);
274
+ * await outbox.cleanup.failed(db);
275
+ * await outbox.cleanup.all(db);
276
+ * ```
277
+ */
278
+ export const outbox = {
279
+ /** Enqueue a new commit to the outbox */
280
+ enqueue: enqueueOutboxCommit,
281
+ /** Get the next sendable commit (atomically claims it) */
282
+ getNextSendable: getNextSendableOutboxCommit,
283
+ /** Mark commit status */
284
+ mark: {
285
+ /** Mark commit as sending (in progress) */
286
+ sending: markOutboxCommitSending,
287
+ /** Mark commit as acknowledged (successfully synced) */
288
+ acked: markOutboxCommitAcked,
289
+ /** Mark commit as failed (permanent error) */
290
+ failed: markOutboxCommitFailed,
291
+ /** Mark commit as pending (ready for retry) */
292
+ pending: markOutboxCommitPending,
293
+ },
294
+ /** Cleanup operations */
295
+ cleanup: {
296
+ /** Delete all acknowledged commits */
297
+ acked: deleteAckedOutboxCommits,
298
+ /** Delete all failed commits */
299
+ failed: deleteFailedOutboxCommits,
300
+ /** Delete all commits (clear entire outbox) */
301
+ all: clearAllOutboxCommits,
302
+ },
303
+ };
304
+ //# sourceMappingURL=outbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../src/outbox.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAkB7B,SAAS,QAAQ,GAAW;IAC1B,IACE,OAAO,MAAM,KAAK,WAAW;QAC7B,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,EACvC,CAAC;QACD,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IACD,8CAA8C;IAC9C,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CAC/D;AAED,SAAS,QAAQ,CAAC,KAAc,EAAoC;IAClE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAA,CAC7E;AAED,SAAS,eAAe,CAAC,KAAc,EAA0B;IAC/D,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjE,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACrE,IAAI,CAAC,CAAC,cAAc,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,CACL,KAAK,CAAC,YAAY,KAAK,IAAI;QAC3B,KAAK,CAAC,YAAY,KAAK,SAAS;QAChC,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ,CACvC,CAAC;AAAA,CACH;AAED,SAAS,eAAe,CAAC,KAAc,EAAmB;IACxD,IAAI,MAAM,GAAY,KAAK,CAAC;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,SAAS;QACrC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACZ;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAc,EACd,IAMC,EACgD;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACrC,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,QAAQ,EAAE,CAAC;IACzD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC;IAE9C,MAAM,GAAG,CAAA;kBACO,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;QAC1C,GAAG,CAAC,IAAI,CAAC;QACT,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QACjB,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC1B,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAC7B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAChB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QACrB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QACrB,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC;QACxB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC;KAC1B,CAAC;;QAEA,GAAG,CAAC,IAAI,CAAC;QACT,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QACvB,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;QAClB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAC9C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACV,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;KACvB,CAAC;;GAEL,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAEd,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC;AAAA,CAC/B;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,EAAc,EACd,OAA0D,EAC5B;IAC9B,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,KAAK,CAAC;IACxD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,CAAC,CAAC;IAE5C,0EAA0E;IAC1E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,gEAAgE;QAChE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,eAAe,GACnB,SAAS,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,GAAG,CAAA,EAAE;YACP,CAAC,CAAC,GAAG,CAAA,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CACzC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAClC,GAAG,CAAA,IAAI,CACR,GAAG,CAAC;QAEX,MAAM,eAAe,GAAG,MAAM,GAAG,CAAgB;eACtC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;aACf,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;UAEnC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;;YAEvC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;gBACrC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;;;QAG1D,eAAe;iBACN,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;cACxB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;KACnB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACd,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAE5B,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAE/B,qEAAqE;QACrE,MAAM,WAAW,GAAG,MAAM,GAAG,CAAA;eAClB,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;UAErC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;UACzC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;UACvC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;UACtE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;UACnC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;cAC5C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;;YAE1C,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;;cAEvC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;kBACrC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;;;KAG/D,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEd,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,MAAM,GAAG,CAYzB;;YAEI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;YACjB,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC;YAC1B,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAC7B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC;YACxB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC;eACtB,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;gBAC/B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;OACjD,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG;gBAAE,SAAS;YAEnB,OAAO;gBACL,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,UAAU,EAAE,eAAe,CAAC,GAAG,CAAC,eAAe,CAAC;gBAChD,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;gBAC1C,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,aAAa,EAAE,GAAG,CAAC,aAAa;gBAChC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,CAAC;aACxC,CAAC;QACJ,CAAC;QAED,oDAAoD;IACtD,CAAC;IAED,OAAO,IAAI,CAAC;AAAA,CACb;AAED,KAAK,UAAU,uBAAuB,CACpC,EAAc,EACd,EAAU,EACK;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,GAAG,CAAA;aACE,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;QAErC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;QACzC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;GACvC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,CACf;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,EAAc,EACd,IAA6E,EAC9D;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,GAAG,CAAA;aACE,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;QAErC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;QAChE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;YACjE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;GAC5C,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,CACf;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,EAAc,EACd,IAAiE,EAClD;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,GAAG,CAAA;aACE,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;QAErC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QACxC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;QACzC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;YACjE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;GAC5C,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,CACf;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,EAAc,EACd,IAAyE,EAC1D;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,GAAG,CAAA;aACE,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;;QAErC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;QACzC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;QACjD,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;YACjE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;GAC5C,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,CACf;AAED,KAAK,UAAU,wBAAwB,CACrC,EAAc,EACG;IACjB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;kBACL,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;YACtC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;GAChD,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;AAAA,CACzC;AAED,KAAK,UAAU,yBAAyB,CACtC,EAAc,EACG;IACjB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;kBACL,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC;YACtC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;GACjD,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;AAAA,CACzC;AAED,KAAK,UAAU,qBAAqB,CAClC,EAAc,EACG;IACjB,MAAM,GAAG,GACP,MAAM,GAAG,CAAA,eAAe,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;AAAA,CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,yCAAyC;IACzC,OAAO,EAAE,mBAAmB;IAE5B,0DAA0D;IAC1D,eAAe,EAAE,2BAA2B;IAE5C,yBAAyB;IACzB,IAAI,EAAE;QACJ,2CAA2C;QAC3C,OAAO,EAAE,uBAAuB;QAChC,wDAAwD;QACxD,KAAK,EAAE,qBAAqB;QAC5B,8CAA8C;QAC9C,MAAM,EAAE,sBAAsB;QAC9B,+CAA+C;QAC/C,OAAO,EAAE,uBAAuB;KACjC;IAED,yBAAyB;IACzB,OAAO,EAAE;QACP,sCAAsC;QACtC,KAAK,EAAE,wBAAwB;QAC/B,gCAAgC;QAChC,MAAM,EAAE,yBAAyB;QACjC,+CAA+C;QAC/C,GAAG,EAAE,qBAAqB;KAC3B;CACO,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { SyncClientPlugin } from './types';
2
+ export interface IncrementingVersionPluginOptions {
3
+ /**
4
+ * Plugin name (used for debugging).
5
+ * Defaults to "incrementing-version".
6
+ */
7
+ name?: string;
8
+ /**
9
+ * Maximum number of rows to track in memory.
10
+ * Defaults to 10_000.
11
+ */
12
+ maxTrackedRows?: number;
13
+ }
14
+ /**
15
+ * Automatically advances `base_version` for sequential operations on the same row.
16
+ *
17
+ * Why this exists:
18
+ * - UI code often reads a row once and can enqueue multiple updates quickly.
19
+ * - The server rejects stale `base_version` values (optimistic concurrency).
20
+ * - When those updates all originate from the same client and are pushed in-order,
21
+ * later ops are effectively based on the earlier ops.
22
+ *
23
+ * Assumptions:
24
+ * - The server's row version is an integer that increments by 1 per applied upsert.
25
+ * - Operations are pushed in commit order for a given client (outbox ordering).
26
+ *
27
+ * This plugin:
28
+ * - Tracks the "next expected server version" per (shape, table, row_id) based on
29
+ * successfully applied pushes.
30
+ * - Rewrites outgoing `base_version` to that expected version when it is higher
31
+ * than the caller-provided value, preventing "self-conflicts" on hot rows.
32
+ */
33
+ export declare function createIncrementingVersionPlugin(options?: IncrementingVersionPluginOptions): SyncClientPlugin;
34
+ //# sourceMappingURL=incrementing-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incrementing-version.d.ts","sourceRoot":"","sources":["../../src/plugins/incrementing-version.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAA2B,MAAM,SAAS,CAAC;AAEzE,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,gCAAqC,GAC7C,gBAAgB,CAyElB"}
@@ -0,0 +1,83 @@
1
+ function makeRowKey(op) {
2
+ return `${op.table}\u001f${op.row_id}`;
3
+ }
4
+ function touchLru(map, key, value, max) {
5
+ // Maintain insertion order as an LRU.
6
+ map.delete(key);
7
+ map.set(key, value);
8
+ if (map.size <= max)
9
+ return;
10
+ const firstKey = map.keys().next().value;
11
+ if (firstKey)
12
+ map.delete(firstKey);
13
+ }
14
+ /**
15
+ * Automatically advances `base_version` for sequential operations on the same row.
16
+ *
17
+ * Why this exists:
18
+ * - UI code often reads a row once and can enqueue multiple updates quickly.
19
+ * - The server rejects stale `base_version` values (optimistic concurrency).
20
+ * - When those updates all originate from the same client and are pushed in-order,
21
+ * later ops are effectively based on the earlier ops.
22
+ *
23
+ * Assumptions:
24
+ * - The server's row version is an integer that increments by 1 per applied upsert.
25
+ * - Operations are pushed in commit order for a given client (outbox ordering).
26
+ *
27
+ * This plugin:
28
+ * - Tracks the "next expected server version" per (shape, table, row_id) based on
29
+ * successfully applied pushes.
30
+ * - Rewrites outgoing `base_version` to that expected version when it is higher
31
+ * than the caller-provided value, preventing "self-conflicts" on hot rows.
32
+ */
33
+ export function createIncrementingVersionPlugin(options = {}) {
34
+ const name = options.name ?? 'incrementing-version';
35
+ const maxTrackedRows = Math.max(1, Math.min(1_000_000, options.maxTrackedRows ?? 10_000));
36
+ const nextExpectedBaseVersionByRow = new Map();
37
+ return {
38
+ name,
39
+ beforePush(_ctx, request) {
40
+ const operations = request.operations.map((op) => {
41
+ if (typeof op.base_version !== 'number')
42
+ return op;
43
+ const key = makeRowKey(op);
44
+ const nextExpected = nextExpectedBaseVersionByRow.get(key);
45
+ if (typeof nextExpected !== 'number')
46
+ return op;
47
+ if (nextExpected > op.base_version) {
48
+ return { ...op, base_version: nextExpected };
49
+ }
50
+ return op;
51
+ });
52
+ return { ...request, operations };
53
+ },
54
+ afterPush(_ctx, args) {
55
+ // Rejected commits are rolled back by the server; nothing is applied.
56
+ if (args.response.status !== 'applied' &&
57
+ args.response.status !== 'cached') {
58
+ return args.response;
59
+ }
60
+ for (const result of args.response.results ?? []) {
61
+ if (result.status !== 'applied')
62
+ continue;
63
+ const op = args.request.operations[result.opIndex];
64
+ if (!op)
65
+ continue;
66
+ const key = makeRowKey(op);
67
+ if (op.op === 'delete') {
68
+ nextExpectedBaseVersionByRow.delete(key);
69
+ continue;
70
+ }
71
+ if (typeof op.base_version === 'number') {
72
+ touchLru(nextExpectedBaseVersionByRow, key, op.base_version + 1, maxTrackedRows);
73
+ }
74
+ else {
75
+ // Insert case: most shapes start at version 1.
76
+ touchLru(nextExpectedBaseVersionByRow, key, 1, maxTrackedRows);
77
+ }
78
+ }
79
+ return args.response;
80
+ },
81
+ };
82
+ }
83
+ //# sourceMappingURL=incrementing-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incrementing-version.js","sourceRoot":"","sources":["../../src/plugins/incrementing-version.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './incrementing-version';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './incrementing-version';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC"}
@@ -0,0 +1,49 @@
1
+ import type { SyncPullRequest, SyncPullResponse, SyncPushRequest, SyncPushResponse } from '@syncular/core';
2
+ export interface SyncClientPluginContext {
3
+ actorId: string;
4
+ clientId: string;
5
+ }
6
+ /**
7
+ * Plugin priority levels for ordering execution.
8
+ * Lower numbers execute first.
9
+ */
10
+ export declare const PluginPriority: {
11
+ /** Compression should run early (before encryption) */
12
+ readonly COMPRESSION: 10;
13
+ /** Encryption should run after compression but before transport */
14
+ readonly ENCRYPTION: 20;
15
+ /** Default priority for general plugins */
16
+ readonly DEFAULT: 50;
17
+ /** Logging/telemetry should run last */
18
+ readonly TELEMETRY: 100;
19
+ };
20
+ export interface SyncClientPlugin {
21
+ name: string;
22
+ /**
23
+ * Plugin priority for ordering. Lower numbers execute first.
24
+ * @default PluginPriority.DEFAULT (50)
25
+ */
26
+ priority?: number;
27
+ /**
28
+ * Called before sending a push request to the server.
29
+ * Use this for client-side encryption, payload shaping, etc.
30
+ */
31
+ beforePush?(ctx: SyncClientPluginContext, request: SyncPushRequest): Promise<SyncPushRequest> | SyncPushRequest;
32
+ /**
33
+ * Called after receiving a push response from the server.
34
+ * Receives both the request and the response to allow opIndex correlation.
35
+ */
36
+ afterPush?(ctx: SyncClientPluginContext, args: {
37
+ request: SyncPushRequest;
38
+ response: SyncPushResponse;
39
+ }): Promise<SyncPushResponse> | SyncPushResponse;
40
+ /**
41
+ * Called after receiving a pull response from the server (and after any
42
+ * snapshot chunk materialization), but before applying it to the local DB.
43
+ */
44
+ afterPull?(ctx: SyncClientPluginContext, args: {
45
+ request: SyncPullRequest;
46
+ response: SyncPullResponse;
47
+ }): Promise<SyncPullResponse> | SyncPullResponse;
48
+ }
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc;IACzB,uDAAuD;;IAEvD,mEAAmE;;IAEnE,2CAA2C;;IAE3C,wCAAwC;;CAEhC,CAAC;AAEX,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,CAAC,CACT,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;IAE9C;;;OAGG;IACH,SAAS,CAAC,CACR,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,QAAQ,EAAE,gBAAgB,CAAA;KAAE,GAC7D,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAAC;IAEhD;;;OAGG;IACH,SAAS,CAAC,CACR,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,QAAQ,EAAE,gBAAgB,CAAA;KAAE,GAC7D,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAAC;CACjD"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Plugin priority levels for ordering execution.
3
+ * Lower numbers execute first.
4
+ */
5
+ export const PluginPriority = {
6
+ /** Compression should run early (before encryption) */
7
+ COMPRESSION: 10,
8
+ /** Encryption should run after compression but before transport */
9
+ ENCRYPTION: 20,
10
+ /** Default priority for general plugins */
11
+ DEFAULT: 50,
12
+ /** Logging/telemetry should run last */
13
+ TELEMETRY: 100,
14
+ };
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,uDAAuD;IACvD,WAAW,EAAE,EAAE;IACf,mEAAmE;IACnE,UAAU,EAAE,EAAE;IACd,2CAA2C;IAC3C,OAAO,EAAE,EAAE;IACX,wCAAwC;IACxC,SAAS,EAAE,GAAG;CACN,CAAC"}