@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.
- package/dist/dialect/base.d.ts +3 -3
- package/dist/dialect/base.d.ts.map +1 -1
- package/dist/dialect/base.js.map +1 -1
- package/dist/dialect/types.d.ts +5 -7
- package/dist/dialect/types.d.ts.map +1 -1
- package/dist/handlers/collection.d.ts +12 -0
- package/dist/handlers/collection.d.ts.map +1 -0
- package/dist/handlers/collection.js +64 -0
- package/dist/handlers/collection.js.map +1 -0
- package/dist/handlers/create-handler.d.ts +10 -10
- package/dist/handlers/create-handler.d.ts.map +1 -1
- package/dist/handlers/create-handler.js +101 -69
- package/dist/handlers/create-handler.js.map +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +1 -1
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/types.d.ts +18 -12
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/notify.js +1 -1
- package/dist/notify.js.map +1 -1
- package/dist/proxy/collection.d.ts +9 -0
- package/dist/proxy/collection.d.ts.map +1 -0
- package/dist/proxy/collection.js +21 -0
- package/dist/proxy/collection.js.map +1 -0
- package/dist/proxy/handler.d.ts +3 -3
- package/dist/proxy/handler.d.ts.map +1 -1
- package/dist/proxy/handler.js +2 -1
- package/dist/proxy/handler.js.map +1 -1
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js +3 -3
- package/dist/proxy/index.js.map +1 -1
- package/dist/proxy/oplog.js +1 -1
- package/dist/proxy/oplog.js.map +1 -1
- package/dist/pull.d.ts +12 -5
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +101 -55
- package/dist/pull.js.map +1 -1
- package/dist/push.d.ts +5 -5
- package/dist/push.d.ts.map +1 -1
- package/dist/push.js +6 -4
- package/dist/push.js.map +1 -1
- package/dist/subscriptions/cache.d.ts +55 -0
- package/dist/subscriptions/cache.d.ts.map +1 -0
- package/dist/subscriptions/cache.js +206 -0
- package/dist/subscriptions/cache.js.map +1 -0
- package/dist/subscriptions/index.d.ts +1 -0
- package/dist/subscriptions/index.d.ts.map +1 -1
- package/dist/subscriptions/index.js +1 -0
- package/dist/subscriptions/index.js.map +1 -1
- package/dist/subscriptions/resolve.d.ts +7 -4
- package/dist/subscriptions/resolve.d.ts.map +1 -1
- package/dist/subscriptions/resolve.js +74 -11
- package/dist/subscriptions/resolve.js.map +1 -1
- package/dist/sync.d.ts +21 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +23 -0
- package/dist/sync.js.map +1 -0
- package/package.json +3 -3
- package/src/dialect/base.ts +5 -3
- package/src/dialect/types.ts +11 -8
- package/src/handlers/collection.ts +121 -0
- package/src/handlers/create-handler.ts +163 -109
- package/src/handlers/index.ts +1 -1
- package/src/handlers/types.ts +29 -12
- package/src/index.ts +1 -0
- package/src/notify.test.ts +25 -21
- package/src/notify.ts +1 -1
- package/src/proxy/collection.ts +39 -0
- package/src/proxy/handler.test.ts +15 -9
- package/src/proxy/handler.ts +4 -4
- package/src/proxy/index.ts +8 -3
- package/src/proxy/oplog.ts +1 -1
- package/src/pull.ts +155 -73
- package/src/push.ts +16 -9
- package/src/snapshot-chunks/db-metadata.test.ts +6 -3
- package/src/subscriptions/cache.ts +318 -0
- package/src/subscriptions/index.ts +1 -0
- package/src/subscriptions/resolve.test.ts +180 -0
- package/src/subscriptions/resolve.ts +94 -18
- package/src/sync.ts +101 -0
- package/dist/handlers/registry.d.ts +0 -20
- package/dist/handlers/registry.d.ts.map +0 -1
- package/dist/handlers/registry.js +0 -88
- package/dist/handlers/registry.js.map +0 -1
- package/dist/proxy/registry.d.ts +0 -35
- package/dist/proxy/registry.d.ts.map +0 -1
- package/dist/proxy/registry.js +0 -49
- package/dist/proxy/registry.js.map +0 -1
- package/src/handlers/registry.ts +0 -109
- 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
|
|
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
|
-
|
|
143
|
+
auth: Auth;
|
|
138
144
|
subscriptions: SyncSubscriptionRequest[];
|
|
139
|
-
handlers:
|
|
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
|
|
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
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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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"}
|
package/dist/proxy/registry.d.ts
DELETED
|
@@ -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"}
|
package/dist/proxy/registry.js
DELETED
|
@@ -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"}
|
package/src/handlers/registry.ts
DELETED
|
@@ -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
|
-
}
|
package/src/proxy/registry.ts
DELETED
|
@@ -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
|
-
}
|