@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
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { sql } from 'kysely';
|
|
2
|
+
const DEFAULT_SCOPE_CACHE_PARTITION_ID = 'default';
|
|
3
|
+
const DEFAULT_MEMORY_SCOPE_CACHE_TTL_MS = 30_000;
|
|
4
|
+
const DEFAULT_MEMORY_SCOPE_CACHE_MAX_ENTRIES = 5_000;
|
|
5
|
+
const DEFAULT_DATABASE_SCOPE_CACHE_TTL_MS = 60_000;
|
|
6
|
+
const DEFAULT_DATABASE_SCOPE_CACHE_TABLE = 'sync_scope_cache';
|
|
7
|
+
export function createDefaultScopeCacheKey(args) {
|
|
8
|
+
const partitionId = args.auth.partitionId ?? DEFAULT_SCOPE_CACHE_PARTITION_ID;
|
|
9
|
+
return `${partitionId}\u0000${args.auth.actorId}\u0000${args.table}`;
|
|
10
|
+
}
|
|
11
|
+
function cloneScopeValues(scopes) {
|
|
12
|
+
const cloned = {};
|
|
13
|
+
for (const [key, value] of Object.entries(scopes)) {
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
cloned[key] = value;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
cloned[key] = [...value];
|
|
19
|
+
}
|
|
20
|
+
return cloned;
|
|
21
|
+
}
|
|
22
|
+
function parseScopeValues(value) {
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = JSON.parse(value);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const out = {};
|
|
34
|
+
for (const [scopeKey, scopeValue] of Object.entries(parsed)) {
|
|
35
|
+
if (typeof scopeValue === 'string') {
|
|
36
|
+
out[scopeKey] = scopeValue;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(scopeValue) &&
|
|
40
|
+
scopeValue.every((item) => typeof item === 'string')) {
|
|
41
|
+
out[scopeKey] = [...scopeValue];
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
export function createMemoryScopeCache(options) {
|
|
49
|
+
const ttlMs = options?.ttlMs ?? DEFAULT_MEMORY_SCOPE_CACHE_TTL_MS;
|
|
50
|
+
const maxEntries = options?.maxEntries ?? DEFAULT_MEMORY_SCOPE_CACHE_MAX_ENTRIES;
|
|
51
|
+
const now = options?.now ?? Date.now;
|
|
52
|
+
const buckets = new WeakMap();
|
|
53
|
+
function getBucket(db) {
|
|
54
|
+
const existing = buckets.get(db);
|
|
55
|
+
if (existing) {
|
|
56
|
+
return existing;
|
|
57
|
+
}
|
|
58
|
+
const created = new Map();
|
|
59
|
+
buckets.set(db, created);
|
|
60
|
+
return created;
|
|
61
|
+
}
|
|
62
|
+
function evictOldest(bucket) {
|
|
63
|
+
while (bucket.size > maxEntries) {
|
|
64
|
+
const oldestKey = bucket.keys().next().value;
|
|
65
|
+
if (!oldestKey) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
bucket.delete(oldestKey);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
name: 'memory',
|
|
73
|
+
async get(args) {
|
|
74
|
+
const bucket = getBucket(args.db);
|
|
75
|
+
const entry = bucket.get(args.cacheKey);
|
|
76
|
+
if (!entry) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const nowMs = now();
|
|
80
|
+
if (entry.expiresAt <= nowMs) {
|
|
81
|
+
bucket.delete(args.cacheKey);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return cloneScopeValues(entry.scopes);
|
|
85
|
+
},
|
|
86
|
+
async set(args) {
|
|
87
|
+
const bucket = getBucket(args.db);
|
|
88
|
+
if (ttlMs <= 0) {
|
|
89
|
+
bucket.delete(args.cacheKey);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (bucket.has(args.cacheKey)) {
|
|
93
|
+
bucket.delete(args.cacheKey);
|
|
94
|
+
}
|
|
95
|
+
bucket.set(args.cacheKey, {
|
|
96
|
+
scopes: cloneScopeValues(args.scopes),
|
|
97
|
+
expiresAt: now() + ttlMs,
|
|
98
|
+
});
|
|
99
|
+
evictOldest(bucket);
|
|
100
|
+
},
|
|
101
|
+
async delete(args) {
|
|
102
|
+
const bucket = getBucket(args.db);
|
|
103
|
+
bucket.delete(args.cacheKey);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function createDatabaseScopeCache(options) {
|
|
108
|
+
const tableName = options?.tableName ?? DEFAULT_DATABASE_SCOPE_CACHE_TABLE;
|
|
109
|
+
const ttlMs = options?.ttlMs ?? DEFAULT_DATABASE_SCOPE_CACHE_TTL_MS;
|
|
110
|
+
const autoCreateTable = options?.autoCreateTable ?? true;
|
|
111
|
+
const now = options?.now ?? (() => new Date());
|
|
112
|
+
const schemaReady = new WeakMap();
|
|
113
|
+
async function ensureTable(db) {
|
|
114
|
+
if (!autoCreateTable) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const existing = schemaReady.get(db);
|
|
118
|
+
if (existing) {
|
|
119
|
+
await existing;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const pending = sql `
|
|
123
|
+
CREATE TABLE IF NOT EXISTS ${sql.table(tableName)} (
|
|
124
|
+
cache_key TEXT PRIMARY KEY,
|
|
125
|
+
scope_values TEXT NOT NULL,
|
|
126
|
+
expires_at TEXT NOT NULL,
|
|
127
|
+
created_at TEXT NOT NULL
|
|
128
|
+
)
|
|
129
|
+
`
|
|
130
|
+
.execute(db)
|
|
131
|
+
.then(() => undefined);
|
|
132
|
+
schemaReady.set(db, pending);
|
|
133
|
+
try {
|
|
134
|
+
await pending;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
schemaReady.delete(db);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function removeCacheRow(args) {
|
|
142
|
+
await sql `
|
|
143
|
+
DELETE FROM ${sql.table(tableName)}
|
|
144
|
+
WHERE cache_key = ${args.cacheKey}
|
|
145
|
+
`.execute(args.db);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
name: 'database',
|
|
149
|
+
async get(args) {
|
|
150
|
+
await ensureTable(args.db);
|
|
151
|
+
const rows = await sql `
|
|
152
|
+
SELECT scope_values, expires_at
|
|
153
|
+
FROM ${sql.table(tableName)}
|
|
154
|
+
WHERE cache_key = ${args.cacheKey}
|
|
155
|
+
LIMIT 1
|
|
156
|
+
`.execute(args.db);
|
|
157
|
+
const row = rows.rows[0];
|
|
158
|
+
if (!row) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const nowIso = now().toISOString();
|
|
162
|
+
if (row.expires_at <= nowIso) {
|
|
163
|
+
await removeCacheRow({ db: args.db, cacheKey: args.cacheKey });
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const parsed = parseScopeValues(row.scope_values);
|
|
167
|
+
if (!parsed) {
|
|
168
|
+
await removeCacheRow({ db: args.db, cacheKey: args.cacheKey });
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return parsed;
|
|
172
|
+
},
|
|
173
|
+
async set(args) {
|
|
174
|
+
await ensureTable(args.db);
|
|
175
|
+
if (ttlMs <= 0) {
|
|
176
|
+
await removeCacheRow({ db: args.db, cacheKey: args.cacheKey });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const createdAt = now();
|
|
180
|
+
const expiresAt = new Date(createdAt.getTime() + ttlMs);
|
|
181
|
+
await sql `
|
|
182
|
+
INSERT INTO ${sql.table(tableName)} (
|
|
183
|
+
cache_key,
|
|
184
|
+
scope_values,
|
|
185
|
+
expires_at,
|
|
186
|
+
created_at
|
|
187
|
+
)
|
|
188
|
+
VALUES (
|
|
189
|
+
${args.cacheKey},
|
|
190
|
+
${JSON.stringify(cloneScopeValues(args.scopes))},
|
|
191
|
+
${expiresAt.toISOString()},
|
|
192
|
+
${createdAt.toISOString()}
|
|
193
|
+
)
|
|
194
|
+
ON CONFLICT (cache_key) DO UPDATE SET
|
|
195
|
+
scope_values = EXCLUDED.scope_values,
|
|
196
|
+
expires_at = EXCLUDED.expires_at,
|
|
197
|
+
created_at = EXCLUDED.created_at
|
|
198
|
+
`.execute(args.db);
|
|
199
|
+
},
|
|
200
|
+
async delete(args) {
|
|
201
|
+
await ensureTable(args.db);
|
|
202
|
+
await removeCacheRow({ db: args.db, cacheKey: args.cacheKey });
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/subscriptions/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/subscriptions/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/subscriptions/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/subscriptions/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/subscriptions/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type ScopeValues, type SyncSubscriptionRequest } from '@syncular/core';
|
|
2
2
|
import type { Kysely } from 'kysely';
|
|
3
|
-
import type
|
|
3
|
+
import { type ServerHandlerCollection } from '../handlers/collection';
|
|
4
|
+
import type { SyncServerAuth } from '../handlers/types';
|
|
4
5
|
import type { SyncCoreDb } from '../schema';
|
|
6
|
+
import { type ScopeCacheBackend } from './cache';
|
|
5
7
|
export declare class InvalidSubscriptionScopeError extends Error {
|
|
6
8
|
constructor(message: string);
|
|
7
9
|
}
|
|
@@ -26,10 +28,11 @@ export interface ResolvedSubscription {
|
|
|
26
28
|
* 3. Intersect requested scopes with allowed scopes
|
|
27
29
|
* 4. Mark as revoked if no effective scopes
|
|
28
30
|
*/
|
|
29
|
-
export declare function resolveEffectiveScopesForSubscriptions<DB extends SyncCoreDb>(args: {
|
|
31
|
+
export declare function resolveEffectiveScopesForSubscriptions<DB extends SyncCoreDb, Auth extends SyncServerAuth>(args: {
|
|
30
32
|
db: Kysely<DB>;
|
|
31
|
-
|
|
33
|
+
auth: Auth;
|
|
32
34
|
subscriptions: SyncSubscriptionRequest[];
|
|
33
|
-
handlers:
|
|
35
|
+
handlers: ServerHandlerCollection<DB, Auth>;
|
|
36
|
+
scopeCache?: ScopeCacheBackend;
|
|
34
37
|
}): Promise<ResolvedSubscription[]>;
|
|
35
38
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/subscriptions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/subscriptions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAA8B,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE7E,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAC;IAC3D,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B;AAgGD;;;;;;;;GAQG;AACH,wBAAsB,sCAAsC,CAC1D,EAAE,SAAS,UAAU,EACrB,IAAI,SAAS,cAAc,EAC3B,IAAI,EAAE;IACN,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,EAAE,uBAAuB,EAAE,CAAC;IACzC,QAAQ,EAAE,uBAAuB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAyKlC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { extractScopeVars, } from '@syncular/core';
|
|
2
|
+
import { getServerHandler, } from '../handlers/collection.js';
|
|
3
|
+
import { createDefaultScopeCacheKey } from './cache.js';
|
|
2
4
|
export class InvalidSubscriptionScopeError extends Error {
|
|
3
5
|
constructor(message) {
|
|
4
6
|
super(message);
|
|
@@ -90,6 +92,7 @@ function validateScopeKeys(args) {
|
|
|
90
92
|
export async function resolveEffectiveScopesForSubscriptions(args) {
|
|
91
93
|
const out = [];
|
|
92
94
|
const seenIds = new Set();
|
|
95
|
+
const requestScopeCache = new Map();
|
|
93
96
|
for (const sub of args.subscriptions) {
|
|
94
97
|
if (!sub.id || typeof sub.id !== 'string') {
|
|
95
98
|
throw new InvalidSubscriptionScopeError('Subscription id is required');
|
|
@@ -101,7 +104,7 @@ export async function resolveEffectiveScopesForSubscriptions(args) {
|
|
|
101
104
|
if (!sub.table || typeof sub.table !== 'string') {
|
|
102
105
|
throw new InvalidSubscriptionScopeError(`Subscription ${sub.id} requires a table name`);
|
|
103
106
|
}
|
|
104
|
-
const handler = args.handlers
|
|
107
|
+
const handler = getServerHandler(args.handlers, sub.table);
|
|
105
108
|
if (!handler) {
|
|
106
109
|
throw new InvalidSubscriptionScopeError(`Unknown table: ${sub.table} for subscription ${sub.id}`);
|
|
107
110
|
}
|
|
@@ -114,18 +117,78 @@ export async function resolveEffectiveScopesForSubscriptions(args) {
|
|
|
114
117
|
subscriptionId: sub.id,
|
|
115
118
|
table: sub.table,
|
|
116
119
|
});
|
|
117
|
-
//
|
|
120
|
+
// Resolve allowed scopes with request-local memoization first, then
|
|
121
|
+
// optional shared cache backend, then table handler.
|
|
122
|
+
const scopeCacheKey = createDefaultScopeCacheKey({
|
|
123
|
+
auth: args.auth,
|
|
124
|
+
table: sub.table,
|
|
125
|
+
});
|
|
118
126
|
let allowed;
|
|
119
|
-
|
|
120
|
-
allowed =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
if (requestScopeCache.has(scopeCacheKey)) {
|
|
128
|
+
allowed = requestScopeCache.get(scopeCacheKey) ?? null;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
allowed = null;
|
|
132
|
+
let sharedCacheHit = false;
|
|
133
|
+
if (args.scopeCache) {
|
|
134
|
+
try {
|
|
135
|
+
const cachedAllowed = await args.scopeCache.get({
|
|
136
|
+
db: args.db,
|
|
137
|
+
auth: args.auth,
|
|
138
|
+
table: sub.table,
|
|
139
|
+
cacheKey: scopeCacheKey,
|
|
140
|
+
});
|
|
141
|
+
if (cachedAllowed !== null) {
|
|
142
|
+
allowed = cachedAllowed;
|
|
143
|
+
sharedCacheHit = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (cacheErr) {
|
|
147
|
+
console.error(`[scopeCache.get] Failed for table ${sub.table}, subscription ${sub.id}:`, cacheErr);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!sharedCacheHit) {
|
|
151
|
+
try {
|
|
152
|
+
allowed = await handler.resolveScopes({
|
|
153
|
+
db: args.db,
|
|
154
|
+
actorId: args.auth.actorId,
|
|
155
|
+
auth: args.auth,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (resolveErr) {
|
|
159
|
+
// Scope resolution failed - mark subscription as revoked
|
|
160
|
+
// rather than failing the entire pull
|
|
161
|
+
console.error(`[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`, resolveErr);
|
|
162
|
+
requestScopeCache.set(scopeCacheKey, null);
|
|
163
|
+
out.push({
|
|
164
|
+
id: sub.id,
|
|
165
|
+
table: sub.table,
|
|
166
|
+
scopes: {},
|
|
167
|
+
params: sub.params,
|
|
168
|
+
cursor: sub.cursor,
|
|
169
|
+
bootstrapState: sub.bootstrapState ?? null,
|
|
170
|
+
status: 'revoked',
|
|
171
|
+
});
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (args.scopeCache && allowed !== null) {
|
|
175
|
+
try {
|
|
176
|
+
await args.scopeCache.set({
|
|
177
|
+
db: args.db,
|
|
178
|
+
auth: args.auth,
|
|
179
|
+
table: sub.table,
|
|
180
|
+
cacheKey: scopeCacheKey,
|
|
181
|
+
scopes: allowed,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (cacheErr) {
|
|
185
|
+
console.error(`[scopeCache.set] Failed for table ${sub.table}, subscription ${sub.id}:`, cacheErr);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
requestScopeCache.set(scopeCacheKey, allowed);
|
|
124
190
|
}
|
|
125
|
-
|
|
126
|
-
// Scope resolution failed - mark subscription as revoked
|
|
127
|
-
// rather than failing the entire pull
|
|
128
|
-
console.error(`[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`, resolveErr);
|
|
191
|
+
if (!allowed) {
|
|
129
192
|
out.push({
|
|
130
193
|
id: sub.id,
|
|
131
194
|
table: sub.table,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/subscriptions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAGjB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/subscriptions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAGjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,GAEjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,0BAA0B,EAA0B,MAAM,SAAS,CAAC;AAE7E,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IACtD,YAAY,OAAe,EAAE;QAC3B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAAA,CAC7C;CACF;AAeD;;;;;;;;GAQG;AACH,SAAS,eAAe,CACtB,SAAsB,EACtB,OAAoB,EACP;IACb,MAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,8BAA8B;YAC9B,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;YAC/C,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAEpB,yEAAyE;QACzE,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;YACxB,SAAS;QACX,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;QAEzC,YAAY;QACZ,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/D,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,8DAA8D;YAC9D,MAAM,CAAC,GAAG,CAAC;gBACT,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;oBACpD,CAAC,CAAC,YAAY,CAAC,CAAC,CAAE;oBAClB,CAAC,CAAC,YAAY,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACf;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,MAAmB,EAAW;IACjD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACb;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,aAAgC,EAAe;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACb;AAED,SAAS,iBAAiB,CAAC,IAM1B,EAAQ;IACP,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QACD,MAAM,YAAY,GAChB,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC;YAC1B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YACnD,CAAC,CAAC,QAAQ,CAAC;QACf,MAAM,IAAI,6BAA6B,CACrC,sBAAsB,QAAQ,QAAQ,IAAI,CAAC,MAAM,sBAAsB,IAAI,CAAC,cAAc,eAAe,IAAI,CAAC,KAAK,qBAAqB,YAAY,EAAE,CACvJ,CAAC;IACJ,CAAC;AAAA,CACF;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,sCAAsC,CAG1D,IAMD,EAAmC;IAClC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEhE,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,6BAA6B,CAAC,6BAA6B,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,6BAA6B,CACrC,8BAA8B,GAAG,CAAC,EAAE,EAAE,CACvC,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEpB,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChD,MAAM,IAAI,6BAA6B,CACrC,gBAAgB,GAAG,CAAC,EAAE,wBAAwB,CAC/C,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,6BAA6B,CACrC,kBAAkB,GAAG,CAAC,KAAK,qBAAqB,GAAG,CAAC,EAAE,EAAE,CACzD,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;QACnC,iBAAiB,CAAC;YAChB,WAAW,EAAE,SAAS;YACtB,cAAc;YACd,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,GAAG,CAAC,EAAE;YACtB,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC,CAAC;QAEH,oEAAoE;QACpE,qDAAqD;QACrD,MAAM,aAAa,GAAG,0BAA0B,CAAC;YAC/C,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC,CAAC;QACH,IAAI,OAA2B,CAAC;QAChC,IAAI,iBAAiB,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC;QACzD,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,cAAc,GAAG,KAAK,CAAC;YAE3B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;wBAC9C,EAAE,EAAE,IAAI,CAAC,EAAE;wBACX,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,QAAQ,EAAE,aAAa;qBACxB,CAAC,CAAC;oBACH,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;wBAC3B,OAAO,GAAG,aAAa,CAAC;wBACxB,cAAc,GAAG,IAAI,CAAC;oBACxB,CAAC;gBACH,CAAC;gBAAC,OAAO,QAAQ,EAAE,CAAC;oBAClB,OAAO,CAAC,KAAK,CACX,qCAAqC,GAAG,CAAC,KAAK,kBAAkB,GAAG,CAAC,EAAE,GAAG,EACzE,QAAQ,CACT,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC;wBACpC,EAAE,EAAE,IAAI,CAAC,EAAE;wBACX,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO;wBAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;qBAChB,CAAC,CAAC;gBACL,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,yDAAyD;oBACzD,sCAAsC;oBACtC,OAAO,CAAC,KAAK,CACX,oCAAoC,GAAG,CAAC,KAAK,kBAAkB,GAAG,CAAC,EAAE,GAAG,EACxE,UAAU,CACX,CAAC;oBACF,iBAAiB,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;oBAC3C,GAAG,CAAC,IAAI,CAAC;wBACP,EAAE,EAAE,GAAG,CAAC,EAAE;wBACV,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,MAAM,EAAE,EAAE;wBACV,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;wBAC1C,MAAM,EAAE,SAAS;qBAClB,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBAED,IAAI,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACxC,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;4BACxB,EAAE,EAAE,IAAI,CAAC,EAAE;4BACX,IAAI,EAAE,IAAI,CAAC,IAAI;4BACf,KAAK,EAAE,GAAG,CAAC,KAAK;4BAChB,QAAQ,EAAE,aAAa;4BACvB,MAAM,EAAE,OAAO;yBAChB,CAAC,CAAC;oBACL,CAAC;oBAAC,OAAO,QAAQ,EAAE,CAAC;wBAClB,OAAO,CAAC,KAAK,CACX,qCAAqC,GAAG,CAAC,KAAK,kBAAkB,GAAG,CAAC,EAAE,GAAG,EACzE,QAAQ,CACT,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,iBAAiB,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC;gBACP,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;gBAC1C,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,iBAAiB,CAAC;YAChB,WAAW,EAAE,OAAO;YACpB,cAAc;YACd,MAAM,EAAE,wBAAwB;YAChC,cAAc,EAAE,GAAG,CAAC,EAAE;YACtB,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAEtD,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,GAAG,CAAC,IAAI,CAAC;gBACP,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;gBAC1C,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;YAC1C,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC;AAAA,CACZ"}
|
package/dist/sync.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ColumnCodecDialect, ColumnCodecSource, ScopeDefinition } from '@syncular/core';
|
|
2
|
+
import { type CreateServerHandlerOptions } from './handlers';
|
|
3
|
+
import type { ServerTableHandler, SyncServerAuth } from './handlers/types';
|
|
4
|
+
import type { SyncCoreDb } from './schema';
|
|
5
|
+
type SharedTableName<ServerDB, ClientDB> = keyof ServerDB & keyof ClientDB & string;
|
|
6
|
+
export type ServerSyncHandlerOptionsForTable<ServerDB extends SyncCoreDb, ClientDB, TableName extends SharedTableName<ServerDB, ClientDB>, Auth extends SyncServerAuth, ScopeDefs extends readonly ScopeDefinition[]> = Omit<CreateServerHandlerOptions<ServerDB, ClientDB, TableName, Auth, ScopeDefs>, 'codecs' | 'codecDialect'>;
|
|
7
|
+
export interface ServerSyncConfig<ServerDB extends SyncCoreDb = SyncCoreDb, Auth extends SyncServerAuth = SyncServerAuth> {
|
|
8
|
+
authenticate: (request: Request) => Promise<Auth | null> | Auth | null;
|
|
9
|
+
handlers: ServerTableHandler<ServerDB, Auth>[];
|
|
10
|
+
}
|
|
11
|
+
export interface DefineServerSyncOptions<Auth extends SyncServerAuth> {
|
|
12
|
+
authenticate: (request: Request) => Promise<Auth | null> | Auth | null;
|
|
13
|
+
codecs?: ColumnCodecSource;
|
|
14
|
+
codecDialect?: ColumnCodecDialect;
|
|
15
|
+
}
|
|
16
|
+
export interface ServerSyncBuilder<ServerDB extends SyncCoreDb, ClientDB, ScopeDefs extends readonly ScopeDefinition[], Auth extends SyncServerAuth> extends ServerSyncConfig<ServerDB, Auth> {
|
|
17
|
+
addHandler<TableName extends SharedTableName<ServerDB, ClientDB>>(options: ServerSyncHandlerOptionsForTable<ServerDB, ClientDB, TableName, Auth, ScopeDefs>): this;
|
|
18
|
+
}
|
|
19
|
+
export declare function defineServerSync<ServerDB extends SyncCoreDb, ClientDB, ScopeDefs extends readonly ScopeDefinition[], Auth extends SyncServerAuth>(options: DefineServerSyncOptions<Auth>): ServerSyncBuilder<ServerDB, ClientDB, ScopeDefs, Auth>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,0BAA0B,EAEhC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,KAAK,eAAe,CAAC,QAAQ,EAAE,QAAQ,IAAI,MAAM,QAAQ,GACvD,MAAM,QAAQ,GACd,MAAM,CAAC;AAET,MAAM,MAAM,gCAAgC,CAC1C,QAAQ,SAAS,UAAU,EAC3B,QAAQ,EACR,SAAS,SAAS,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACrD,IAAI,SAAS,cAAc,EAC3B,SAAS,SAAS,SAAS,eAAe,EAAE,IAC1C,IAAI,CACN,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,EAC1E,QAAQ,GAAG,cAAc,CAC1B,CAAC;AAEF,MAAM,WAAW,gBAAgB,CAC/B,QAAQ,SAAS,UAAU,GAAG,UAAU,EACxC,IAAI,SAAS,cAAc,GAAG,cAAc;IAE5C,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IACvE,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,cAAc;IAClE,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IACvE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB,CAChC,QAAQ,SAAS,UAAU,EAC3B,QAAQ,EACR,SAAS,SAAS,SAAS,eAAe,EAAE,EAC5C,IAAI,SAAS,cAAc,CAC3B,SAAQ,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxC,UAAU,CAAC,SAAS,SAAS,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAC9D,OAAO,EAAE,gCAAgC,CACvC,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,SAAS,CACV,GACA,IAAI,CAAC;CACT;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,SAAS,UAAU,EAC3B,QAAQ,EACR,SAAS,SAAS,SAAS,eAAe,EAAE,EAC5C,IAAI,SAAS,cAAc,EAE3B,OAAO,EAAE,uBAAuB,CAAC,IAAI,CAAC,GACrC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAmCxD"}
|
package/dist/sync.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createServerHandler, } from './handlers/index.js';
|
|
2
|
+
export function defineServerSync(options) {
|
|
3
|
+
const handlers = [];
|
|
4
|
+
const registeredTables = new Set();
|
|
5
|
+
const sync = {
|
|
6
|
+
authenticate: options.authenticate,
|
|
7
|
+
handlers,
|
|
8
|
+
addHandler(handlerOptions) {
|
|
9
|
+
if (registeredTables.has(handlerOptions.table)) {
|
|
10
|
+
throw new Error(`Server table handler already registered: ${handlerOptions.table}`);
|
|
11
|
+
}
|
|
12
|
+
handlers.push(createServerHandler({
|
|
13
|
+
...handlerOptions,
|
|
14
|
+
codecs: options.codecs,
|
|
15
|
+
codecDialect: options.codecDialect,
|
|
16
|
+
}));
|
|
17
|
+
registeredTables.add(handlerOptions.table);
|
|
18
|
+
return sync;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
return sync;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=sync.js.map
|
package/dist/sync.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAkDpB,MAAM,UAAU,gBAAgB,CAM9B,OAAsC,EACkB;IACxD,MAAM,QAAQ,GAAyC,EAAE,CAAC;IAC1D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE3C,MAAM,IAAI,GAA2D;QACnE,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,QAAQ;QACR,UAAU,CACR,cAMC,EACD;YACA,IAAI,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CACb,4CAA4C,cAAc,CAAC,KAAK,EAAE,CACnE,CAAC;YACJ,CAAC;YAED,QAAQ,CAAC,IAAI,CACX,mBAAmB,CAAC;gBAClB,GAAG,cAAc;gBACjB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,YAAY,EAAE,OAAO,CAAC,YAAY;aACnC,CAAC,CACH,CAAC;YACF,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,IAAI,CAAC;QAAA,CACb;KACF,CAAC;IAEF,OAAO,IAAI,CAAC;AAAA,CACb"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6-101",
|
|
4
4
|
"description": "Server-side sync engine with push/pull, pruning, and snapshot support",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
7
7
|
"homepage": "https://syncular.dev",
|
|
8
8
|
"repository": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"release": "bunx syncular-publish"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@syncular/core": "0.0.
|
|
65
|
+
"@syncular/core": "0.0.6-101"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
68
|
"kysely": "^0.28.0",
|
package/src/dialect/base.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* database-specific sync dialect implementations.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ScopeValues, StoredScopes } from '@syncular/core';
|
|
8
|
+
import type { ScopeValues, SqlFamily, StoredScopes } from '@syncular/core';
|
|
9
9
|
import type { Kysely, RawBuilder, Transaction } from 'kysely';
|
|
10
10
|
import { sql } from 'kysely';
|
|
11
11
|
import type { SyncChangeRow, SyncCommitRow, SyncCoreDb } from '../schema';
|
|
@@ -28,8 +28,10 @@ import type {
|
|
|
28
28
|
* Genuinely different methods (DDL, transaction control, scope filtering,
|
|
29
29
|
* compaction) remain abstract for each dialect to implement.
|
|
30
30
|
*/
|
|
31
|
-
export abstract class BaseServerSyncDialect
|
|
32
|
-
|
|
31
|
+
export abstract class BaseServerSyncDialect<F extends SqlFamily = SqlFamily>
|
|
32
|
+
implements ServerSyncDialect<F>
|
|
33
|
+
{
|
|
34
|
+
abstract readonly family: F;
|
|
33
35
|
abstract readonly supportsForUpdate: boolean;
|
|
34
36
|
abstract readonly supportsSavepoints: boolean;
|
|
35
37
|
|
package/src/dialect/types.ts
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* Supports the new JSONB scopes model.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
ScopeValues,
|
|
10
|
+
SqlFamily,
|
|
11
|
+
StoredScopes,
|
|
12
|
+
SyncOp,
|
|
13
|
+
} from '@syncular/core';
|
|
9
14
|
import type { Kysely, Transaction } from 'kysely';
|
|
10
15
|
import type { SyncChangeRow, SyncCommitRow, SyncCoreDb } from '../schema';
|
|
11
16
|
|
|
@@ -17,11 +22,6 @@ export type DbExecutor<DB extends SyncCoreDb = SyncCoreDb> =
|
|
|
17
22
|
| Kysely<DB>
|
|
18
23
|
| Transaction<DB>;
|
|
19
24
|
|
|
20
|
-
/**
|
|
21
|
-
* Supported dialect names.
|
|
22
|
-
*/
|
|
23
|
-
export type ServerSyncDialectName = string;
|
|
24
|
-
|
|
25
25
|
export interface IncrementalPullRowsArgs {
|
|
26
26
|
table: string;
|
|
27
27
|
scopes: ScopeValues;
|
|
@@ -44,8 +44,11 @@ export interface IncrementalPullRow {
|
|
|
44
44
|
scopes: StoredScopes;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export
|
|
48
|
-
|
|
47
|
+
export type ServerSqliteDialect = ServerSyncDialect<'sqlite'>;
|
|
48
|
+
export type ServerPostgresDialect = ServerSyncDialect<'postgres'>;
|
|
49
|
+
|
|
50
|
+
export interface ServerSyncDialect<F extends SqlFamily = SqlFamily> {
|
|
51
|
+
readonly family: F;
|
|
49
52
|
|
|
50
53
|
/** Create sync tables + indexes (idempotent) */
|
|
51
54
|
ensureSyncSchema<DB extends SyncCoreDb>(db: Kysely<DB>): Promise<void>;
|