@syncular/core 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +5 -19
  2. package/dist/blob-ref.d.ts +21 -0
  3. package/dist/blob-ref.js +97 -0
  4. package/dist/bytes.d.ts +45 -0
  5. package/dist/bytes.js +242 -0
  6. package/dist/canonical-json.d.ts +10 -0
  7. package/dist/canonical-json.js +18 -0
  8. package/dist/constants.d.ts +5 -0
  9. package/dist/constants.js +5 -0
  10. package/dist/crypto.d.ts +60 -0
  11. package/dist/crypto.js +251 -0
  12. package/dist/errors.d.ts +14 -0
  13. package/dist/errors.js +17 -0
  14. package/dist/frames.d.ts +24 -0
  15. package/dist/frames.js +42 -0
  16. package/dist/index.d.ts +18 -26
  17. package/dist/index.js +18 -43
  18. package/dist/message.d.ts +157 -0
  19. package/dist/message.js +786 -0
  20. package/dist/realtime.d.ts +92 -0
  21. package/dist/realtime.js +222 -0
  22. package/dist/render.d.ts +22 -0
  23. package/dist/render.js +273 -0
  24. package/dist/row-codec.d.ts +39 -0
  25. package/dist/row-codec.js +176 -0
  26. package/dist/segment.d.ts +18 -0
  27. package/dist/segment.js +105 -0
  28. package/dist/stream.d.ts +20 -0
  29. package/dist/stream.js +102 -0
  30. package/package.json +7 -59
  31. package/src/blob-ref.ts +135 -0
  32. package/src/bytes.ts +301 -0
  33. package/src/canonical-json.ts +20 -0
  34. package/src/constants.ts +7 -0
  35. package/src/crypto.ts +335 -0
  36. package/src/errors.ts +18 -0
  37. package/src/frames.ts +47 -0
  38. package/src/index.ts +18 -43
  39. package/src/message.ts +1024 -0
  40. package/src/realtime.ts +340 -0
  41. package/src/render.ts +325 -0
  42. package/src/row-codec.ts +265 -0
  43. package/src/segment.ts +150 -0
  44. package/src/stream.ts +128 -0
  45. package/dist/blobs.d.ts +0 -153
  46. package/dist/blobs.d.ts.map +0 -1
  47. package/dist/blobs.js +0 -47
  48. package/dist/blobs.js.map +0 -1
  49. package/dist/column-codecs.d.ts +0 -59
  50. package/dist/column-codecs.d.ts.map +0 -1
  51. package/dist/column-codecs.js +0 -159
  52. package/dist/column-codecs.js.map +0 -1
  53. package/dist/conflict.d.ts +0 -22
  54. package/dist/conflict.d.ts.map +0 -1
  55. package/dist/conflict.js +0 -81
  56. package/dist/conflict.js.map +0 -1
  57. package/dist/database.d.ts +0 -7
  58. package/dist/database.d.ts.map +0 -1
  59. package/dist/database.js +0 -14
  60. package/dist/database.js.map +0 -1
  61. package/dist/dialect.d.ts +0 -7
  62. package/dist/dialect.d.ts.map +0 -1
  63. package/dist/dialect.js +0 -2
  64. package/dist/dialect.js.map +0 -1
  65. package/dist/error-responses.d.ts +0 -393
  66. package/dist/error-responses.d.ts.map +0 -1
  67. package/dist/error-responses.js +0 -393
  68. package/dist/error-responses.js.map +0 -1
  69. package/dist/http/api-client.d.ts +0 -11
  70. package/dist/http/api-client.d.ts.map +0 -1
  71. package/dist/http/api-client.js +0 -30
  72. package/dist/http/api-client.js.map +0 -1
  73. package/dist/http/blob.d.ts +0 -6
  74. package/dist/http/blob.d.ts.map +0 -1
  75. package/dist/http/blob.js +0 -46
  76. package/dist/http/blob.js.map +0 -1
  77. package/dist/http/generated/api.d.ts +0 -5241
  78. package/dist/http/generated/api.d.ts.map +0 -1
  79. package/dist/http/generated/api.js +0 -6
  80. package/dist/http/generated/api.js.map +0 -1
  81. package/dist/http/index.d.ts +0 -18
  82. package/dist/http/index.d.ts.map +0 -1
  83. package/dist/http/index.js +0 -212
  84. package/dist/http/index.js.map +0 -1
  85. package/dist/http/shared.d.ts +0 -45
  86. package/dist/http/shared.d.ts.map +0 -1
  87. package/dist/http/shared.js +0 -122
  88. package/dist/http/shared.js.map +0 -1
  89. package/dist/http/transport-client.d.ts +0 -31
  90. package/dist/http/transport-client.d.ts.map +0 -1
  91. package/dist/http/transport-client.js +0 -193
  92. package/dist/http/transport-client.js.map +0 -1
  93. package/dist/index.d.ts.map +0 -1
  94. package/dist/index.js.map +0 -1
  95. package/dist/kysely-column-codecs.d.ts +0 -31
  96. package/dist/kysely-column-codecs.d.ts.map +0 -1
  97. package/dist/kysely-column-codecs.js +0 -452
  98. package/dist/kysely-column-codecs.js.map +0 -1
  99. package/dist/logger.d.ts +0 -29
  100. package/dist/logger.d.ts.map +0 -1
  101. package/dist/logger.js +0 -26
  102. package/dist/logger.js.map +0 -1
  103. package/dist/proxy/index.d.ts +0 -54
  104. package/dist/proxy/index.d.ts.map +0 -1
  105. package/dist/proxy/index.js +0 -7
  106. package/dist/proxy/index.js.map +0 -1
  107. package/dist/schemas/blobs.d.ts +0 -82
  108. package/dist/schemas/blobs.d.ts.map +0 -1
  109. package/dist/schemas/blobs.js +0 -64
  110. package/dist/schemas/blobs.js.map +0 -1
  111. package/dist/schemas/common.d.ts +0 -100
  112. package/dist/schemas/common.d.ts.map +0 -1
  113. package/dist/schemas/common.js +0 -64
  114. package/dist/schemas/common.js.map +0 -1
  115. package/dist/schemas/index.d.ts +0 -7
  116. package/dist/schemas/index.d.ts.map +0 -1
  117. package/dist/schemas/index.js +0 -7
  118. package/dist/schemas/index.js.map +0 -1
  119. package/dist/schemas/sync.d.ts +0 -1065
  120. package/dist/schemas/sync.d.ts.map +0 -1
  121. package/dist/schemas/sync.js +0 -361
  122. package/dist/schemas/sync.js.map +0 -1
  123. package/dist/scopes/index.d.ts +0 -113
  124. package/dist/scopes/index.d.ts.map +0 -1
  125. package/dist/scopes/index.js +0 -103
  126. package/dist/scopes/index.js.map +0 -1
  127. package/dist/sentry.d.ts +0 -31
  128. package/dist/sentry.d.ts.map +0 -1
  129. package/dist/sentry.js +0 -147
  130. package/dist/sentry.js.map +0 -1
  131. package/dist/snapshot-chunks.d.ts +0 -110
  132. package/dist/snapshot-chunks.d.ts.map +0 -1
  133. package/dist/snapshot-chunks.js +0 -682
  134. package/dist/snapshot-chunks.js.map +0 -1
  135. package/dist/sync-packs.d.ts +0 -33
  136. package/dist/sync-packs.d.ts.map +0 -1
  137. package/dist/sync-packs.js +0 -821
  138. package/dist/sync-packs.js.map +0 -1
  139. package/dist/telemetry.d.ts +0 -114
  140. package/dist/telemetry.d.ts.map +0 -1
  141. package/dist/telemetry.js +0 -114
  142. package/dist/telemetry.js.map +0 -1
  143. package/dist/transforms.d.ts +0 -146
  144. package/dist/transforms.d.ts.map +0 -1
  145. package/dist/transforms.js +0 -155
  146. package/dist/transforms.js.map +0 -1
  147. package/dist/types.d.ts +0 -210
  148. package/dist/types.d.ts.map +0 -1
  149. package/dist/types.js +0 -20
  150. package/dist/types.js.map +0 -1
  151. package/dist/utils/bytes.d.ts +0 -4
  152. package/dist/utils/bytes.d.ts.map +0 -1
  153. package/dist/utils/bytes.js +0 -66
  154. package/dist/utils/bytes.js.map +0 -1
  155. package/dist/utils/compression.d.ts +0 -22
  156. package/dist/utils/compression.d.ts.map +0 -1
  157. package/dist/utils/compression.js +0 -129
  158. package/dist/utils/compression.js.map +0 -1
  159. package/dist/utils/crypto.d.ts +0 -13
  160. package/dist/utils/crypto.d.ts.map +0 -1
  161. package/dist/utils/crypto.js +0 -107
  162. package/dist/utils/crypto.js.map +0 -1
  163. package/dist/utils/id.d.ts +0 -3
  164. package/dist/utils/id.d.ts.map +0 -1
  165. package/dist/utils/id.js +0 -25
  166. package/dist/utils/id.js.map +0 -1
  167. package/dist/utils/index.d.ts +0 -10
  168. package/dist/utils/index.d.ts.map +0 -1
  169. package/dist/utils/index.js +0 -10
  170. package/dist/utils/index.js.map +0 -1
  171. package/dist/utils/internal-runtime.d.ts +0 -16
  172. package/dist/utils/internal-runtime.d.ts.map +0 -1
  173. package/dist/utils/internal-runtime.js +0 -14
  174. package/dist/utils/internal-runtime.js.map +0 -1
  175. package/dist/utils/object.d.ts +0 -2
  176. package/dist/utils/object.d.ts.map +0 -1
  177. package/dist/utils/object.js +0 -4
  178. package/dist/utils/object.js.map +0 -1
  179. package/dist/utils/realtime-change-index.d.ts +0 -9
  180. package/dist/utils/realtime-change-index.d.ts.map +0 -1
  181. package/dist/utils/realtime-change-index.js +0 -36
  182. package/dist/utils/realtime-change-index.js.map +0 -1
  183. package/dist/utils/realtime-connection-registry.d.ts +0 -40
  184. package/dist/utils/realtime-connection-registry.d.ts.map +0 -1
  185. package/dist/utils/realtime-connection-registry.js +0 -237
  186. package/dist/utils/realtime-connection-registry.js.map +0 -1
  187. package/dist/utils/table-registry.d.ts +0 -10
  188. package/dist/utils/table-registry.d.ts.map +0 -1
  189. package/dist/utils/table-registry.js +0 -54
  190. package/dist/utils/table-registry.js.map +0 -1
  191. package/dist/utils/url.d.ts +0 -3
  192. package/dist/utils/url.d.ts.map +0 -1
  193. package/dist/utils/url.js +0 -20
  194. package/dist/utils/url.js.map +0 -1
  195. package/src/blobs.ts +0 -219
  196. package/src/column-codecs.ts +0 -262
  197. package/src/conflict.ts +0 -92
  198. package/src/database.ts +0 -21
  199. package/src/dialect.ts +0 -8
  200. package/src/error-responses.ts +0 -423
  201. package/src/http/api-client.ts +0 -39
  202. package/src/http/blob.ts +0 -95
  203. package/src/http/generated/api.ts +0 -5241
  204. package/src/http/index.ts +0 -365
  205. package/src/http/shared.ts +0 -220
  206. package/src/http/transport-client.ts +0 -314
  207. package/src/kysely-column-codecs.ts +0 -585
  208. package/src/logger.ts +0 -38
  209. package/src/proxy/index.ts +0 -57
  210. package/src/schemas/blobs.ts +0 -110
  211. package/src/schemas/common.ts +0 -89
  212. package/src/schemas/index.ts +0 -7
  213. package/src/schemas/sync.ts +0 -517
  214. package/src/scopes/index.ts +0 -237
  215. package/src/sentry.ts +0 -200
  216. package/src/snapshot-chunks.ts +0 -964
  217. package/src/sync-packs.ts +0 -1096
  218. package/src/telemetry.ts +0 -243
  219. package/src/transforms.ts +0 -256
  220. package/src/types.ts +0 -267
  221. package/src/utils/bytes.ts +0 -75
  222. package/src/utils/compression.ts +0 -187
  223. package/src/utils/crypto.ts +0 -146
  224. package/src/utils/id.ts +0 -34
  225. package/src/utils/index.ts +0 -9
  226. package/src/utils/internal-runtime.ts +0 -39
  227. package/src/utils/object.ts +0 -3
  228. package/src/utils/realtime-change-index.ts +0 -44
  229. package/src/utils/realtime-connection-registry.ts +0 -286
  230. package/src/utils/table-registry.ts +0 -67
  231. package/src/utils/url.ts +0 -29
