@syncular/client 0.0.6-55 → 0.0.6-66

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 (49) hide show
  1. package/dist/client.d.ts +2 -2
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/create-client.d.ts +2 -3
  4. package/dist/create-client.d.ts.map +1 -1
  5. package/dist/create-client.js +12 -8
  6. package/dist/create-client.js.map +1 -1
  7. package/dist/engine/SyncEngine.d.ts.map +1 -1
  8. package/dist/engine/SyncEngine.js +35 -29
  9. package/dist/engine/SyncEngine.js.map +1 -1
  10. package/dist/engine/types.d.ts +3 -3
  11. package/dist/engine/types.d.ts.map +1 -1
  12. package/dist/handlers/collection.d.ts +6 -0
  13. package/dist/handlers/collection.d.ts.map +1 -0
  14. package/dist/handlers/collection.js +21 -0
  15. package/dist/handlers/collection.js.map +1 -0
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/pull-engine.d.ts +3 -3
  21. package/dist/pull-engine.d.ts.map +1 -1
  22. package/dist/pull-engine.js +11 -4
  23. package/dist/pull-engine.js.map +1 -1
  24. package/dist/sync-loop.d.ts +2 -2
  25. package/dist/sync-loop.d.ts.map +1 -1
  26. package/dist/sync-loop.js.map +1 -1
  27. package/dist/sync.d.ts +32 -0
  28. package/dist/sync.d.ts.map +1 -0
  29. package/dist/sync.js +55 -0
  30. package/dist/sync.js.map +1 -0
  31. package/package.json +3 -3
  32. package/src/client.test.ts +4 -4
  33. package/src/client.ts +2 -2
  34. package/src/create-client.test.ts +79 -0
  35. package/src/create-client.ts +15 -10
  36. package/src/engine/SyncEngine.test.ts +77 -29
  37. package/src/engine/SyncEngine.ts +39 -33
  38. package/src/engine/types.ts +3 -3
  39. package/src/handlers/collection.ts +36 -0
  40. package/src/index.ts +2 -1
  41. package/src/pull-engine.test.ts +4 -4
  42. package/src/pull-engine.ts +16 -7
  43. package/src/sync-loop.ts +4 -4
  44. package/src/sync.ts +170 -0
  45. package/dist/handlers/registry.d.ts +0 -15
  46. package/dist/handlers/registry.d.ts.map +0 -1
  47. package/dist/handlers/registry.js +0 -29
  48. package/dist/handlers/registry.js.map +0 -1
  49. package/src/handlers/registry.ts +0 -36
