@syncular/server 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.
- package/dist/blobs/adapters/database.d.ts +83 -0
- package/dist/blobs/adapters/database.d.ts.map +1 -0
- package/dist/blobs/adapters/database.js +180 -0
- package/dist/blobs/adapters/database.js.map +1 -0
- package/dist/blobs/adapters/s3.d.ts +82 -0
- package/dist/blobs/adapters/s3.d.ts.map +1 -0
- package/dist/blobs/adapters/s3.js +170 -0
- package/dist/blobs/adapters/s3.js.map +1 -0
- package/dist/blobs/index.d.ts +9 -0
- package/dist/blobs/index.d.ts.map +1 -0
- package/dist/blobs/index.js +9 -0
- package/dist/blobs/index.js.map +1 -0
- package/dist/blobs/manager.d.ts +195 -0
- package/dist/blobs/manager.d.ts.map +1 -0
- package/dist/blobs/manager.js +440 -0
- package/dist/blobs/manager.js.map +1 -0
- package/dist/blobs/migrate.d.ts +27 -0
- package/dist/blobs/migrate.d.ts.map +1 -0
- package/dist/blobs/migrate.js +119 -0
- package/dist/blobs/migrate.js.map +1 -0
- package/dist/blobs/types.d.ts +54 -0
- package/dist/blobs/types.d.ts.map +1 -0
- package/dist/blobs/types.js +5 -0
- package/dist/blobs/types.js.map +1 -0
- package/dist/clients.d.ts +14 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +7 -0
- package/dist/clients.js.map +1 -0
- package/dist/compaction.d.ts +27 -0
- package/dist/compaction.d.ts.map +1 -0
- package/dist/compaction.js +49 -0
- package/dist/compaction.js.map +1 -0
- package/dist/dialect/index.d.ts +5 -0
- package/dist/dialect/index.d.ts.map +1 -0
- package/dist/dialect/index.js +5 -0
- package/dist/dialect/index.js.map +1 -0
- package/dist/dialect/types.d.ts +170 -0
- package/dist/dialect/types.d.ts.map +1 -0
- package/dist/dialect/types.js +8 -0
- package/dist/dialect/types.js.map +1 -0
- package/dist/helpers/conflict.d.ts +52 -0
- package/dist/helpers/conflict.d.ts.map +1 -0
- package/dist/helpers/conflict.js +49 -0
- package/dist/helpers/conflict.js.map +1 -0
- package/dist/helpers/emitted-change.d.ts +56 -0
- package/dist/helpers/emitted-change.d.ts.map +1 -0
- package/dist/helpers/emitted-change.js +46 -0
- package/dist/helpers/emitted-change.js.map +1 -0
- package/dist/helpers/index.d.ts +10 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +10 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/paginate.d.ts +49 -0
- package/dist/helpers/paginate.d.ts.map +1 -0
- package/dist/helpers/paginate.js +54 -0
- package/dist/helpers/paginate.js.map +1 -0
- package/dist/helpers/scope-strings.d.ts +74 -0
- package/dist/helpers/scope-strings.d.ts.map +1 -0
- package/dist/helpers/scope-strings.js +82 -0
- package/dist/helpers/scope-strings.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate.d.ts +14 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +13 -0
- package/dist/migrate.js.map +1 -0
- package/dist/proxy/handler.d.ts +42 -0
- package/dist/proxy/handler.d.ts.map +1 -0
- package/dist/proxy/handler.js +99 -0
- package/dist/proxy/handler.js.map +1 -0
- package/dist/proxy/index.d.ts +9 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +14 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/mutation-detector.d.ts +31 -0
- package/dist/proxy/mutation-detector.d.ts.map +1 -0
- package/dist/proxy/mutation-detector.js +61 -0
- package/dist/proxy/mutation-detector.js.map +1 -0
- package/dist/proxy/oplog.d.ts +30 -0
- package/dist/proxy/oplog.d.ts.map +1 -0
- package/dist/proxy/oplog.js +110 -0
- package/dist/proxy/oplog.js.map +1 -0
- package/dist/proxy/registry.d.ts +35 -0
- package/dist/proxy/registry.d.ts.map +1 -0
- package/dist/proxy/registry.js +49 -0
- package/dist/proxy/registry.js.map +1 -0
- package/dist/proxy/types.d.ts +44 -0
- package/dist/proxy/types.d.ts.map +1 -0
- package/dist/proxy/types.js +7 -0
- package/dist/proxy/types.js.map +1 -0
- package/dist/prune.d.ts +37 -0
- package/dist/prune.d.ts.map +1 -0
- package/dist/prune.js +112 -0
- package/dist/prune.js.map +1 -0
- package/dist/pull.d.ts +31 -0
- package/dist/pull.d.ts.map +1 -0
- package/dist/pull.js +414 -0
- package/dist/pull.js.map +1 -0
- package/dist/push.d.ts +33 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/push.js +329 -0
- package/dist/push.js.map +1 -0
- package/dist/realtime/in-memory.d.ts +13 -0
- package/dist/realtime/in-memory.d.ts.map +1 -0
- package/dist/realtime/in-memory.js +28 -0
- package/dist/realtime/in-memory.js.map +1 -0
- package/dist/realtime/index.d.ts +3 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +2 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/types.d.ts +50 -0
- package/dist/realtime/types.d.ts.map +1 -0
- package/dist/realtime/types.js +7 -0
- package/dist/realtime/types.js.map +1 -0
- package/dist/schema.d.ts +164 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +10 -0
- package/dist/schema.js.map +1 -0
- package/dist/shapes/create-handler.d.ts +119 -0
- package/dist/shapes/create-handler.d.ts.map +1 -0
- package/dist/shapes/create-handler.js +327 -0
- package/dist/shapes/create-handler.js.map +1 -0
- package/dist/shapes/index.d.ts +4 -0
- package/dist/shapes/index.d.ts.map +1 -0
- package/dist/shapes/index.js +4 -0
- package/dist/shapes/index.js.map +1 -0
- package/dist/shapes/registry.d.ts +20 -0
- package/dist/shapes/registry.d.ts.map +1 -0
- package/dist/shapes/registry.js +88 -0
- package/dist/shapes/registry.js.map +1 -0
- package/dist/shapes/types.d.ts +204 -0
- package/dist/shapes/types.d.ts.map +1 -0
- package/dist/shapes/types.js +2 -0
- package/dist/shapes/types.js.map +1 -0
- package/dist/snapshot-chunks/adapters/s3.d.ts +63 -0
- package/dist/snapshot-chunks/adapters/s3.d.ts.map +1 -0
- package/dist/snapshot-chunks/adapters/s3.js +50 -0
- package/dist/snapshot-chunks/adapters/s3.js.map +1 -0
- package/dist/snapshot-chunks/db-metadata.d.ts +33 -0
- package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -0
- package/dist/snapshot-chunks/db-metadata.js +169 -0
- package/dist/snapshot-chunks/db-metadata.js.map +1 -0
- package/dist/snapshot-chunks/index.d.ts +9 -0
- package/dist/snapshot-chunks/index.d.ts.map +1 -0
- package/dist/snapshot-chunks/index.js +9 -0
- package/dist/snapshot-chunks/index.js.map +1 -0
- package/dist/snapshot-chunks/types.d.ts +65 -0
- package/dist/snapshot-chunks/types.d.ts.map +1 -0
- package/dist/snapshot-chunks/types.js +8 -0
- package/dist/snapshot-chunks/types.js.map +1 -0
- package/dist/snapshot-chunks.d.ts +59 -0
- package/dist/snapshot-chunks.d.ts.map +1 -0
- package/dist/snapshot-chunks.js +202 -0
- package/dist/snapshot-chunks.js.map +1 -0
- package/dist/stats.d.ts +19 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +57 -0
- package/dist/stats.js.map +1 -0
- package/dist/subscriptions/index.d.ts +2 -0
- package/dist/subscriptions/index.d.ts.map +1 -0
- package/dist/subscriptions/index.js +2 -0
- package/dist/subscriptions/index.js.map +1 -0
- package/dist/subscriptions/resolve.d.ts +35 -0
- package/dist/subscriptions/resolve.d.ts.map +1 -0
- package/dist/subscriptions/resolve.js +134 -0
- package/dist/subscriptions/resolve.js.map +1 -0
- package/package.json +80 -0
- package/src/blobs/adapters/database.ts +290 -0
- package/src/blobs/adapters/s3.ts +271 -0
- package/src/blobs/index.ts +9 -0
- package/src/blobs/manager.ts +600 -0
- package/src/blobs/migrate.ts +150 -0
- package/src/blobs/types.ts +70 -0
- package/src/clients.ts +21 -0
- package/src/compaction.ts +77 -0
- package/src/dialect/index.ts +5 -0
- package/src/dialect/types.ts +222 -0
- package/src/helpers/conflict.ts +64 -0
- package/src/helpers/emitted-change.ts +69 -0
- package/src/helpers/index.ts +10 -0
- package/src/helpers/paginate.ts +82 -0
- package/src/helpers/scope-strings.ts +101 -0
- package/src/index.ts +28 -0
- package/src/migrate.ts +20 -0
- package/src/proxy/handler.ts +152 -0
- package/src/proxy/index.ts +18 -0
- package/src/proxy/mutation-detector.ts +83 -0
- package/src/proxy/oplog.ts +144 -0
- package/src/proxy/registry.ts +56 -0
- package/src/proxy/types.ts +46 -0
- package/src/prune.ts +200 -0
- package/src/pull.ts +551 -0
- package/src/push.ts +457 -0
- package/src/realtime/in-memory.ts +33 -0
- package/src/realtime/index.ts +5 -0
- package/src/realtime/types.ts +55 -0
- package/src/schema.ts +172 -0
- package/src/shapes/create-handler.ts +590 -0
- package/src/shapes/index.ts +3 -0
- package/src/shapes/registry.ts +109 -0
- package/src/shapes/types.ts +267 -0
- package/src/snapshot-chunks/adapters/s3.ts +68 -0
- package/src/snapshot-chunks/db-metadata.ts +238 -0
- package/src/snapshot-chunks/index.ts +9 -0
- package/src/snapshot-chunks/types.ts +79 -0
- package/src/snapshot-chunks.ts +301 -0
- package/src/stats.ts +104 -0
- package/src/subscriptions/index.ts +1 -0
- package/src/subscriptions/resolve.ts +185 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/server - Declarative server handler helper
|
|
3
|
+
*/
|
|
4
|
+
import type { ScopeValues, ScopeDefinition as SimpleScopeDefinition, StoredScopes, SyncOperation } from '@syncular/core';
|
|
5
|
+
import type { Selectable, Updateable } from 'kysely';
|
|
6
|
+
import type { SyncCoreDb } from '../schema';
|
|
7
|
+
import type { ServerApplyOperationContext, ServerContext, ServerTableHandler } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Authorization result from authorize callback.
|
|
10
|
+
*/
|
|
11
|
+
type AuthorizeResult = true | {
|
|
12
|
+
error: string;
|
|
13
|
+
code: string;
|
|
14
|
+
retriable?: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Scope definition for a column - maps scope variable to column name.
|
|
18
|
+
*/
|
|
19
|
+
export type ScopeColumnMap = Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Options for creating a declarative server handler.
|
|
22
|
+
*/
|
|
23
|
+
export interface CreateServerHandlerOptions<ServerDB extends SyncCoreDb, ClientDB, TableName extends keyof ServerDB & keyof ClientDB & string> {
|
|
24
|
+
/** Table name in the database */
|
|
25
|
+
table: TableName;
|
|
26
|
+
/**
|
|
27
|
+
* Scope definitions for this table.
|
|
28
|
+
* Can be simple strings (column auto-derived) or objects with explicit mapping.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // Simple: column auto-derived from placeholder
|
|
33
|
+
* scopes: ['user:{user_id}', 'org:{org_id}']
|
|
34
|
+
*
|
|
35
|
+
* // Explicit: when column differs from pattern variable
|
|
36
|
+
* scopes: [
|
|
37
|
+
* { pattern: 'user:{user_id}', column: 'owner_id' }
|
|
38
|
+
* ]
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
scopes: SimpleScopeDefinition[];
|
|
42
|
+
/** Primary key column name (default: 'id') */
|
|
43
|
+
primaryKey?: string;
|
|
44
|
+
/** Version column name (default: 'server_version') */
|
|
45
|
+
versionColumn?: string;
|
|
46
|
+
/** Tables this handler depends on (for bootstrap ordering) */
|
|
47
|
+
dependsOn?: string[];
|
|
48
|
+
/** TTL for cached snapshot chunks in ms */
|
|
49
|
+
snapshotChunkTtlMs?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve allowed scope values for the current actor.
|
|
52
|
+
* Called per request to determine what the actor can access.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* resolveScopes: async (ctx) => ({
|
|
56
|
+
* user_id: [ctx.actorId],
|
|
57
|
+
* project_id: await getProjectsForUser(ctx.db, ctx.actorId),
|
|
58
|
+
* })
|
|
59
|
+
*/
|
|
60
|
+
resolveScopes: (ctx: ServerContext<ServerDB>) => Promise<ScopeValues>;
|
|
61
|
+
/**
|
|
62
|
+
* Transform inbound row from client to server format.
|
|
63
|
+
* Use ctx.schemaVersion to handle older client versions.
|
|
64
|
+
*/
|
|
65
|
+
transformInbound?: (row: ClientDB[TableName], ctx: {
|
|
66
|
+
schemaVersion?: number;
|
|
67
|
+
}) => Updateable<ServerDB[TableName]>;
|
|
68
|
+
/**
|
|
69
|
+
* Transform outbound row from server to client format.
|
|
70
|
+
*/
|
|
71
|
+
transformOutbound?: (row: Selectable<ServerDB[TableName]>) => ClientDB[TableName];
|
|
72
|
+
/**
|
|
73
|
+
* Authorize an operation before applying.
|
|
74
|
+
* Return true to allow, or an error object to reject.
|
|
75
|
+
*/
|
|
76
|
+
authorize?: (ctx: ServerApplyOperationContext<ServerDB>, op: SyncOperation) => Promise<AuthorizeResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Override: Build snapshot query.
|
|
79
|
+
*/
|
|
80
|
+
snapshot?: ServerTableHandler<ServerDB>['snapshot'];
|
|
81
|
+
/**
|
|
82
|
+
* Override: Apply operation.
|
|
83
|
+
*/
|
|
84
|
+
applyOperation?: ServerTableHandler<ServerDB>['applyOperation'];
|
|
85
|
+
/**
|
|
86
|
+
* Custom scope extraction from row (for complex scope logic).
|
|
87
|
+
*/
|
|
88
|
+
extractScopes?: (row: Record<string, unknown>) => StoredScopes;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Create a declarative server table handler with sensible defaults.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* import { createServerHandler } from '@syncular/server';
|
|
96
|
+
* import type { ServerDb } from '../db';
|
|
97
|
+
* import type { ClientDb } from '../../shared/client-db.generated';
|
|
98
|
+
*
|
|
99
|
+
* export const tasksHandler = createServerHandler<ServerDb, ClientDb, 'tasks'>({
|
|
100
|
+
* table: 'tasks',
|
|
101
|
+
* scopes: ['user:{user_id}'], // column auto-derived from placeholder
|
|
102
|
+
* resolveScopes: async (ctx) => ({
|
|
103
|
+
* user_id: [ctx.actorId],
|
|
104
|
+
* }),
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* // With custom column mapping:
|
|
108
|
+
* export const tasksHandler = createServerHandler<ServerDb, ClientDb, 'tasks'>({
|
|
109
|
+
* table: 'tasks',
|
|
110
|
+
* scopes: [{ pattern: 'user:{user_id}', column: 'owner_id' }],
|
|
111
|
+
* resolveScopes: async (ctx) => ({
|
|
112
|
+
* user_id: [ctx.actorId],
|
|
113
|
+
* }),
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function createServerHandler<ServerDB extends SyncCoreDb, ClientDB, TableName extends keyof ServerDB & keyof ClientDB & string>(options: CreateServerHandlerOptions<ServerDB, ClientDB, TableName>): ServerTableHandler<ServerDB>;
|
|
118
|
+
export {};
|
|
119
|
+
//# sourceMappingURL=create-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-handler.d.ts","sourceRoot":"","sources":["../../src/shapes/create-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,IAAI,qBAAqB,EACxC,YAAY,EACZ,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAMV,UAAU,EAEV,UAAU,EAGX,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAGV,2BAA2B,EAC3B,aAAa,EAEb,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,KAAK,eAAe,GAChB,IAAI,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAoBzD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,0BAA0B,CACzC,QAAQ,SAAS,UAAU,EAC3B,QAAQ,EACR,SAAS,SAAS,MAAM,QAAQ,GAAG,MAAM,QAAQ,GAAG,MAAM;IAE1D,iCAAiC;IACjC,KAAK,EAAE,SAAS,CAAC;IAEjB;;;;;;;;;;;;;;OAcG;IACH,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAEhC,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,2CAA2C;IAC3C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;;;;;OASG;IACH,aAAa,EAAE,CAAC,GAAG,EAAE,aAAa,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAEtE;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CACjB,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC,EACxB,GAAG,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,KAC5B,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAErC;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAClB,GAAG,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,KACjC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,EAAE,CACV,GAAG,EAAE,2BAA2B,CAAC,QAAQ,CAAC,EAC1C,EAAE,EAAE,aAAa,KACd,OAAO,CAAC,eAAe,CAAC,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;IAEpD;;OAEG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAEhE;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,YAAY,CAAC;CAChE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,SAAS,UAAU,EAC3B,QAAQ,EACR,SAAS,SAAS,MAAM,QAAQ,GAAG,MAAM,QAAQ,GAAG,MAAM,EAE1D,OAAO,EAAE,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,GACjE,kBAAkB,CAAC,QAAQ,CAAC,CA+Y9B"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/server - Declarative server handler helper
|
|
3
|
+
*/
|
|
4
|
+
import { extractScopeVars, normalizeScopes } from '@syncular/core';
|
|
5
|
+
function classifyConstraintViolationCode(message) {
|
|
6
|
+
const normalized = message.toLowerCase();
|
|
7
|
+
if (normalized.includes('not null'))
|
|
8
|
+
return 'NOT_NULL_CONSTRAINT';
|
|
9
|
+
if (normalized.includes('unique'))
|
|
10
|
+
return 'UNIQUE_CONSTRAINT';
|
|
11
|
+
if (normalized.includes('foreign key'))
|
|
12
|
+
return 'FOREIGN_KEY_CONSTRAINT';
|
|
13
|
+
return 'CONSTRAINT_VIOLATION';
|
|
14
|
+
}
|
|
15
|
+
function isConstraintViolationError(message) {
|
|
16
|
+
const normalized = message.toLowerCase();
|
|
17
|
+
return (normalized.includes('constraint') ||
|
|
18
|
+
normalized.includes('not null') ||
|
|
19
|
+
normalized.includes('foreign key') ||
|
|
20
|
+
normalized.includes('unique'));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a declarative server table handler with sensible defaults.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { createServerHandler } from '@syncular/server';
|
|
28
|
+
* import type { ServerDb } from '../db';
|
|
29
|
+
* import type { ClientDb } from '../../shared/client-db.generated';
|
|
30
|
+
*
|
|
31
|
+
* export const tasksHandler = createServerHandler<ServerDb, ClientDb, 'tasks'>({
|
|
32
|
+
* table: 'tasks',
|
|
33
|
+
* scopes: ['user:{user_id}'], // column auto-derived from placeholder
|
|
34
|
+
* resolveScopes: async (ctx) => ({
|
|
35
|
+
* user_id: [ctx.actorId],
|
|
36
|
+
* }),
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // With custom column mapping:
|
|
40
|
+
* export const tasksHandler = createServerHandler<ServerDb, ClientDb, 'tasks'>({
|
|
41
|
+
* table: 'tasks',
|
|
42
|
+
* scopes: [{ pattern: 'user:{user_id}', column: 'owner_id' }],
|
|
43
|
+
* resolveScopes: async (ctx) => ({
|
|
44
|
+
* user_id: [ctx.actorId],
|
|
45
|
+
* }),
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function createServerHandler(options) {
|
|
50
|
+
const { table, scopes: scopeDefs, primaryKey = 'id', versionColumn = 'server_version', dependsOn, snapshotChunkTtlMs, resolveScopes, transformInbound, transformOutbound, authorize, extractScopes: customExtractScopes, } = options;
|
|
51
|
+
// Normalize scopes to pattern map and extract patterns/columns
|
|
52
|
+
const scopeColumnMap = normalizeScopes(scopeDefs);
|
|
53
|
+
const scopePatterns = Object.keys(scopeColumnMap);
|
|
54
|
+
const scopeColumns = {};
|
|
55
|
+
for (const [pattern, columnName] of Object.entries(scopeColumnMap)) {
|
|
56
|
+
const vars = extractScopeVars(pattern);
|
|
57
|
+
if (vars.length !== 1) {
|
|
58
|
+
throw new Error(`Scope pattern "${pattern}" must contain exactly one placeholder (got ${vars.length}).`);
|
|
59
|
+
}
|
|
60
|
+
const varName = vars[0];
|
|
61
|
+
const existing = scopeColumns[varName];
|
|
62
|
+
if (existing && existing !== columnName) {
|
|
63
|
+
throw new Error(`Scope variable "${varName}" is mapped to multiple columns: "${existing}" and "${columnName}".`);
|
|
64
|
+
}
|
|
65
|
+
scopeColumns[varName] = columnName;
|
|
66
|
+
}
|
|
67
|
+
// Default extractScopes from scope columns
|
|
68
|
+
const defaultExtractScopes = (row) => {
|
|
69
|
+
const scopes = {};
|
|
70
|
+
for (const [varName, columnName] of Object.entries(scopeColumns)) {
|
|
71
|
+
const raw = row[columnName];
|
|
72
|
+
if (raw === null || raw === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
const value = String(raw);
|
|
75
|
+
if (value.length > 0) {
|
|
76
|
+
scopes[varName] = value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return scopes;
|
|
80
|
+
};
|
|
81
|
+
const extractScopesImpl = customExtractScopes ?? defaultExtractScopes;
|
|
82
|
+
// Default snapshot implementation
|
|
83
|
+
const defaultSnapshot = async (ctx, _params) => {
|
|
84
|
+
const trx = ctx.db;
|
|
85
|
+
const { ref } = trx.dynamic;
|
|
86
|
+
const scopeValues = ctx.scopeValues;
|
|
87
|
+
const pageSize = Math.max(1, Math.min(10_000, ctx.limit));
|
|
88
|
+
// Build dynamic WHERE conditions
|
|
89
|
+
const whereConditions = [];
|
|
90
|
+
for (const [varName, columnName] of Object.entries(scopeColumns)) {
|
|
91
|
+
const values = scopeValues[varName];
|
|
92
|
+
if (values === undefined)
|
|
93
|
+
continue;
|
|
94
|
+
const normalized = Array.isArray(values) ? values : [values];
|
|
95
|
+
if (normalized.length === 0)
|
|
96
|
+
continue;
|
|
97
|
+
whereConditions.push({ column: columnName, values: normalized });
|
|
98
|
+
}
|
|
99
|
+
let q = trx.selectFrom(table).selectAll();
|
|
100
|
+
for (const cond of whereConditions) {
|
|
101
|
+
if (cond.values.length === 1) {
|
|
102
|
+
q = q.where(ref(cond.column), '=', cond.values[0]);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
q = q.where(ref(cond.column), 'in', cond.values);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (ctx.cursor !== null) {
|
|
109
|
+
q = q.where(ref(primaryKey), '>', ctx.cursor);
|
|
110
|
+
}
|
|
111
|
+
const rows = await q
|
|
112
|
+
.orderBy(ref(primaryKey), 'asc')
|
|
113
|
+
.limit(pageSize + 1)
|
|
114
|
+
.execute();
|
|
115
|
+
const hasMore = rows.length > pageSize;
|
|
116
|
+
const pageRows = hasMore ? rows.slice(0, pageSize) : rows;
|
|
117
|
+
const lastRow = pageRows[pageRows.length - 1];
|
|
118
|
+
const nextCursor = hasMore
|
|
119
|
+
? lastRow?.[primaryKey]
|
|
120
|
+
: null;
|
|
121
|
+
// Transform outbound if provided
|
|
122
|
+
const outputRows = transformOutbound
|
|
123
|
+
? pageRows.map((r) => transformOutbound(r))
|
|
124
|
+
: pageRows;
|
|
125
|
+
return {
|
|
126
|
+
rows: outputRows,
|
|
127
|
+
nextCursor: typeof nextCursor === 'string' && nextCursor.length > 0
|
|
128
|
+
? nextCursor
|
|
129
|
+
: null,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
// Default applyOperation implementation
|
|
133
|
+
const defaultApplyOperation = async (ctx, op, opIndex) => {
|
|
134
|
+
const trx = ctx.trx;
|
|
135
|
+
const { ref } = trx.dynamic;
|
|
136
|
+
if (op.table !== table) {
|
|
137
|
+
return {
|
|
138
|
+
result: {
|
|
139
|
+
opIndex,
|
|
140
|
+
status: 'error',
|
|
141
|
+
error: `UNKNOWN_TABLE:${op.table}`,
|
|
142
|
+
code: 'UNKNOWN_TABLE',
|
|
143
|
+
retriable: false,
|
|
144
|
+
},
|
|
145
|
+
emittedChanges: [],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Run authorization if provided
|
|
149
|
+
if (authorize) {
|
|
150
|
+
const authResult = await authorize(ctx, op);
|
|
151
|
+
if (authResult !== true) {
|
|
152
|
+
return {
|
|
153
|
+
result: {
|
|
154
|
+
opIndex,
|
|
155
|
+
status: 'error',
|
|
156
|
+
error: authResult.error,
|
|
157
|
+
code: authResult.code,
|
|
158
|
+
retriable: authResult.retriable ?? false,
|
|
159
|
+
},
|
|
160
|
+
emittedChanges: [],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Handle delete
|
|
165
|
+
if (op.op === 'delete') {
|
|
166
|
+
const existing = await trx.selectFrom(table).selectAll()
|
|
167
|
+
.where(ref(primaryKey), '=', op.row_id)
|
|
168
|
+
.executeTakeFirst();
|
|
169
|
+
if (!existing) {
|
|
170
|
+
return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
|
|
171
|
+
}
|
|
172
|
+
// Extract scopes from existing row for the delete emission
|
|
173
|
+
const scopes = extractScopesImpl(existing);
|
|
174
|
+
await trx.deleteFrom(table)
|
|
175
|
+
.where(ref(primaryKey), '=', op.row_id)
|
|
176
|
+
.execute();
|
|
177
|
+
const emitted = {
|
|
178
|
+
table,
|
|
179
|
+
row_id: op.row_id,
|
|
180
|
+
op: 'delete',
|
|
181
|
+
row_json: null,
|
|
182
|
+
row_version: null,
|
|
183
|
+
scopes,
|
|
184
|
+
};
|
|
185
|
+
return {
|
|
186
|
+
result: { opIndex, status: 'applied' },
|
|
187
|
+
emittedChanges: [emitted],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Handle upsert
|
|
191
|
+
const rawPayload = op.payload ?? {};
|
|
192
|
+
const payload = transformInbound
|
|
193
|
+
? transformInbound(rawPayload, {
|
|
194
|
+
schemaVersion: ctx.schemaVersion,
|
|
195
|
+
})
|
|
196
|
+
: rawPayload;
|
|
197
|
+
// Check for existing row
|
|
198
|
+
const existing = await trx.selectFrom(table).selectAll()
|
|
199
|
+
.where(ref(primaryKey), '=', op.row_id)
|
|
200
|
+
.executeTakeFirst();
|
|
201
|
+
const existingRow = existing;
|
|
202
|
+
const existingVersion = existingRow?.[versionColumn] ?? 0;
|
|
203
|
+
// Check version conflict
|
|
204
|
+
if (existing &&
|
|
205
|
+
op.base_version != null &&
|
|
206
|
+
existingVersion !== op.base_version) {
|
|
207
|
+
return {
|
|
208
|
+
result: {
|
|
209
|
+
opIndex,
|
|
210
|
+
status: 'conflict',
|
|
211
|
+
message: `Version conflict: server=${existingVersion}, base=${op.base_version}`,
|
|
212
|
+
server_version: existingVersion,
|
|
213
|
+
server_row: transformOutbound
|
|
214
|
+
? transformOutbound(existing)
|
|
215
|
+
: existing,
|
|
216
|
+
},
|
|
217
|
+
emittedChanges: [],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// If the client provided a base version, they expected this row to exist.
|
|
221
|
+
// A missing row usually indicates stale local state after a server reset.
|
|
222
|
+
if (!existing && op.base_version != null) {
|
|
223
|
+
return {
|
|
224
|
+
result: {
|
|
225
|
+
opIndex,
|
|
226
|
+
status: 'error',
|
|
227
|
+
error: 'ROW_NOT_FOUND_FOR_BASE_VERSION',
|
|
228
|
+
code: 'ROW_MISSING',
|
|
229
|
+
retriable: false,
|
|
230
|
+
},
|
|
231
|
+
emittedChanges: [],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const nextVersion = existingVersion + 1;
|
|
235
|
+
let updated;
|
|
236
|
+
let constraintError = null;
|
|
237
|
+
try {
|
|
238
|
+
if (existing) {
|
|
239
|
+
// Update - merge payload with existing
|
|
240
|
+
const updateSet = {
|
|
241
|
+
...payload,
|
|
242
|
+
[versionColumn]: nextVersion,
|
|
243
|
+
};
|
|
244
|
+
// Don't update primary key or scope columns
|
|
245
|
+
delete updateSet[primaryKey];
|
|
246
|
+
for (const col of Object.values(scopeColumns)) {
|
|
247
|
+
delete updateSet[col];
|
|
248
|
+
}
|
|
249
|
+
await trx.updateTable(table)
|
|
250
|
+
.set(updateSet)
|
|
251
|
+
.where(ref(primaryKey), '=', op.row_id)
|
|
252
|
+
.execute();
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// Insert
|
|
256
|
+
const insertValues = {
|
|
257
|
+
...payload,
|
|
258
|
+
[primaryKey]: op.row_id,
|
|
259
|
+
[versionColumn]: 1,
|
|
260
|
+
};
|
|
261
|
+
await trx.insertInto(table)
|
|
262
|
+
.values(insertValues)
|
|
263
|
+
.execute();
|
|
264
|
+
}
|
|
265
|
+
// Read back the updated row
|
|
266
|
+
updated = await trx.selectFrom(table).selectAll()
|
|
267
|
+
.where(ref(primaryKey), '=', op.row_id)
|
|
268
|
+
.executeTakeFirstOrThrow();
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
272
|
+
if (!isConstraintViolationError(message)) {
|
|
273
|
+
throw err;
|
|
274
|
+
}
|
|
275
|
+
constraintError = {
|
|
276
|
+
message,
|
|
277
|
+
code: classifyConstraintViolationCode(message),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
if (constraintError) {
|
|
281
|
+
return {
|
|
282
|
+
result: {
|
|
283
|
+
opIndex,
|
|
284
|
+
status: 'error',
|
|
285
|
+
error: constraintError.message,
|
|
286
|
+
code: constraintError.code,
|
|
287
|
+
retriable: false,
|
|
288
|
+
},
|
|
289
|
+
emittedChanges: [],
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
if (!updated) {
|
|
293
|
+
throw new Error('Updated row is missing after applyOperation');
|
|
294
|
+
}
|
|
295
|
+
const updatedRow = updated;
|
|
296
|
+
const rowVersion = updatedRow[versionColumn] ?? 1;
|
|
297
|
+
// Extract scopes from updated row
|
|
298
|
+
const scopes = extractScopesImpl(updatedRow);
|
|
299
|
+
// Transform outbound for emitted change
|
|
300
|
+
const rowJson = transformOutbound
|
|
301
|
+
? transformOutbound(updated)
|
|
302
|
+
: updated;
|
|
303
|
+
const emitted = {
|
|
304
|
+
table,
|
|
305
|
+
row_id: op.row_id,
|
|
306
|
+
op: 'upsert',
|
|
307
|
+
row_json: rowJson,
|
|
308
|
+
row_version: rowVersion,
|
|
309
|
+
scopes,
|
|
310
|
+
};
|
|
311
|
+
return {
|
|
312
|
+
result: { opIndex, status: 'applied' },
|
|
313
|
+
emittedChanges: [emitted],
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
table,
|
|
318
|
+
scopePatterns,
|
|
319
|
+
dependsOn,
|
|
320
|
+
snapshotChunkTtlMs,
|
|
321
|
+
resolveScopes,
|
|
322
|
+
extractScopes: extractScopesImpl,
|
|
323
|
+
snapshot: options.snapshot ?? defaultSnapshot,
|
|
324
|
+
applyOperation: options.applyOperation ?? defaultApplyOperation,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
//# sourceMappingURL=create-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-handler.js","sourceRoot":"","sources":["../../src/shapes/create-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shapes/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shapes/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SyncCoreDb } from '../schema';
|
|
2
|
+
import type { ServerTableHandler } from './types';
|
|
3
|
+
export declare class TableRegistry<DB extends SyncCoreDb = SyncCoreDb> {
|
|
4
|
+
private tables;
|
|
5
|
+
register(handler: ServerTableHandler<DB>): this;
|
|
6
|
+
get(table: string): ServerTableHandler<DB> | undefined;
|
|
7
|
+
getOrThrow(table: string): ServerTableHandler<DB>;
|
|
8
|
+
getAll(): ServerTableHandler<DB>[];
|
|
9
|
+
/**
|
|
10
|
+
* Return tables in topological order (parents before children).
|
|
11
|
+
* Throws if a circular dependency is detected.
|
|
12
|
+
*/
|
|
13
|
+
getBootstrapOrder(): ServerTableHandler<DB>[];
|
|
14
|
+
/**
|
|
15
|
+
* Return bootstrap order for a target table and its dependencies.
|
|
16
|
+
* Parents are returned before children.
|
|
17
|
+
*/
|
|
18
|
+
getBootstrapOrderFor(table: string): ServerTableHandler<DB>[];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/shapes/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,qBAAa,aAAa,CAAC,EAAE,SAAS,UAAU,GAAG,UAAU;IAC3D,OAAO,CAAC,MAAM,CAA6C;IAE3D,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAAE,CAAC,GAAG,IAAI,CAgB9C;IAED,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC,GAAG,SAAS,CAErD;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAIhD;IAED,MAAM,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAEjC;IAED;;;OAGG;IACH,iBAAiB,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE,CA8B5C;IAED;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC,EAAE,CA6B5D;CACF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export class TableRegistry {
|
|
2
|
+
tables = new Map();
|
|
3
|
+
register(handler) {
|
|
4
|
+
if (this.tables.has(handler.table)) {
|
|
5
|
+
throw new Error(`Table "${handler.table}" is already registered`);
|
|
6
|
+
}
|
|
7
|
+
// Validate dependencies exist
|
|
8
|
+
for (const dep of handler.dependsOn ?? []) {
|
|
9
|
+
if (!this.tables.has(dep)) {
|
|
10
|
+
throw new Error(`Table "${handler.table}" depends on unknown table "${dep}"`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
this.tables.set(handler.table, handler);
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
get(table) {
|
|
17
|
+
return this.tables.get(table);
|
|
18
|
+
}
|
|
19
|
+
getOrThrow(table) {
|
|
20
|
+
const handler = this.tables.get(table);
|
|
21
|
+
if (!handler)
|
|
22
|
+
throw new Error(`Unknown table: ${table}`);
|
|
23
|
+
return handler;
|
|
24
|
+
}
|
|
25
|
+
getAll() {
|
|
26
|
+
return Array.from(this.tables.values());
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Return tables in topological order (parents before children).
|
|
30
|
+
* Throws if a circular dependency is detected.
|
|
31
|
+
*/
|
|
32
|
+
getBootstrapOrder() {
|
|
33
|
+
const visited = new Set();
|
|
34
|
+
const sorted = [];
|
|
35
|
+
const visiting = new Set();
|
|
36
|
+
const visit = (table) => {
|
|
37
|
+
if (visited.has(table))
|
|
38
|
+
return;
|
|
39
|
+
if (visiting.has(table)) {
|
|
40
|
+
throw new Error(`Circular dependency detected involving table "${table}"`);
|
|
41
|
+
}
|
|
42
|
+
visiting.add(table);
|
|
43
|
+
const handler = this.tables.get(table);
|
|
44
|
+
if (handler) {
|
|
45
|
+
for (const dep of handler.dependsOn ?? []) {
|
|
46
|
+
visit(dep);
|
|
47
|
+
}
|
|
48
|
+
visited.add(table);
|
|
49
|
+
visiting.delete(table);
|
|
50
|
+
sorted.push(handler);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
for (const table of this.tables.keys()) {
|
|
54
|
+
visit(table);
|
|
55
|
+
}
|
|
56
|
+
return sorted;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Return bootstrap order for a target table and its dependencies.
|
|
60
|
+
* Parents are returned before children.
|
|
61
|
+
*/
|
|
62
|
+
getBootstrapOrderFor(table) {
|
|
63
|
+
const visited = new Set();
|
|
64
|
+
const sorted = [];
|
|
65
|
+
const visiting = new Set();
|
|
66
|
+
const visit = (name) => {
|
|
67
|
+
if (visited.has(name))
|
|
68
|
+
return;
|
|
69
|
+
if (visiting.has(name)) {
|
|
70
|
+
throw new Error(`Circular dependency detected involving table "${name}"`);
|
|
71
|
+
}
|
|
72
|
+
const handler = this.tables.get(name);
|
|
73
|
+
if (!handler) {
|
|
74
|
+
throw new Error(`Unknown table: ${name}`);
|
|
75
|
+
}
|
|
76
|
+
visiting.add(name);
|
|
77
|
+
for (const dep of handler.dependsOn ?? []) {
|
|
78
|
+
visit(dep);
|
|
79
|
+
}
|
|
80
|
+
visiting.delete(name);
|
|
81
|
+
visited.add(name);
|
|
82
|
+
sorted.push(handler);
|
|
83
|
+
};
|
|
84
|
+
visit(table);
|
|
85
|
+
return sorted;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/shapes/registry.ts"],"names":[],"mappings":"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"}
|