@@ -1,585 +0,0 @@
1
- import {
2
- type AliasNode,
3
- type ColumnNode,
4
- type ColumnUpdateNode,
5
- type DeleteQueryNode,
6
- type IdentifierNode,
7
- type InsertQueryNode,
8
- type KyselyPlugin,
9
- type OperationNode,
10
- OperationNodeTransformer,
11
- type PluginTransformQueryArgs,
12
- type PluginTransformResultArgs,
13
- type PrimitiveValueListNode,
14
- type QueryResult,
15
- type ReferenceNode,
16
- type RootOperationNode,
17
- type SelectionNode,
18
- type SelectQueryNode,
19
- type TableNode,
20
- type UnknownRow,
21
- type UpdateQueryNode,
22
- type ValueNode,
23
- type ValuesNode,
24
- } from 'kysely';
25
- import {
26
- type AnyColumnCodec,
27
- applyCodecFromDbValue,
28
- applyCodecToDbValue,
29
- type ColumnCodecDialect,
30
- type ColumnCodecSource,
31
- createTableColumnCodecsResolver,
32
- type TableColumnCodecs,
33
- } from './column-codecs';
34
-
35
- interface ColumnCodecPluginOptions {
36
- codecs: ColumnCodecSource;
37
- dialect?: ColumnCodecDialect;
38
- }
39
-
40
- interface ColumnReference {
41
- outputKey: string;
42
- table: string;
43
- column: string;
44
- }
45
-
46
- export interface QueryResultPlan {
47
- explicit: ColumnReference[];
48
- selectAllTables: string[];
49
- }
50
-
51
- function isIdentifierNode(
52
- node: OperationNode | undefined
53
- ): node is IdentifierNode {
54
- return node?.kind === 'IdentifierNode';
55
- }
56
-
57
- function isTableNode(node: OperationNode | undefined): node is TableNode {
58
- return node?.kind === 'TableNode';
59
- }
60
-
61
- function isAliasNode(node: OperationNode | undefined): node is AliasNode {
62
- return node?.kind === 'AliasNode';
63
- }
64
-
65
- function isColumnNode(node: OperationNode | undefined): node is ColumnNode {
66
- return node?.kind === 'ColumnNode';
67
- }
68
-
69
- function isReferenceNode(
70
- node: OperationNode | undefined
71
- ): node is ReferenceNode {
72
- return node?.kind === 'ReferenceNode';
73
- }
74
-
75
- function isSelectionNode(
76
- node: OperationNode | undefined
77
- ): node is SelectionNode {
78
- return node?.kind === 'SelectionNode';
79
- }
80
-
81
- function isPrimitiveValueListNode(
82
- node: OperationNode | undefined
83
- ): node is PrimitiveValueListNode {
84
- return node?.kind === 'PrimitiveValueListNode';
85
- }
86
-
87
- function isValuesNode(node: OperationNode | undefined): node is ValuesNode {
88
- return node?.kind === 'ValuesNode';
89
- }
90
-
91
- function isValueNode(node: OperationNode | undefined): node is ValueNode {
92
- return node?.kind === 'ValueNode';
93
- }
94
-
95
- function getIdentifierName(node?: OperationNode): string | undefined {
96
- if (!isIdentifierNode(node)) return undefined;
97
- return node?.name;
98
- }
99
-
100
- function getTableName(node?: OperationNode): string | undefined {
101
- if (!isTableNode(node)) return undefined;
102
- return getIdentifierName(node.table.identifier);
103
- }
104
-
105
- function getColumnName(node?: OperationNode): string | undefined {
106
- if (!isColumnNode(node)) return undefined;
107
- return getIdentifierName(node.column);
108
- }
109
-
110
- function getBaseTableFromAlias(node: AliasNode): string | undefined {
111
- if (!isTableNode(node.node)) return undefined;
112
- return getTableName(node.node);
113
- }
114
-
115
- function getAliasName(node: AliasNode): string | undefined {
116
- return getIdentifierName(node.alias);
117
- }
118
-
119
- function tableAliasMapForSelect(node: SelectQueryNode): Map<string, string> {
120
- const aliases = new Map<string, string>();
121
-
122
- for (const fromItem of node.from?.froms ?? []) {
123
- if (isTableNode(fromItem)) {
124
- const tableName = getTableName(fromItem);
125
- if (tableName) aliases.set(tableName, tableName);
126
- continue;
127
- }
128
- if (isAliasNode(fromItem)) {
129
- const tableName = getBaseTableFromAlias(fromItem);
130
- const aliasName = getAliasName(fromItem);
131
- if (tableName && aliasName) aliases.set(aliasName, tableName);
132
- }
133
- }
134
-
135
- for (const join of node.joins ?? []) {
136
- const joinItem = join.table;
137
- if (isTableNode(joinItem)) {
138
- const tableName = getTableName(joinItem);
139
- if (tableName) aliases.set(tableName, tableName);
140
- continue;
141
- }
142
- if (isAliasNode(joinItem)) {
143
- const tableName = getBaseTableFromAlias(joinItem);
144
- const aliasName = getAliasName(joinItem);
145
- if (tableName && aliasName) aliases.set(aliasName, tableName);
146
- }
147
- }
148
-
149
- return aliases;
150
- }
151
-
152
- function resolveTableName(args: {
153
- refTable?: string;
154
- aliases: Map<string, string>;
155
- fallbackTable?: string;
156
- }): string | undefined {
157
- if (args.refTable) {
158
- return args.aliases.get(args.refTable) ?? args.refTable;
159
- }
160
- if (args.fallbackTable) return args.fallbackTable;
161
- if (args.aliases.size === 1) {
162
- return args.aliases.values().next().value;
163
- }
164
- return undefined;
165
- }
166
-
167
- function collectSelectionReferences(args: {
168
- selections: readonly OperationNode[];
169
- aliases: Map<string, string>;
170
- fallbackTable?: string;
171
- }): { explicit: ColumnReference[]; selectAllTables: string[] } {
172
- const explicit: ColumnReference[] = [];
173
- const selectAllTables: string[] = [];
174
-
175
- for (const selectionCandidate of args.selections) {
176
- if (!isSelectionNode(selectionCandidate)) continue;
177
- const selectionNode = selectionCandidate;
178
- const selection = selectionNode.selection;
179
-
180
- if (selection.kind === 'SelectAllNode') {
181
- const tableName = resolveTableName({
182
- aliases: args.aliases,
183
- fallbackTable: args.fallbackTable,
184
- });
185
- if (tableName) selectAllTables.push(tableName);
186
- continue;
187
- }
188
-
189
- if (selection.kind === 'ReferenceNode') {
190
- if (selection.column.kind === 'SelectAllNode') {
191
- const tableRef = getTableName(selection.table);
192
- const tableName = resolveTableName({
193
- refTable: tableRef,
194
- aliases: args.aliases,
195
- fallbackTable: args.fallbackTable,
196
- });
197
- if (tableName) selectAllTables.push(tableName);
198
- continue;
199
- }
200
-
201
- const columnName = getColumnName(selection.column);
202
- const tableRef = getTableName(selection.table);
203
- const tableName = resolveTableName({
204
- refTable: tableRef,
205
- aliases: args.aliases,
206
- fallbackTable: args.fallbackTable,
207
- });
208
- if (!columnName || !tableName) continue;
209
-
210
- explicit.push({
211
- outputKey: columnName,
212
- table: tableName,
213
- column: columnName,
214
- });
215
- continue;
216
- }
217
-
218
- if (selection.kind === 'AliasNode' && isReferenceNode(selection.node)) {
219
- const outputKey = getIdentifierName(selection.alias);
220
- if (!outputKey) continue;
221
-
222
- const reference = selection.node;
223
- if (reference.column.kind === 'SelectAllNode') {
224
- const tableRef = getTableName(reference.table);
225
- const tableName = resolveTableName({
226
- refTable: tableRef,
227
- aliases: args.aliases,
228
- fallbackTable: args.fallbackTable,
229
- });
230
- if (tableName) selectAllTables.push(tableName);
231
- continue;
232
- }
233
-
234
- const columnName = getColumnName(reference.column);
235
- const tableRef = getTableName(reference.table);
236
- const tableName = resolveTableName({
237
- refTable: tableRef,
238
- aliases: args.aliases,
239
- fallbackTable: args.fallbackTable,
240
- });
241
- if (!columnName || !tableName) continue;
242
-
243
- explicit.push({
244
- outputKey,
245
- table: tableName,
246
- column: columnName,
247
- });
248
- }
249
- }
250
-
251
- return { explicit, selectAllTables };
252
- }
253
-
254
- function planForSelect(node: SelectQueryNode): QueryResultPlan | null {
255
- if (!node.selections || node.selections.length === 0) return null;
256
- const aliases = tableAliasMapForSelect(node);
257
- const collected = collectSelectionReferences({
258
- selections: node.selections,
259
- aliases,
260
- });
261
- if (
262
- collected.explicit.length === 0 &&
263
- collected.selectAllTables.length === 0
264
- ) {
265
- return null;
266
- }
267
- return collected;
268
- }
269
-
270
- function planForInsert(node: InsertQueryNode): QueryResultPlan | null {
271
- if (!node.returning || node.returning.selections.length === 0) return null;
272
- const tableName = getTableName(node.into);
273
- if (!tableName) return null;
274
- const aliases = new Map<string, string>([[tableName, tableName]]);
275
- const collected = collectSelectionReferences({
276
- selections: node.returning.selections,
277
- aliases,
278
- fallbackTable: tableName,
279
- });
280
- if (
281
- collected.explicit.length === 0 &&
282
- collected.selectAllTables.length === 0
283
- ) {
284
- return null;
285
- }
286
- return collected;
287
- }
288
-
289
- function planForUpdate(node: UpdateQueryNode): QueryResultPlan | null {
290
- if (!node.returning || node.returning.selections.length === 0) return null;
291
- const tableName = getTableName(node.table);
292
- if (!tableName) return null;
293
- const aliases = new Map<string, string>([[tableName, tableName]]);
294
- const collected = collectSelectionReferences({
295
- selections: node.returning.selections,
296
- aliases,
297
- fallbackTable: tableName,
298
- });
299
- if (
300
- collected.explicit.length === 0 &&
301
- collected.selectAllTables.length === 0
302
- ) {
303
- return null;
304
- }
305
- return collected;
306
- }
307
-
308
- function planForDelete(node: DeleteQueryNode): QueryResultPlan | null {
309
- if (!node.returning || node.returning.selections.length === 0) return null;
310
- const fromTables = node.from?.froms ?? [];
311
- if (fromTables.length !== 1) return null;
312
- const fromItem = fromTables[0];
313
- if (!fromItem) return null;
314
-
315
- let tableName: string | undefined;
316
- if (isTableNode(fromItem)) {
317
- tableName = getTableName(fromItem);
318
- } else if (isAliasNode(fromItem)) {
319
- tableName = getBaseTableFromAlias(fromItem);
320
- }
321
- if (!tableName) return null;
322
-
323
- const aliases = new Map<string, string>([[tableName, tableName]]);
324
- const collected = collectSelectionReferences({
325
- selections: node.returning.selections,
326
- aliases,
327
- fallbackTable: tableName,
328
- });
329
- if (
330
- collected.explicit.length === 0 &&
331
- collected.selectAllTables.length === 0
332
- ) {
333
- return null;
334
- }
335
- return collected;
336
- }
337
-
338
- export function buildQueryResultPlan(
339
- node: RootOperationNode
340
- ): QueryResultPlan | null {
341
- if (node.kind === 'SelectQueryNode') return planForSelect(node);
342
- if (node.kind === 'InsertQueryNode') return planForInsert(node);
343
- if (node.kind === 'UpdateQueryNode') return planForUpdate(node);
344
- if (node.kind === 'DeleteQueryNode') return planForDelete(node);
345
- return null;
346
- }
347
-
348
- export function applyQueryResultPlan(args: {
349
- row: UnknownRow;
350
- plan: QueryResultPlan;
351
- resolveTableCodecs: (
352
- table: string,
353
- row: Record<string, unknown>
354
- ) => TableColumnCodecs;
355
- dialect: ColumnCodecDialect;
356
- }): UnknownRow {
357
- const { row, plan, resolveTableCodecs, dialect } = args;
358
- const source = row as Record<string, unknown>;
359
- const target: Record<string, unknown> = { ...source };
360
-
361
- if (plan.selectAllTables.length > 0) {
362
- const codecCandidates = new Map<string, AnyColumnCodec>();
363
- const ambiguousColumns = new Set<string>();
364
-
365
- for (const table of plan.selectAllTables) {
366
- const tableCodecs = resolveTableCodecs(table, source);
367
- for (const [column, codec] of Object.entries(tableCodecs)) {
368
- if (!(column in source)) continue;
369
- const existing = codecCandidates.get(column);
370
- if (existing && existing !== codec) {
371
- ambiguousColumns.add(column);
372
- continue;
373
- }
374
- codecCandidates.set(column, codec);
375
- }
376
- }
377
-
378
- for (const [column, codec] of codecCandidates.entries()) {
379
- if (ambiguousColumns.has(column)) continue;
380
- target[column] = applyCodecFromDbValue(codec, target[column], dialect);
381
- }
382
- }
383
-
384
- for (const ref of plan.explicit) {
385
- if (!(ref.outputKey in source)) continue;
386
- const tableCodecs = resolveTableCodecs(ref.table, {
387
- [ref.column]: source[ref.outputKey],
388
- });
389
- const codec = tableCodecs[ref.column];
390
- if (!codec) continue;
391
- target[ref.outputKey] = applyCodecFromDbValue(
392
- codec,
393
- target[ref.outputKey],
394
- dialect
395
- );
396
- }
397
-
398
- return target;
399
- }
400
-
401
- class ColumnCodecsTransformer extends OperationNodeTransformer {
402
- readonly #dialect: ColumnCodecDialect;
403
- readonly #resolveTableCodecs: (
404
- table: string,
405
- row: Record<string, unknown>
406
- ) => TableColumnCodecs;
407
- #currentUpdateTable: string | null = null;
408
-
409
- constructor(options: ColumnCodecPluginOptions) {
410
- super();
411
- this.#dialect = options.dialect ?? 'sqlite';
412
- this.#resolveTableCodecs = createTableColumnCodecsResolver(options.codecs, {
413
- dialect: this.#dialect,
414
- });
415
- }
416
-
417
- protected override transformInsertQuery(
418
- node: InsertQueryNode
419
- ): InsertQueryNode {
420
- const transformed = super.transformInsertQuery(node);
421
- if (!transformed.columns || transformed.columns.length === 0) {
422
- return transformed;
423
- }
424
- if (!isValuesNode(transformed.values)) {
425
- return transformed;
426
- }
427
-
428
- const tableName = getTableName(transformed.into);
429
- if (!tableName) return transformed;
430
-
431
- const columns = transformed.columns
432
- .map((columnNode) => getColumnName(columnNode))
433
- .filter((columnName): columnName is string => Boolean(columnName));
434
- if (columns.length === 0) return transformed;
435
-
436
- const tableCodecs = this.#resolveTableCodecs(
437
- tableName,
438
- Object.fromEntries(columns.map((column) => [column, null]))
439
- );
440
-
441
- let didChange = false;
442
- const nextValueRows = transformed.values.values.map((valueNode) => {
443
- if (!isPrimitiveValueListNode(valueNode)) return valueNode;
444
-
445
- const nextValues = valueNode.values.map(
446
- (value: unknown, index: number) => {
447
- const columnName = columns[index];
448
- if (!columnName) return value;
449
- const codec = tableCodecs[columnName];
450
- if (!codec) return value;
451
- const converted = applyCodecToDbValue(codec, value, this.#dialect);
452
- if (converted !== value) {
453
- didChange = true;
454
- }
455
- return converted;
456
- }
457
- );
458
-
459
- if (!didChange) return valueNode;
460
- return {
461
- ...valueNode,
462
- values: nextValues,
463
- };
464
- });
465
-
466
- if (!didChange) return transformed;
467
-
468
- const nextValuesNode: ValuesNode = {
469
- ...transformed.values,
470
- values: nextValueRows,
471
- };
472
-
473
- return {
474
- ...transformed,
475
- values: nextValuesNode,
476
- };
477
- }
478
-
479
- protected override transformUpdateQuery(
480
- node: UpdateQueryNode
481
- ): UpdateQueryNode {
482
- const previousTable = this.#currentUpdateTable;
483
- this.#currentUpdateTable = getTableName(node.table) ?? null;
484
- try {
485
- return super.transformUpdateQuery(node);
486
- } finally {
487
- this.#currentUpdateTable = previousTable;
488
- }
489
- }
490
-
491
- protected override transformColumnUpdate(
492
- node: ColumnUpdateNode,
493
- queryId?: { readonly queryId: string }
494
- ): ColumnUpdateNode {
495
- const transformed = super.transformColumnUpdate(node, queryId);
496
- if (!this.#currentUpdateTable) return transformed;
497
- if (!isValueNode(transformed.value)) return transformed;
498
-
499
- const columnName = getColumnName(transformed.column);
500
- if (!columnName) return transformed;
501
-
502
- const tableCodecs = this.#resolveTableCodecs(this.#currentUpdateTable, {
503
- [columnName]: null,
504
- });
505
- const codec = tableCodecs[columnName];
506
- if (!codec) return transformed;
507
-
508
- const valueNode = transformed.value;
509
- const converted = applyCodecToDbValue(
510
- codec,
511
- valueNode.value,
512
- this.#dialect
513
- );
514
- if (converted === valueNode.value) return transformed;
515
-
516
- const nextValueNode: ValueNode = {
517
- ...valueNode,
518
- value: converted,
519
- };
520
- return {
521
- ...transformed,
522
- value: nextValueNode,
523
- };
524
- }
525
- }
526
-
527
- export class ColumnCodecsPlugin implements KyselyPlugin {
528
- readonly #dialect: ColumnCodecDialect;
529
- readonly #transformer: ColumnCodecsTransformer;
530
- readonly #resultPlans = new WeakMap<object, QueryResultPlan>();
531
- readonly #resolveTableCodecs: (
532
- table: string,
533
- row: Record<string, unknown>
534
- ) => TableColumnCodecs;
535
-
536
- constructor(options: ColumnCodecPluginOptions) {
537
- this.#dialect = options.dialect ?? 'sqlite';
538
- this.#resolveTableCodecs = createTableColumnCodecsResolver(options.codecs, {
539
- dialect: this.#dialect,
540
- });
541
- this.#transformer = new ColumnCodecsTransformer(options);
542
- }
543
-
544
- transformQuery({
545
- node,
546
- queryId,
547
- }: PluginTransformQueryArgs): RootOperationNode {
548
- const transformed = this.#transformer.transformNode(node);
549
- const plan = buildQueryResultPlan(transformed);
550
- if (plan) {
551
- this.#resultPlans.set(queryId, plan);
552
- }
553
- return transformed;
554
- }
555
-
556
- async transformResult({
557
- result,
558
- queryId,
559
- }: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {
560
- const plan = this.#resultPlans.get(queryId);
561
- if (!plan) return result;
562
- if (!result.rows || result.rows.length === 0) return result;
563
-
564
- const rows = result.rows.map((row) => this.#transformRow(row, plan));
565
- return {
566
- ...result,
567
- rows,
568
- };
569
- }
570
-
571
- #transformRow(row: UnknownRow, plan: QueryResultPlan): UnknownRow {
572
- return applyQueryResultPlan({
573
- row,
574
- plan,
575
- resolveTableCodecs: this.#resolveTableCodecs,
576
- dialect: this.#dialect,
577
- });
578
- }
579
- }
580
-
581
- export function createColumnCodecsPlugin(
582
- options: ColumnCodecPluginOptions
583
- ): ColumnCodecsPlugin {
584
- return new ColumnCodecsPlugin(options);
585
- }
package/src/logger.ts DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * @syncular/core - Structured logging utilities for sync operations
3
- *
4
- * Uses the active telemetry backend configured via `configureSyncTelemetry()`.
5
- */
6
-
7
- import { getSyncTelemetry, type SyncTelemetryEvent } from './telemetry';
8
-
9
- /**
10
- * Sync log event structure.
11
- */
12
- export type SyncLogEvent = SyncTelemetryEvent;
13
-
14
- /**
15
- * Logger function type.
16
- */
17
- export type SyncLogger = (event: SyncLogEvent) => void;
18
-
19
- /**
20
- * Log a sync event using the currently configured telemetry backend.
21
- */
22
- export const logSyncEvent: SyncLogger = (event) => {
23
- getSyncTelemetry().log(event);
24
- };
25
-
26
- /**
27
- * Create a timer for measuring operation duration.
28
- * Returns the elapsed time in milliseconds when called.
29
- *
30
- * @example
31
- * const elapsed = createSyncTimer();
32
- * await doSomeWork();
33
- * logSyncEvent({ event: 'work_complete', durationMs: elapsed() });
34
- */
35
- export function createSyncTimer(): () => number {
36
- const start = performance.now();
37
- return () => Math.round(performance.now() - start);
38
- }
@@ -1,57 +0,0 @@
1
- /**
2
- * @syncular/core - Proxy Protocol Types
3
- *
4
- * Shared protocol types between proxy client (Kysely dialect) and server (WebSocket handler).
5
- */
6
-
7
- /**
8
- * Message sent from proxy client to server.
9
- */
10
- export interface ProxyMessage {
11
- /** Correlation ID for matching request/response */
12
- id: string;
13
- /** Message type */
14
- type: 'query' | 'begin' | 'commit' | 'rollback';
15
- /** SQL query (for 'query' type) */
16
- sql?: string;
17
- /** Query parameters (for 'query' type) */
18
- parameters?: readonly unknown[];
19
- }
20
-
21
- /**
22
- * Response sent from server to proxy client.
23
- */
24
- export interface ProxyResponse {
25
- /** Correlation ID matching the request */
26
- id: string;
27
- /** Response type */
28
- type: 'result' | 'error';
29
- /** Query result rows (for SELECT queries) */
30
- rows?: unknown[];
31
- /** Number of affected rows (for mutations) */
32
- rowCount?: number;
33
- /** Error message (for 'error' type) */
34
- error?: string;
35
- }
36
-
37
- /**
38
- * Handshake message sent when connection is established.
39
- */
40
- export interface ProxyHandshake {
41
- type: 'handshake';
42
- /** Actor ID for oplog tracking */
43
- actorId: string;
44
- /** Client ID for oplog tracking */
45
- clientId: string;
46
- }
47
-
48
- /**
49
- * Handshake acknowledgement from server.
50
- */
51
- export interface ProxyHandshakeAck {
52
- type: 'handshake_ack';
53
- /** Whether handshake was successful */
54
- ok: boolean;
55
- /** Error message if handshake failed */
56
- error?: string;
57
- }