@syncular/server 0.0.5-44 → 0.0.6-101

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 (96) hide show
  1. package/dist/dialect/base.d.ts +3 -3
  2. package/dist/dialect/base.d.ts.map +1 -1
  3. package/dist/dialect/base.js.map +1 -1
  4. package/dist/dialect/types.d.ts +5 -7
  5. package/dist/dialect/types.d.ts.map +1 -1
  6. package/dist/handlers/collection.d.ts +12 -0
  7. package/dist/handlers/collection.d.ts.map +1 -0
  8. package/dist/handlers/collection.js +64 -0
  9. package/dist/handlers/collection.js.map +1 -0
  10. package/dist/handlers/create-handler.d.ts +10 -10
  11. package/dist/handlers/create-handler.d.ts.map +1 -1
  12. package/dist/handlers/create-handler.js +101 -69
  13. package/dist/handlers/create-handler.js.map +1 -1
  14. package/dist/handlers/index.d.ts +1 -1
  15. package/dist/handlers/index.d.ts.map +1 -1
  16. package/dist/handlers/index.js +1 -1
  17. package/dist/handlers/index.js.map +1 -1
  18. package/dist/handlers/types.d.ts +18 -12
  19. package/dist/handlers/types.d.ts.map +1 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +1 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/notify.js +1 -1
  25. package/dist/notify.js.map +1 -1
  26. package/dist/proxy/collection.d.ts +9 -0
  27. package/dist/proxy/collection.d.ts.map +1 -0
  28. package/dist/proxy/collection.js +21 -0
  29. package/dist/proxy/collection.js.map +1 -0
  30. package/dist/proxy/handler.d.ts +3 -3
  31. package/dist/proxy/handler.d.ts.map +1 -1
  32. package/dist/proxy/handler.js +2 -1
  33. package/dist/proxy/handler.js.map +1 -1
  34. package/dist/proxy/index.d.ts +1 -1
  35. package/dist/proxy/index.d.ts.map +1 -1
  36. package/dist/proxy/index.js +3 -3
  37. package/dist/proxy/index.js.map +1 -1
  38. package/dist/proxy/oplog.js +1 -1
  39. package/dist/proxy/oplog.js.map +1 -1
  40. package/dist/pull.d.ts +12 -5
  41. package/dist/pull.d.ts.map +1 -1
  42. package/dist/pull.js +101 -55
  43. package/dist/pull.js.map +1 -1
  44. package/dist/push.d.ts +5 -5
  45. package/dist/push.d.ts.map +1 -1
  46. package/dist/push.js +6 -4
  47. package/dist/push.js.map +1 -1
  48. package/dist/subscriptions/cache.d.ts +55 -0
  49. package/dist/subscriptions/cache.d.ts.map +1 -0
  50. package/dist/subscriptions/cache.js +206 -0
  51. package/dist/subscriptions/cache.js.map +1 -0
  52. package/dist/subscriptions/index.d.ts +1 -0
  53. package/dist/subscriptions/index.d.ts.map +1 -1
  54. package/dist/subscriptions/index.js +1 -0
  55. package/dist/subscriptions/index.js.map +1 -1
  56. package/dist/subscriptions/resolve.d.ts +7 -4
  57. package/dist/subscriptions/resolve.d.ts.map +1 -1
  58. package/dist/subscriptions/resolve.js +74 -11
  59. package/dist/subscriptions/resolve.js.map +1 -1
  60. package/dist/sync.d.ts +21 -0
  61. package/dist/sync.d.ts.map +1 -0
  62. package/dist/sync.js +23 -0
  63. package/dist/sync.js.map +1 -0
  64. package/package.json +3 -3
  65. package/src/dialect/base.ts +5 -3
  66. package/src/dialect/types.ts +11 -8
  67. package/src/handlers/collection.ts +121 -0
  68. package/src/handlers/create-handler.ts +163 -109
  69. package/src/handlers/index.ts +1 -1
  70. package/src/handlers/types.ts +29 -12
  71. package/src/index.ts +1 -0
  72. package/src/notify.test.ts +25 -21
  73. package/src/notify.ts +1 -1
  74. package/src/proxy/collection.ts +39 -0
  75. package/src/proxy/handler.test.ts +15 -9
  76. package/src/proxy/handler.ts +4 -4
  77. package/src/proxy/index.ts +8 -3
  78. package/src/proxy/oplog.ts +1 -1
  79. package/src/pull.ts +155 -73
  80. package/src/push.ts +16 -9
  81. package/src/snapshot-chunks/db-metadata.test.ts +6 -3
  82. package/src/subscriptions/cache.ts +318 -0
  83. package/src/subscriptions/index.ts +1 -0
  84. package/src/subscriptions/resolve.test.ts +180 -0
  85. package/src/subscriptions/resolve.ts +94 -18
  86. package/src/sync.ts +101 -0
  87. package/dist/handlers/registry.d.ts +0 -20
  88. package/dist/handlers/registry.d.ts.map +0 -1
  89. package/dist/handlers/registry.js +0 -88
  90. package/dist/handlers/registry.js.map +0 -1
  91. package/dist/proxy/registry.d.ts +0 -35
  92. package/dist/proxy/registry.d.ts.map +0 -1
  93. package/dist/proxy/registry.js +0 -49
  94. package/dist/proxy/registry.js.map +0 -1
  95. package/src/handlers/registry.ts +0 -109
  96. package/src/proxy/registry.ts +0 -56