package/src/sync.ts ADDED
@@ -0,0 +1,170 @@
1
+ import type {
2
+ ColumnCodecDialect,
3
+ ColumnCodecSource,
4
+ ScopeDefinition,
5
+ ScopeValue,
6
+ ScopeValuesFromPatterns,
7
+ SyncSubscriptionRequest,
8
+ } from '@syncular/core';
9
+ import {
10
+ type CreateClientHandlerOptions,
11
+ createClientHandler,
12
+ } from './handlers/create-handler';
13
+ import type { ClientTableHandler } from './handlers/types';
14
+ import type { SyncClientDb } from './schema';
15
+
16
+ type ClientSyncSubscription<ScopeDefs extends readonly ScopeDefinition[]> =
17
+ Omit<SyncSubscriptionRequest, 'cursor' | 'table' | 'scopes'> & {
18
+ table: string;
19
+ scopes?: ScopeValuesFromPatterns<ScopeDefs>;
20
+ };
21
+
22
+ type SharedTableName<DB extends SyncClientDb> = keyof DB & string;
23
+
24
+ export type ClientSyncHandlerOptionsForTable<
25
+ DB extends SyncClientDb,
26
+ TableName extends SharedTableName<DB>,
27
+ ScopeDefs extends readonly ScopeDefinition[],
28
+ Identity,
29
+ > = Omit<
30
+ CreateClientHandlerOptions<DB, TableName, ScopeDefs>,
31
+ 'columnCodecs' | 'codecDialect' | 'subscribe'
32
+ > & {
33
+ columnCodecs?: ColumnCodecSource;
34
+ codecDialect?: ColumnCodecDialect;
35
+ subscribe?:
36
+ | ClientSyncSubscription<ScopeDefs>
37
+ | ClientSyncSubscription<ScopeDefs>[]
38
+ | null
39
+ | ((args: {
40
+ identity: Identity;
41
+ }) =>
42
+ | ClientSyncSubscription<ScopeDefs>
43
+ | ClientSyncSubscription<ScopeDefs>[]
44
+ | null);
45
+ };
46
+
47
+ export interface ClientSyncConfig<
48
+ DB extends SyncClientDb = SyncClientDb,
49
+ Identity = { actorId: string },
50
+ > {
51
+ handlers: ClientTableHandler<DB>[];
52
+ subscriptions(
53
+ identity: Identity
54
+ ): Array<Omit<SyncSubscriptionRequest, 'cursor'>>;
55
+ }
56
+
57
+ export interface DefineClientSyncOptions {
58
+ codecs?: ColumnCodecSource;
59
+ codecDialect?: ColumnCodecDialect;
60
+ }
61
+
62
+ export interface ClientSyncBuilder<
63
+ DB extends SyncClientDb,
64
+ ScopeDefs extends readonly ScopeDefinition[],
65
+ Identity,
66
+ > extends ClientSyncConfig<DB, Identity> {
67
+ addHandler<TableName extends SharedTableName<DB>>(
68
+ options: ClientSyncHandlerOptionsForTable<
69
+ DB,
70
+ TableName,
71
+ ScopeDefs,
72
+ Identity
73
+ >
74
+ ): this;
75
+ }
76
+
77
+ export function defineClientSync<
78
+ DB extends SyncClientDb,
79
+ ScopeDefs extends readonly ScopeDefinition[],
80
+ Identity,
81
+ >(
82
+ options: DefineClientSyncOptions
83
+ ): ClientSyncBuilder<DB, ScopeDefs, Identity> {
84
+ const handlers: ClientTableHandler<DB>[] = [];
85
+ const registeredTables = new Set<string>();
86
+ const subscriptionsByTable = new Map<
87
+ string,
88
+ ClientSyncHandlerOptionsForTable<
89
+ DB,
90
+ SharedTableName<DB>,
91
+ ScopeDefs,
92
+ Identity
93
+ >['subscribe']
94
+ >();
95
+
96
+ const toScopeValues = (
97
+ value: ScopeValuesFromPatterns<ScopeDefs> | undefined
98
+ ): Record<string, ScopeValue> => {
99
+ const result: Record<string, ScopeValue> = {};
100
+ for (const [key, scopeValue] of Object.entries(
101
+ (value ?? {}) as Record<string, ScopeValue | undefined>
102
+ )) {
103
+ if (scopeValue === undefined) continue;
104
+ result[key] = scopeValue;
105
+ }
106
+ return result;
107
+ };
108
+
109
+ const sync: ClientSyncBuilder<DB, ScopeDefs, Identity> = {
110
+ handlers,
111
+ addHandler<TableName extends SharedTableName<DB>>(
112
+ handlerOptions: ClientSyncHandlerOptionsForTable<
113
+ DB,
114
+ TableName,
115
+ ScopeDefs,
116
+ Identity
117
+ >
118
+ ) {
119
+ if (registeredTables.has(handlerOptions.table)) {
120
+ throw new Error(
121
+ `Client table handler already registered: ${handlerOptions.table}`
122
+ );
123
+ }
124
+
125
+ handlers.push(
126
+ createClientHandler({
127
+ ...handlerOptions,
128
+ subscribe: false,
129
+ columnCodecs: options.codecs,
130
+ codecDialect: options.codecDialect,
131
+ })
132
+ );
133
+ subscriptionsByTable.set(
134
+ handlerOptions.table,
135
+ handlerOptions.subscribe as ClientSyncHandlerOptionsForTable<
136
+ DB,
137
+ SharedTableName<DB>,
138
+ ScopeDefs,
139
+ Identity
140
+ >['subscribe']
141
+ );
142
+ registeredTables.add(handlerOptions.table);
143
+ return sync;
144
+ },
145
+ subscriptions(
146
+ identity: Identity
147
+ ): Array<Omit<SyncSubscriptionRequest, 'cursor'>> {
148
+ const resolved: Array<Omit<SyncSubscriptionRequest, 'cursor'>> = [];
149
+ for (const [table, subscribe] of subscriptionsByTable.entries()) {
150
+ if (!subscribe) continue;
151
+ const value =
152
+ typeof subscribe === 'function' ? subscribe({ identity }) : subscribe;
153
+ if (!value) continue;
154
+ const entries = Array.isArray(value) ? value : [value];
155
+ for (const entry of entries) {
156
+ resolved.push({
157
+ id: entry.id,
158
+ table: entry.table ?? table,
159
+ scopes: toScopeValues(entry.scopes),
160
+ params: entry.params,
161
+ bootstrapState: entry.bootstrapState,
162
+ });
163
+ }
164
+ }
165
+ return resolved;
166
+ },
167
+ };
168
+
169
+ return sync;
170
+ }
@@ -1,15 +0,0 @@
1
- /**
2
- * @syncular/client - Sync client table registry
3
- */
4
- import type { ClientTableHandler } from './types';
5
- /**
6
- * Registry for client-side table handlers.
7
- */
8
- export declare class ClientTableRegistry<DB> {
9
- private handlers;
10
- register(handler: ClientTableHandler<DB>): this;
11
- get(table: string): ClientTableHandler<DB> | undefined;
12
- getOrThrow(table: string): ClientTableHandler<DB>;
13
- getAll(): ClientTableHandler<DB>[];
14
- }
15
- //# sourceMappingURL=registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/handlers/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;GAEG;AACH,qBAAa,mBAAmB,CAAC,EAAE;IACjC,OAAO,CAAC,QAAQ,CAA6C;IAE7D,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAAE,CAAC,GAAG,IAAI,CAQ9C;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;CACF"}
@@ -1,29 +0,0 @@
1
- /**
2
- * @syncular/client - Sync client table registry
3
- */
4
- /**
5
- * Registry for client-side table handlers.
6
- */
7
- export class ClientTableRegistry {
8
- handlers = new Map();
9
- register(handler) {
10
- if (this.handlers.has(handler.table)) {
11
- throw new Error(`Client table handler already registered: ${handler.table}`);
12
- }
13
- this.handlers.set(handler.table, handler);
14
- return this;
15
- }
16
- get(table) {
17
- return this.handlers.get(table);
18
- }
19
- getOrThrow(table) {
20
- const h = this.handlers.get(table);
21
- if (!h)
22
- throw new Error(`Missing client table handler for table: ${table}`);
23
- return h;
24
- }
25
- getAll() {
26
- return Array.from(this.handlers.values());
27
- }
28
- }
29
- //# sourceMappingURL=registry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/handlers/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,OAAO,mBAAmB;IACtB,QAAQ,GAAG,IAAI,GAAG,EAAkC,CAAC;IAE7D,QAAQ,CAAC,OAA+B,EAAQ;QAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,4CAA4C,OAAO,CAAC,KAAK,EAAE,CAC5D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IAAA,CACb;IAED,GAAG,CAAC,KAAa,EAAsC;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAAA,CACjC;IAED,UAAU,CAAC,KAAa,EAA0B;QAChD,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,CAAC;IAAA,CACV;IAED,MAAM,GAA6B;QACjC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAAA,CAC3C;CACF"}
@@ -1,36 +0,0 @@
1
- /**
2
- * @syncular/client - Sync client table registry
3
- */
4
-
5
- import type { ClientTableHandler } from './types';
6
-
7
- /**
8
- * Registry for client-side table handlers.
9
- */
10
- export class ClientTableRegistry<DB> {
11
- private handlers = new Map<string, ClientTableHandler<DB>>();
12
-
13
- register(handler: ClientTableHandler<DB>): this {
14
- if (this.handlers.has(handler.table)) {
15
- throw new Error(
16
- `Client table handler already registered: ${handler.table}`
17
- );
18
- }
19
- this.handlers.set(handler.table, handler);
20
- return this;
21
- }
22
-
23
- get(table: string): ClientTableHandler<DB> | undefined {
24
- return this.handlers.get(table);
25
- }
26
-
27
- getOrThrow(table: string): ClientTableHandler<DB> {
28
- const h = this.handlers.get(table);
29
- if (!h) throw new Error(`Missing client table handler for table: ${table}`);
30
- return h;
31
- }
32
-
33
- getAll(): ClientTableHandler<DB>[] {
34
- return Array.from(this.handlers.values());
35
- }
36
- }