@syncular/server 0.0.1-98 → 0.0.2-126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/blobs/adapters/filesystem.d.ts +31 -0
- package/dist/blobs/adapters/filesystem.d.ts.map +1 -0
- package/dist/blobs/adapters/filesystem.js +140 -0
- package/dist/blobs/adapters/filesystem.js.map +1 -0
- package/dist/blobs/adapters/s3.d.ts +3 -2
- package/dist/blobs/adapters/s3.d.ts.map +1 -1
- package/dist/blobs/adapters/s3.js +49 -0
- package/dist/blobs/adapters/s3.js.map +1 -1
- package/dist/blobs/index.d.ts +1 -0
- package/dist/blobs/index.d.ts.map +1 -1
- package/dist/blobs/index.js +1 -0
- package/dist/blobs/index.js.map +1 -1
- package/dist/compaction.d.ts +1 -1
- package/dist/compaction.js +1 -1
- package/dist/{shapes → handlers}/create-handler.d.ts +18 -5
- package/dist/handlers/create-handler.d.ts.map +1 -0
- package/dist/{shapes → handlers}/create-handler.js +54 -17
- package/dist/handlers/create-handler.js.map +1 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/registry.d.ts.map +1 -0
- package/dist/handlers/registry.js.map +1 -0
- package/dist/{shapes → handlers}/types.d.ts +7 -7
- package/dist/{shapes → handlers}/types.d.ts.map +1 -1
- package/dist/{shapes → handlers}/types.js.map +1 -1
- package/dist/helpers/conflict.d.ts +1 -1
- package/dist/helpers/conflict.d.ts.map +1 -1
- package/dist/helpers/emitted-change.d.ts +1 -1
- package/dist/helpers/emitted-change.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/notify.d.ts +47 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +85 -0
- package/dist/notify.js.map +1 -0
- package/dist/proxy/handler.d.ts +1 -1
- package/dist/proxy/handler.d.ts.map +1 -1
- package/dist/proxy/handler.js +7 -7
- package/dist/proxy/handler.js.map +1 -1
- package/dist/proxy/oplog.d.ts +1 -1
- package/dist/proxy/oplog.d.ts.map +1 -1
- package/dist/proxy/oplog.js +6 -6
- package/dist/proxy/oplog.js.map +1 -1
- package/dist/pull.d.ts +2 -2
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +48 -9
- package/dist/pull.js.map +1 -1
- package/dist/push.d.ts +2 -2
- package/dist/push.d.ts.map +1 -1
- package/dist/push.js +1 -1
- package/dist/push.js.map +1 -1
- package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
- package/dist/snapshot-chunks/db-metadata.js +14 -3
- package/dist/snapshot-chunks/db-metadata.js.map +1 -1
- package/dist/snapshot-chunks/index.d.ts +0 -1
- package/dist/snapshot-chunks/index.d.ts.map +1 -1
- package/dist/snapshot-chunks/index.js +0 -1
- package/dist/snapshot-chunks/index.js.map +1 -1
- package/dist/subscriptions/resolve.d.ts +6 -6
- package/dist/subscriptions/resolve.d.ts.map +1 -1
- package/dist/subscriptions/resolve.js +53 -14
- package/dist/subscriptions/resolve.js.map +1 -1
- package/package.json +2 -2
- package/src/blobs/adapters/filesystem.test.ts +132 -0
- package/src/blobs/adapters/filesystem.ts +189 -0
- package/src/blobs/adapters/s3.test.ts +522 -0
- package/src/blobs/adapters/s3.ts +55 -2
- package/src/blobs/index.ts +1 -0
- package/src/compaction.ts +1 -1
- package/src/{shapes → handlers}/create-handler.ts +111 -21
- package/src/{shapes → handlers}/types.ts +10 -7
- package/src/helpers/conflict.ts +1 -1
- package/src/helpers/emitted-change.ts +1 -1
- package/src/index.ts +2 -1
- package/src/notify.test.ts +516 -0
- package/src/notify.ts +131 -0
- package/src/proxy/handler.test.ts +3 -3
- package/src/proxy/handler.ts +8 -8
- package/src/proxy/oplog.ts +7 -7
- package/src/pull.ts +66 -12
- package/src/push.ts +3 -3
- package/src/snapshot-chunks/db-metadata.test.ts +69 -0
- package/src/snapshot-chunks/db-metadata.ts +14 -3
- package/src/snapshot-chunks/index.ts +0 -1
- package/src/subscriptions/resolve.ts +73 -18
- package/dist/shapes/create-handler.d.ts.map +0 -1
- package/dist/shapes/create-handler.js.map +0 -1
- package/dist/shapes/index.d.ts.map +0 -1
- package/dist/shapes/index.js.map +0 -1
- package/dist/shapes/registry.d.ts.map +0 -1
- package/dist/shapes/registry.js.map +0 -1
- package/dist/snapshot-chunks/adapters/s3.d.ts +0 -74
- package/dist/snapshot-chunks/adapters/s3.d.ts.map +0 -1
- package/dist/snapshot-chunks/adapters/s3.js +0 -50
- package/dist/snapshot-chunks/adapters/s3.js.map +0 -1
- package/src/snapshot-chunks/adapters/s3.ts +0 -68
- /package/dist/{shapes → handlers}/index.d.ts +0 -0
- /package/dist/{shapes → handlers}/index.js +0 -0
- /package/dist/{shapes → handlers}/registry.d.ts +0 -0
- /package/dist/{shapes → handlers}/registry.js +0 -0
- /package/dist/{shapes → handlers}/types.js +0 -0
- /package/src/{shapes → handlers}/index.ts +0 -0
- /package/src/{shapes → handlers}/registry.ts +0 -0
|
@@ -5,11 +5,20 @@
|
|
|
5
5
|
import type {
|
|
6
6
|
ScopePattern,
|
|
7
7
|
ScopeValues,
|
|
8
|
+
ScopeValuesFromPatterns,
|
|
8
9
|
ScopeDefinition as SimpleScopeDefinition,
|
|
9
10
|
StoredScopes,
|
|
10
11
|
SyncOperation,
|
|
11
12
|
} from '@syncular/core';
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
applyCodecsFromDbRow,
|
|
15
|
+
applyCodecsToDbRow,
|
|
16
|
+
type ColumnCodecDialect,
|
|
17
|
+
type ColumnCodecSource,
|
|
18
|
+
extractScopeVars,
|
|
19
|
+
normalizeScopes,
|
|
20
|
+
toTableColumnCodecs,
|
|
21
|
+
} from '@syncular/core';
|
|
13
22
|
import type {
|
|
14
23
|
DeleteQueryBuilder,
|
|
15
24
|
DeleteResult,
|
|
@@ -69,6 +78,8 @@ export interface CreateServerHandlerOptions<
|
|
|
69
78
|
ServerDB extends SyncCoreDb,
|
|
70
79
|
ClientDB,
|
|
71
80
|
TableName extends keyof ServerDB & keyof ClientDB & string,
|
|
81
|
+
ScopeDefs extends
|
|
82
|
+
readonly SimpleScopeDefinition[] = readonly SimpleScopeDefinition[],
|
|
72
83
|
> {
|
|
73
84
|
/** Table name in the database */
|
|
74
85
|
table: TableName;
|
|
@@ -88,7 +99,7 @@ export interface CreateServerHandlerOptions<
|
|
|
88
99
|
* ]
|
|
89
100
|
* ```
|
|
90
101
|
*/
|
|
91
|
-
scopes:
|
|
102
|
+
scopes: ScopeDefs;
|
|
92
103
|
|
|
93
104
|
/** Primary key column name (default: 'id') */
|
|
94
105
|
primaryKey?: string;
|
|
@@ -112,7 +123,9 @@ export interface CreateServerHandlerOptions<
|
|
|
112
123
|
* project_id: await getProjectsForUser(ctx.db, ctx.actorId),
|
|
113
124
|
* })
|
|
114
125
|
*/
|
|
115
|
-
resolveScopes: (
|
|
126
|
+
resolveScopes: (
|
|
127
|
+
ctx: ServerContext<ServerDB>
|
|
128
|
+
) => Promise<ScopeValuesFromPatterns<ScopeDefs>>;
|
|
116
129
|
|
|
117
130
|
/**
|
|
118
131
|
* Transform inbound row from client to server format.
|
|
@@ -130,6 +143,20 @@ export interface CreateServerHandlerOptions<
|
|
|
130
143
|
row: Selectable<ServerDB[TableName]>
|
|
131
144
|
) => ClientDB[TableName];
|
|
132
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Optional column codec resolver.
|
|
148
|
+
* Receives `{ table, column, sqlType?, dialect? }` and returns a codec.
|
|
149
|
+
* Only used by default snapshot/apply paths when the corresponding
|
|
150
|
+
* transform hook is not provided.
|
|
151
|
+
*/
|
|
152
|
+
columnCodecs?: ColumnCodecSource;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Dialect used for codec dialect overrides.
|
|
156
|
+
* Default: 'sqlite'
|
|
157
|
+
*/
|
|
158
|
+
codecDialect?: ColumnCodecDialect;
|
|
159
|
+
|
|
133
160
|
/**
|
|
134
161
|
* Authorize an operation before applying.
|
|
135
162
|
* Return true to allow, or an error object to reject.
|
|
@@ -186,8 +213,10 @@ export function createServerHandler<
|
|
|
186
213
|
ServerDB extends SyncCoreDb,
|
|
187
214
|
ClientDB,
|
|
188
215
|
TableName extends keyof ServerDB & keyof ClientDB & string,
|
|
216
|
+
ScopeDefs extends
|
|
217
|
+
readonly SimpleScopeDefinition[] = readonly SimpleScopeDefinition[],
|
|
189
218
|
>(
|
|
190
|
-
options: CreateServerHandlerOptions<ServerDB, ClientDB, TableName>
|
|
219
|
+
options: CreateServerHandlerOptions<ServerDB, ClientDB, TableName, ScopeDefs>
|
|
191
220
|
): ServerTableHandler<ServerDB> {
|
|
192
221
|
type OverloadParameters<T> = T extends (...args: infer A) => unknown
|
|
193
222
|
? A
|
|
@@ -210,9 +239,25 @@ export function createServerHandler<
|
|
|
210
239
|
resolveScopes,
|
|
211
240
|
transformInbound,
|
|
212
241
|
transformOutbound,
|
|
242
|
+
columnCodecs,
|
|
243
|
+
codecDialect = 'sqlite',
|
|
213
244
|
authorize,
|
|
214
245
|
extractScopes: customExtractScopes,
|
|
215
246
|
} = options;
|
|
247
|
+
const codecCache = new Map<string, ReturnType<typeof toTableColumnCodecs>>();
|
|
248
|
+
const resolveTableCodecs = (row: Record<string, unknown>) => {
|
|
249
|
+
if (!columnCodecs) return {};
|
|
250
|
+
const columns = Object.keys(row);
|
|
251
|
+
if (columns.length === 0) return {};
|
|
252
|
+
const cacheKey = columns.slice().sort().join('\u0000');
|
|
253
|
+
const cached = codecCache.get(cacheKey);
|
|
254
|
+
if (cached) return cached;
|
|
255
|
+
const resolved = toTableColumnCodecs(table, columnCodecs, columns, {
|
|
256
|
+
dialect: codecDialect,
|
|
257
|
+
});
|
|
258
|
+
codecCache.set(cacheKey, resolved);
|
|
259
|
+
return resolved;
|
|
260
|
+
};
|
|
216
261
|
|
|
217
262
|
// Normalize scopes to pattern map and extract patterns/columns
|
|
218
263
|
const scopeColumnMap = normalizeScopes(scopeDefs);
|
|
@@ -252,6 +297,53 @@ export function createServerHandler<
|
|
|
252
297
|
|
|
253
298
|
const extractScopesImpl = customExtractScopes ?? defaultExtractScopes;
|
|
254
299
|
|
|
300
|
+
const resolveScopesImpl = async (
|
|
301
|
+
ctx: ServerContext<ServerDB>
|
|
302
|
+
): Promise<ScopeValues> => {
|
|
303
|
+
const resolved = await resolveScopes(ctx);
|
|
304
|
+
const normalized: ScopeValues = {};
|
|
305
|
+
for (const [scopeKey, scopeValue] of Object.entries(resolved)) {
|
|
306
|
+
if (typeof scopeValue === 'string' || Array.isArray(scopeValue)) {
|
|
307
|
+
normalized[scopeKey] = scopeValue;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return normalized;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const applyOutboundTransform = (
|
|
314
|
+
row: Selectable<ServerDB[TableName]>
|
|
315
|
+
): ClientDB[TableName] => {
|
|
316
|
+
if (transformOutbound) {
|
|
317
|
+
return transformOutbound(row);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const recordRow = row as Record<string, unknown>;
|
|
321
|
+
const transformed = applyCodecsFromDbRow(
|
|
322
|
+
recordRow,
|
|
323
|
+
resolveTableCodecs(recordRow),
|
|
324
|
+
codecDialect
|
|
325
|
+
);
|
|
326
|
+
return transformed as ClientDB[TableName];
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const applyInboundTransform = (
|
|
330
|
+
row: Record<string, unknown>,
|
|
331
|
+
schemaVersion: number | undefined
|
|
332
|
+
): Updateable<ServerDB[TableName]> => {
|
|
333
|
+
if (transformInbound) {
|
|
334
|
+
return transformInbound(row as ClientDB[TableName], {
|
|
335
|
+
schemaVersion,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const transformed = applyCodecsToDbRow(
|
|
340
|
+
row,
|
|
341
|
+
resolveTableCodecs(row),
|
|
342
|
+
codecDialect
|
|
343
|
+
);
|
|
344
|
+
return transformed as Updateable<ServerDB[TableName]>;
|
|
345
|
+
};
|
|
346
|
+
|
|
255
347
|
// Default snapshot implementation
|
|
256
348
|
const defaultSnapshot = async (
|
|
257
349
|
ctx: ServerSnapshotContext<ServerDB>,
|
|
@@ -308,11 +400,9 @@ export function createServerHandler<
|
|
|
308
400
|
: null;
|
|
309
401
|
|
|
310
402
|
// Transform outbound if provided
|
|
311
|
-
const outputRows =
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
)
|
|
315
|
-
: pageRows;
|
|
403
|
+
const outputRows = pageRows.map((r) =>
|
|
404
|
+
applyOutboundTransform(r as Selectable<ServerDB[TableName]>)
|
|
405
|
+
);
|
|
316
406
|
|
|
317
407
|
return {
|
|
318
408
|
rows: outputRows,
|
|
@@ -408,11 +498,11 @@ export function createServerHandler<
|
|
|
408
498
|
|
|
409
499
|
// Handle upsert
|
|
410
500
|
const rawPayload = op.payload ?? {};
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
|
|
501
|
+
const payloadRecord =
|
|
502
|
+
rawPayload !== null && typeof rawPayload === 'object'
|
|
503
|
+
? (rawPayload as Record<string, unknown>)
|
|
504
|
+
: {};
|
|
505
|
+
const payload = applyInboundTransform(payloadRecord, ctx.schemaVersion);
|
|
416
506
|
|
|
417
507
|
// Check for existing row
|
|
418
508
|
const existing = await (
|
|
@@ -441,9 +531,9 @@ export function createServerHandler<
|
|
|
441
531
|
status: 'conflict',
|
|
442
532
|
message: `Version conflict: server=${existingVersion}, base=${op.base_version}`,
|
|
443
533
|
server_version: existingVersion,
|
|
444
|
-
server_row:
|
|
445
|
-
|
|
446
|
-
|
|
534
|
+
server_row: applyOutboundTransform(
|
|
535
|
+
existing as Selectable<ServerDB[TableName]>
|
|
536
|
+
),
|
|
447
537
|
},
|
|
448
538
|
emittedChanges: [],
|
|
449
539
|
};
|
|
@@ -558,9 +648,9 @@ export function createServerHandler<
|
|
|
558
648
|
const scopes = extractScopesImpl(updatedRow);
|
|
559
649
|
|
|
560
650
|
// Transform outbound for emitted change
|
|
561
|
-
const rowJson =
|
|
562
|
-
|
|
563
|
-
|
|
651
|
+
const rowJson = applyOutboundTransform(
|
|
652
|
+
updated as Selectable<ServerDB[TableName]>
|
|
653
|
+
);
|
|
564
654
|
|
|
565
655
|
const emitted: EmittedChange = {
|
|
566
656
|
table,
|
|
@@ -582,7 +672,7 @@ export function createServerHandler<
|
|
|
582
672
|
scopePatterns,
|
|
583
673
|
dependsOn,
|
|
584
674
|
snapshotChunkTtlMs,
|
|
585
|
-
resolveScopes,
|
|
675
|
+
resolveScopes: resolveScopesImpl,
|
|
586
676
|
extractScopes: extractScopesImpl,
|
|
587
677
|
snapshot: options.snapshot ?? defaultSnapshot,
|
|
588
678
|
applyOperation: options.applyOperation ?? defaultApplyOperation,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ScopePattern,
|
|
3
3
|
ScopeValues,
|
|
4
|
+
ScopeValuesForKeys,
|
|
4
5
|
StoredScopes,
|
|
5
6
|
SyncOp,
|
|
6
7
|
SyncOperation,
|
|
@@ -50,12 +51,14 @@ export interface ServerContext<DB extends SyncCoreDb = SyncCoreDb> {
|
|
|
50
51
|
/**
|
|
51
52
|
* Context passed to snapshot method.
|
|
52
53
|
*/
|
|
53
|
-
export interface ServerSnapshotContext<
|
|
54
|
-
extends
|
|
54
|
+
export interface ServerSnapshotContext<
|
|
55
|
+
DB extends SyncCoreDb = SyncCoreDb,
|
|
56
|
+
ScopeKeys extends string = string,
|
|
57
|
+
> extends ServerContext<DB> {
|
|
55
58
|
/** Database executor for the snapshot */
|
|
56
59
|
db: DbExecutor<DB>;
|
|
57
60
|
/** Effective scope values for this subscription */
|
|
58
|
-
scopeValues:
|
|
61
|
+
scopeValues: ScopeValuesForKeys<ScopeKeys>;
|
|
59
62
|
/** Pagination cursor (row_id for keyset pagination) */
|
|
60
63
|
cursor: string | null;
|
|
61
64
|
/** Max rows to return */
|
|
@@ -120,9 +123,9 @@ interface ServerScopeConfig {
|
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
123
|
-
* Server
|
|
126
|
+
* Server handler options - configuration for a table's sync behavior.
|
|
124
127
|
*/
|
|
125
|
-
export interface
|
|
128
|
+
export interface ServerHandlerOptions<
|
|
126
129
|
DB extends SyncCoreDb = SyncCoreDb,
|
|
127
130
|
Scopes extends Record<ScopePattern, Record<string, string>> = Record<
|
|
128
131
|
ScopePattern,
|
|
@@ -132,7 +135,7 @@ export interface ServerShapeOptions<
|
|
|
132
135
|
Params extends ZodSchema = ZodSchema,
|
|
133
136
|
> {
|
|
134
137
|
/**
|
|
135
|
-
* Scope patterns this
|
|
138
|
+
* Scope patterns this handler uses.
|
|
136
139
|
* Array of pattern keys from SharedScopes.
|
|
137
140
|
*/
|
|
138
141
|
scopes: (keyof Scopes)[];
|
|
@@ -225,7 +228,7 @@ export interface ServerTableHandler<DB extends SyncCoreDb = SyncCoreDb> {
|
|
|
225
228
|
/** Table name */
|
|
226
229
|
table: string;
|
|
227
230
|
|
|
228
|
-
/** Scope patterns used by this
|
|
231
|
+
/** Scope patterns used by this handler */
|
|
229
232
|
scopePatterns: ScopePattern[];
|
|
230
233
|
|
|
231
234
|
/**
|
package/src/helpers/conflict.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Helper for building conflict results in server table handlers.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ApplyOperationResult } from '../
|
|
7
|
+
import type { ApplyOperationResult } from '../handlers/types';
|
|
8
8
|
|
|
9
9
|
export interface BuildConflictResultArgs {
|
|
10
10
|
/** Index of the operation in the batch */
|
package/src/index.ts
CHANGED
|
@@ -13,15 +13,16 @@ export * from './blobs';
|
|
|
13
13
|
export * from './clients';
|
|
14
14
|
export * from './compaction';
|
|
15
15
|
export * from './dialect';
|
|
16
|
+
export * from './handlers';
|
|
16
17
|
export * from './helpers';
|
|
17
18
|
export * from './migrate';
|
|
19
|
+
export * from './notify';
|
|
18
20
|
export * from './proxy';
|
|
19
21
|
export * from './prune';
|
|
20
22
|
export * from './pull';
|
|
21
23
|
export * from './push';
|
|
22
24
|
export * from './realtime';
|
|
23
25
|
export * from './schema';
|
|
24
|
-
export * from './shapes';
|
|
25
26
|
export * from './snapshot-chunks';
|
|
26
27
|
export type { SnapshotChunkStorage } from './snapshot-chunks/types';
|
|
27
28
|
export * from './stats';
|