@@ -4,8 +4,13 @@ import {
4
4
  type SyncSubscriptionRequest,
5
5
  } from '@syncular/core';
6
6
  import type { Kysely } from 'kysely';
7
- import type { TableRegistry } from '../handlers/registry';
7
+ import {
8
+ getServerHandler,
9
+ type ServerHandlerCollection,
10
+ } from '../handlers/collection';
11
+ import type { SyncServerAuth } from '../handlers/types';
8
12
  import type { SyncCoreDb } from '../schema';
13
+ import { createDefaultScopeCacheKey, type ScopeCacheBackend } from './cache';
9
14
 
10
15
  export class InvalidSubscriptionScopeError extends Error {
11
16
  constructor(message: string) {
@@ -132,14 +137,17 @@ function validateScopeKeys(args: {
132
137
  */
133
138
  export async function resolveEffectiveScopesForSubscriptions<
134
139
  DB extends SyncCoreDb,
140
+ Auth extends SyncServerAuth,
135
141
  >(args: {
136
142
  db: Kysely<DB>;
137
- actorId: string;
143
+ auth: Auth;
138
144
  subscriptions: SyncSubscriptionRequest[];
139
- handlers: TableRegistry<DB>;
145
+ handlers: ServerHandlerCollection<DB, Auth>;
146
+ scopeCache?: ScopeCacheBackend;
140
147
  }): Promise<ResolvedSubscription[]> {
141
148
  const out: ResolvedSubscription[] = [];
142
149
  const seenIds = new Set<string>();
150
+ const requestScopeCache = new Map<string, ScopeValues | null>();
143
151
 
144
152
  for (const sub of args.subscriptions) {
145
153
  if (!sub.id || typeof sub.id !== 'string') {
@@ -158,7 +166,7 @@ export async function resolveEffectiveScopesForSubscriptions<
158
166
  );
159
167
  }
160
168
 
161
- const handler = args.handlers.get(sub.table);
169
+ const handler = getServerHandler(args.handlers, sub.table);
162
170
  if (!handler) {
163
171
  throw new InvalidSubscriptionScopeError(
164
172
  `Unknown table: ${sub.table} for subscription ${sub.id}`
@@ -175,20 +183,88 @@ export async function resolveEffectiveScopesForSubscriptions<
175
183
  table: sub.table,
176
184
  });
177
185
 
178
- // Get allowed scopes from the handler
179
- let allowed: ScopeValues;
180
- try {
181
- allowed = await handler.resolveScopes({
182
- db: args.db,
183
- actorId: args.actorId,
184
- });
185
- } catch (resolveErr) {
186
- // Scope resolution failed - mark subscription as revoked
187
- // rather than failing the entire pull
188
- console.error(
189
- `[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`,
190
- resolveErr
191
- );
186
+ // Resolve allowed scopes with request-local memoization first, then
187
+ // optional shared cache backend, then table handler.
188
+ const scopeCacheKey = createDefaultScopeCacheKey({
189
+ auth: args.auth,
190
+ table: sub.table,
191
+ });
192
+ let allowed: ScopeValues | null;
193
+ if (requestScopeCache.has(scopeCacheKey)) {
194
+ allowed = requestScopeCache.get(scopeCacheKey) ?? null;
195
+ } else {
196
+ allowed = null;
197
+ let sharedCacheHit = false;
198
+
199
+ if (args.scopeCache) {
200
+ try {
201
+ const cachedAllowed = await args.scopeCache.get({
202
+ db: args.db,
203
+ auth: args.auth,
204
+ table: sub.table,
205
+ cacheKey: scopeCacheKey,
206
+ });
207
+ if (cachedAllowed !== null) {
208
+ allowed = cachedAllowed;
209
+ sharedCacheHit = true;
210
+ }
211
+ } catch (cacheErr) {
212
+ console.error(
213
+ `[scopeCache.get] Failed for table ${sub.table}, subscription ${sub.id}:`,
214
+ cacheErr
215
+ );
216
+ }
217
+ }
218
+
219
+ if (!sharedCacheHit) {
220
+ try {
221
+ allowed = await handler.resolveScopes({
222
+ db: args.db,
223
+ actorId: args.auth.actorId,
224
+ auth: args.auth,
225
+ });
226
+ } catch (resolveErr) {
227
+ // Scope resolution failed - mark subscription as revoked
228
+ // rather than failing the entire pull
229
+ console.error(
230
+ `[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`,
231
+ resolveErr
232
+ );
233
+ requestScopeCache.set(scopeCacheKey, null);
234
+ out.push({
235
+ id: sub.id,
236
+ table: sub.table,
237
+ scopes: {},
238
+ params: sub.params,
239
+ cursor: sub.cursor,
240
+ bootstrapState: sub.bootstrapState ?? null,
241
+ status: 'revoked',
242
+ });
243
+ continue;
244
+ }
245
+
246
+ if (args.scopeCache && allowed !== null) {
247
+ try {
248
+ await args.scopeCache.set({
249
+ db: args.db,
250
+ auth: args.auth,
251
+ table: sub.table,
252
+ cacheKey: scopeCacheKey,
253
+ scopes: allowed,
254
+ });
255
+ } catch (cacheErr) {
256
+ console.error(
257
+ `[scopeCache.set] Failed for table ${sub.table}, subscription ${sub.id}:`,
258
+ cacheErr
259
+ );
260
+ }
261
+ }
262
+ }
263
+
264
+ requestScopeCache.set(scopeCacheKey, allowed);
265
+ }
266
+
267
+ if (!allowed) {
192
268
  out.push({
193
269
  id: sub.id,
194
270
  table: sub.table,
package/src/sync.ts ADDED
@@ -0,0 +1,101 @@
1
+ import type {
2
+ ColumnCodecDialect,
3
+ ColumnCodecSource,
4
+ ScopeDefinition,
5
+ } from '@syncular/core';
6
+ import {
7
+ type CreateServerHandlerOptions,
8
+ createServerHandler,
9
+ } from './handlers';
10
+ import type { ServerTableHandler, SyncServerAuth } from './handlers/types';
11
+ import type { SyncCoreDb } from './schema';
12
+
13
+ type SharedTableName<ServerDB, ClientDB> = keyof ServerDB &
14
+ keyof ClientDB &
15
+ string;
16
+
17
+ export type ServerSyncHandlerOptionsForTable<
18
+ ServerDB extends SyncCoreDb,
19
+ ClientDB,
20
+ TableName extends SharedTableName<ServerDB, ClientDB>,
21
+ Auth extends SyncServerAuth,
22
+ ScopeDefs extends readonly ScopeDefinition[],
23
+ > = Omit<
24
+ CreateServerHandlerOptions<ServerDB, ClientDB, TableName, Auth, ScopeDefs>,
25
+ 'codecs' | 'codecDialect'
26
+ >;
27
+
28
+ export interface ServerSyncConfig<
29
+ ServerDB extends SyncCoreDb = SyncCoreDb,
30
+ Auth extends SyncServerAuth = SyncServerAuth,
31
+ > {
32
+ authenticate: (request: Request) => Promise<Auth | null> | Auth | null;
33
+ handlers: ServerTableHandler<ServerDB, Auth>[];
34
+ }
35
+
36
+ export interface DefineServerSyncOptions<Auth extends SyncServerAuth> {
37
+ authenticate: (request: Request) => Promise<Auth | null> | Auth | null;
38
+ codecs?: ColumnCodecSource;
39
+ codecDialect?: ColumnCodecDialect;
40
+ }
41
+
42
+ export interface ServerSyncBuilder<
43
+ ServerDB extends SyncCoreDb,
44
+ ClientDB,
45
+ ScopeDefs extends readonly ScopeDefinition[],
46
+ Auth extends SyncServerAuth,
47
+ > extends ServerSyncConfig<ServerDB, Auth> {
48
+ addHandler<TableName extends SharedTableName<ServerDB, ClientDB>>(
49
+ options: ServerSyncHandlerOptionsForTable<
50
+ ServerDB,
51
+ ClientDB,
52
+ TableName,
53
+ Auth,
54
+ ScopeDefs
55
+ >
56
+ ): this;
57
+ }
58
+
59
+ export function defineServerSync<
60
+ ServerDB extends SyncCoreDb,
61
+ ClientDB,
62
+ ScopeDefs extends readonly ScopeDefinition[],
63
+ Auth extends SyncServerAuth,
64
+ >(
65
+ options: DefineServerSyncOptions<Auth>
66
+ ): ServerSyncBuilder<ServerDB, ClientDB, ScopeDefs, Auth> {
67
+ const handlers: ServerTableHandler<ServerDB, Auth>[] = [];
68
+ const registeredTables = new Set<string>();
69
+
70
+ const sync: ServerSyncBuilder<ServerDB, ClientDB, ScopeDefs, Auth> = {
71
+ authenticate: options.authenticate,
72
+ handlers,
73
+ addHandler<TableName extends SharedTableName<ServerDB, ClientDB>>(
74
+ handlerOptions: ServerSyncHandlerOptionsForTable<
75
+ ServerDB,
76
+ ClientDB,
77
+ TableName,
78
+ Auth,
79
+ ScopeDefs
80
+ >
81
+ ) {
82
+ if (registeredTables.has(handlerOptions.table)) {
83
+ throw new Error(
84
+ `Server table handler already registered: ${handlerOptions.table}`
85
+ );
86
+ }
87
+
88
+ handlers.push(
89
+ createServerHandler({
90
+ ...handlerOptions,
91
+ codecs: options.codecs,
92
+ codecDialect: options.codecDialect,
93
+ })
94
+ );
95
+ registeredTables.add(handlerOptions.table);
96
+ return sync;
97
+ },
98
+ };
99
+
100
+ return sync;
101
+ }
@@ -1,20 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/handlers/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"}
@@ -1,88 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/handlers/registry.ts"],"names":[],"mappings":"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"}
@@ -1,35 +0,0 @@
1
- /**
2
- * @syncular/server - Proxy Table Registry
3
- *
4
- * Registry for proxy table handlers.
5
- */
6
- import type { ProxyTableHandler } from './types';
7
- /**
8
- * Registry for proxy table handlers.
9
- *
10
- * Maps table names to table handlers for oplog generation.
11
- */
12
- export declare class ProxyTableRegistry {
13
- private handlers;
14
- /**
15
- * Register a proxy table handler.
16
- */
17
- register(handler: ProxyTableHandler): this;
18
- /**
19
- * Get handler by table name.
20
- */
21
- get(tableName: string): ProxyTableHandler | undefined;
22
- /**
23
- * Get handler by table name or throw.
24
- */
25
- getOrThrow(tableName: string): ProxyTableHandler;
26
- /**
27
- * Check if a table has a registered handler.
28
- */
29
- has(tableName: string): boolean;
30
- /**
31
- * Get all registered handlers.
32
- */
33
- getAll(): ProxyTableHandler[];
34
- }
35
- //# sourceMappingURL=registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/proxy/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAwC;IAExD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAGzC;IAED;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAEpD;IAED;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAM/C;IAED;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED;;OAEG;IACH,MAAM,IAAI,iBAAiB,EAAE,CAE5B;CACF"}
@@ -1,49 +0,0 @@
1
- /**
2
- * @syncular/server - Proxy Table Registry
3
- *
4
- * Registry for proxy table handlers.
5
- */
6
- /**
7
- * Registry for proxy table handlers.
8
- *
9
- * Maps table names to table handlers for oplog generation.
10
- */
11
- export class ProxyTableRegistry {
12
- handlers = new Map();
13
- /**
14
- * Register a proxy table handler.
15
- */
16
- register(handler) {
17
- this.handlers.set(handler.table, handler);
18
- return this;
19
- }
20
- /**
21
- * Get handler by table name.
22
- */
23
- get(tableName) {
24
- return this.handlers.get(tableName);
25
- }
26
- /**
27
- * Get handler by table name or throw.
28
- */
29
- getOrThrow(tableName) {
30
- const handler = this.handlers.get(tableName);
31
- if (!handler) {
32
- throw new Error(`No proxy table registered for table: ${tableName}`);
33
- }
34
- return handler;
35
- }
36
- /**
37
- * Check if a table has a registered handler.
38
- */
39
- has(tableName) {
40
- return this.handlers.has(tableName);
41
- }
42
- /**
43
- * Get all registered handlers.
44
- */
45
- getAll() {
46
- return Array.from(this.handlers.values());
47
- }
48
- }
49
- //# sourceMappingURL=registry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/proxy/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IACrB,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAExD;;OAEG;IACH,QAAQ,CAAC,OAA0B,EAAQ;QACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IAAA,CACb;IAED;;OAEG;IACH,GAAG,CAAC,SAAiB,EAAiC;QACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAAA,CACrC;IAED;;OAEG;IACH,UAAU,CAAC,SAAiB,EAAqB;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,SAAS,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,OAAO,CAAC;IAAA,CAChB;IAED;;OAEG;IACH,GAAG,CAAC,SAAiB,EAAW;QAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAAA,CACrC;IAED;;OAEG;IACH,MAAM,GAAwB;QAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAAA,CAC3C;CACF"}
@@ -1,109 +0,0 @@
1
- import type { SyncCoreDb } from '../schema';
2
- import type { ServerTableHandler } from './types';
3
-
4
- export class TableRegistry<DB extends SyncCoreDb = SyncCoreDb> {
5
- private tables = new Map<string, ServerTableHandler<DB>>();
6
-
7
- register(handler: ServerTableHandler<DB>): this {
8
- if (this.tables.has(handler.table)) {
9
- throw new Error(`Table "${handler.table}" is already registered`);
10
- }
11
-
12
- // Validate dependencies exist
13
- for (const dep of handler.dependsOn ?? []) {
14
- if (!this.tables.has(dep)) {
15
- throw new Error(
16
- `Table "${handler.table}" depends on unknown table "${dep}"`
17
- );
18
- }
19
- }
20
-
21
- this.tables.set(handler.table, handler);
22
- return this;
23
- }
24
-
25
- get(table: string): ServerTableHandler<DB> | undefined {
26
- return this.tables.get(table);
27
- }
28
-
29
- getOrThrow(table: string): ServerTableHandler<DB> {
30
- const handler = this.tables.get(table);
31
- if (!handler) throw new Error(`Unknown table: ${table}`);
32
- return handler;
33
- }
34
-
35
- getAll(): ServerTableHandler<DB>[] {
36
- return Array.from(this.tables.values());
37
- }
38
-
39
- /**
40
- * Return tables in topological order (parents before children).
41
- * Throws if a circular dependency is detected.
42
- */
43
- getBootstrapOrder(): ServerTableHandler<DB>[] {
44
- const visited = new Set<string>();
45
- const sorted: ServerTableHandler<DB>[] = [];
46
- const visiting = new Set<string>();
47
-
48
- const visit = (table: string) => {
49
- if (visited.has(table)) return;
50
- if (visiting.has(table)) {
51
- throw new Error(
52
- `Circular dependency detected involving table "${table}"`
53
- );
54
- }
55
-
56
- visiting.add(table);
57
- const handler = this.tables.get(table);
58
- if (handler) {
59
- for (const dep of handler.dependsOn ?? []) {
60
- visit(dep);
61
- }
62
- visited.add(table);
63
- visiting.delete(table);
64
- sorted.push(handler);
65
- }
66
- };
67
-
68
- for (const table of this.tables.keys()) {
69
- visit(table);
70
- }
71
-
72
- return sorted;
73
- }
74
-
75
- /**
76
- * Return bootstrap order for a target table and its dependencies.
77
- * Parents are returned before children.
78
- */
79
- getBootstrapOrderFor(table: string): ServerTableHandler<DB>[] {
80
- const visited = new Set<string>();
81
- const sorted: ServerTableHandler<DB>[] = [];
82
- const visiting = new Set<string>();
83
-
84
- const visit = (name: string) => {
85
- if (visited.has(name)) return;
86
- if (visiting.has(name)) {
87
- throw new Error(
88
- `Circular dependency detected involving table "${name}"`
89
- );
90
- }
91
-
92
- const handler = this.tables.get(name);
93
- if (!handler) {
94
- throw new Error(`Unknown table: ${name}`);
95
- }
96
-
97
- visiting.add(name);
98
- for (const dep of handler.dependsOn ?? []) {
99
- visit(dep);
100
- }
101
- visiting.delete(name);
102
- visited.add(name);
103
- sorted.push(handler);
104
- };
105
-
106
- visit(table);
107
- return sorted;
108
- }
109
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * @syncular/server - Proxy Table Registry
3
- *
4
- * Registry for proxy table handlers.
5
- */
6
-
7
- import type { ProxyTableHandler } from './types';
8
-
9
- /**
10
- * Registry for proxy table handlers.
11
- *
12
- * Maps table names to table handlers for oplog generation.
13
- */
14
- export class ProxyTableRegistry {
15
- private handlers = new Map<string, ProxyTableHandler>();
16
-
17
- /**
18
- * Register a proxy table handler.
19
- */
20
- register(handler: ProxyTableHandler): this {
21
- this.handlers.set(handler.table, handler);
22
- return this;
23
- }
24
-
25
- /**
26
- * Get handler by table name.
27
- */
28
- get(tableName: string): ProxyTableHandler | undefined {
29
- return this.handlers.get(tableName);
30
- }
31
-
32
- /**
33
- * Get handler by table name or throw.
34
- */
35
- getOrThrow(tableName: string): ProxyTableHandler {
36
- const handler = this.handlers.get(tableName);
37
- if (!handler) {
38
- throw new Error(`No proxy table registered for table: ${tableName}`);
39
- }
40
- return handler;
41
- }
42
-
43
- /**
44
- * Check if a table has a registered handler.
45
- */
46
- has(tableName: string): boolean {
47
- return this.handlers.has(tableName);
48
- }
49
-
50
- /**
51
- * Get all registered handlers.
52
- */
53
- getAll(): ProxyTableHandler[] {
54
- return Array.from(this.handlers.values());
55
- }
56
- }