@syncular/core 0.0.1-98 → 0.0.2-126

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/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @syncular/core
2
+
3
+ Core protocol types, schemas, and shared utilities for Syncular (scopes, commit-log types, telemetry, blob types, etc.).
4
+
5
+ Most apps won't depend on this directly. It is the shared foundation used by `@syncular/client`, `@syncular/server`, and the transports.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @syncular/core
11
+ ```
12
+
13
+ ## Documentation
14
+
15
+ - Overview: https://syncular.dev/docs/introduction/what-is-syncular
16
+ - Architecture (commit log, push/pull, snapshots): https://syncular.dev/docs/introduction/architecture
17
+
18
+ ## Links
19
+
20
+ - GitHub: https://github.com/syncular/syncular
21
+ - Issues: https://github.com/syncular/syncular/issues
22
+
23
+ > Status: Alpha. APIs and storage layouts may change between releases.
24
+
@@ -0,0 +1,55 @@
1
+ export type ColumnCodecDialect = 'sqlite' | 'postgres';
2
+ export interface ColumnCodecTypeImport {
3
+ name: string;
4
+ from: string;
5
+ }
6
+ export type ColumnCodecType = string | {
7
+ type: string;
8
+ import?: ColumnCodecTypeImport;
9
+ };
10
+ export interface ColumnCodec<App, Db> {
11
+ ts: ColumnCodecType;
12
+ toDb(value: App): Db;
13
+ fromDb(value: Db): App;
14
+ dialects?: Partial<Record<ColumnCodecDialect, {
15
+ toDb?(value: App): Db;
16
+ fromDb?(value: Db): App;
17
+ }>>;
18
+ }
19
+ export type AnyColumnCodec = ColumnCodec<unknown, unknown>;
20
+ export interface ColumnCodecColumn {
21
+ table: string;
22
+ column: string;
23
+ sqlType?: string;
24
+ nullable?: boolean;
25
+ isPrimaryKey?: boolean;
26
+ hasDefault?: boolean;
27
+ dialect?: ColumnCodecDialect;
28
+ }
29
+ export type TableColumnCodecs = Record<string, AnyColumnCodec>;
30
+ export type ColumnCodecSource = (column: ColumnCodecColumn) => AnyColumnCodec | undefined;
31
+ export declare function toTableColumnCodecs(table: string, codecSource: ColumnCodecSource | undefined, columns: Iterable<string>, options?: {
32
+ dialect?: ColumnCodecDialect;
33
+ sqlTypes?: Record<string, string | undefined>;
34
+ }): TableColumnCodecs;
35
+ export declare function applyCodecToDbValue(codec: AnyColumnCodec, value: unknown, dialect?: ColumnCodecDialect): unknown;
36
+ export declare function applyCodecFromDbValue(codec: AnyColumnCodec, value: unknown, dialect?: ColumnCodecDialect): unknown;
37
+ export declare function applyCodecsToDbRow(row: Record<string, unknown>, tableCodecs: TableColumnCodecs, dialect?: ColumnCodecDialect): Record<string, unknown>;
38
+ export declare function applyCodecsFromDbRow(row: Record<string, unknown>, tableCodecs: TableColumnCodecs, dialect?: ColumnCodecDialect): Record<string, unknown>;
39
+ export declare function numberBoolean(): ColumnCodec<boolean, number | boolean | string>;
40
+ export interface StringJsonCodecOptions<T> {
41
+ ts?: ColumnCodecType;
42
+ import?: ColumnCodecTypeImport;
43
+ stringify?: (value: T) => string;
44
+ parse?: (value: string) => T;
45
+ }
46
+ export declare function stringJson<T = unknown>(options?: StringJsonCodecOptions<T>): ColumnCodec<T, string | T>;
47
+ export declare function timestampDate(): ColumnCodec<Date, string | Date>;
48
+ export declare function dateString(): ColumnCodec<string, string | Date>;
49
+ export declare const codecs: {
50
+ numberBoolean: typeof numberBoolean;
51
+ stringJson: typeof stringJson;
52
+ timestampDate: typeof timestampDate;
53
+ dateString: typeof dateString;
54
+ };
55
+ //# sourceMappingURL=column-codecs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-codecs.d.ts","sourceRoot":"","sources":["../src/column-codecs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ function hasCodecs(tableCodecs) {
2
+ return Object.keys(tableCodecs).length > 0;
3
+ }
4
+ function resolveCodecToDb(codec, dialect) {
5
+ return codec.dialects?.[dialect]?.toDb ?? codec.toDb;
6
+ }
7
+ function resolveCodecFromDb(codec, dialect) {
8
+ return codec.dialects?.[dialect]?.fromDb ?? codec.fromDb;
9
+ }
10
+ export function toTableColumnCodecs(table, codecSource, columns, options = {}) {
11
+ if (!codecSource)
12
+ return {};
13
+ const out = {};
14
+ for (const column of columns) {
15
+ if (column.length === 0)
16
+ continue;
17
+ const codec = codecSource({
18
+ table,
19
+ column,
20
+ sqlType: options.sqlTypes?.[column],
21
+ dialect: options.dialect,
22
+ });
23
+ if (codec)
24
+ out[column] = codec;
25
+ }
26
+ return out;
27
+ }
28
+ export function applyCodecToDbValue(codec, value, dialect = 'sqlite') {
29
+ if (value === null || value === undefined)
30
+ return value;
31
+ const transform = resolveCodecToDb(codec, dialect);
32
+ return transform(value);
33
+ }
34
+ export function applyCodecFromDbValue(codec, value, dialect = 'sqlite') {
35
+ if (value === null || value === undefined)
36
+ return value;
37
+ const transform = resolveCodecFromDb(codec, dialect);
38
+ return transform(value);
39
+ }
40
+ export function applyCodecsToDbRow(row, tableCodecs, dialect = 'sqlite') {
41
+ if (!hasCodecs(tableCodecs))
42
+ return { ...row };
43
+ const transformed = { ...row };
44
+ for (const [column, codec] of Object.entries(tableCodecs)) {
45
+ if (!(column in transformed))
46
+ continue;
47
+ transformed[column] = applyCodecToDbValue(codec, transformed[column], dialect);
48
+ }
49
+ return transformed;
50
+ }
51
+ export function applyCodecsFromDbRow(row, tableCodecs, dialect = 'sqlite') {
52
+ if (!hasCodecs(tableCodecs))
53
+ return { ...row };
54
+ const transformed = { ...row };
55
+ for (const [column, codec] of Object.entries(tableCodecs)) {
56
+ if (!(column in transformed))
57
+ continue;
58
+ transformed[column] = applyCodecFromDbValue(codec, transformed[column], dialect);
59
+ }
60
+ return transformed;
61
+ }
62
+ function parseBooleanValue(value) {
63
+ if (typeof value === 'boolean')
64
+ return value;
65
+ if (typeof value === 'number')
66
+ return value === 1;
67
+ if (typeof value === 'string') {
68
+ const normalized = value.trim().toLowerCase();
69
+ return normalized === '1' || normalized === 'true';
70
+ }
71
+ return Boolean(value);
72
+ }
73
+ export function numberBoolean() {
74
+ return {
75
+ ts: 'boolean',
76
+ toDb: (value) => (value ? 1 : 0),
77
+ fromDb: (value) => parseBooleanValue(value),
78
+ dialects: {
79
+ postgres: {
80
+ toDb: (value) => value,
81
+ fromDb: (value) => parseBooleanValue(value),
82
+ },
83
+ },
84
+ };
85
+ }
86
+ export function stringJson(options = {}) {
87
+ const stringify = options.stringify ?? ((value) => JSON.stringify(value));
88
+ const parse = options.parse ?? ((value) => JSON.parse(value));
89
+ const ts = options.ts ??
90
+ (options.import
91
+ ? { type: options.import.name, import: options.import }
92
+ : 'unknown');
93
+ return {
94
+ ts,
95
+ toDb: (value) => stringify(value),
96
+ fromDb: (value) => {
97
+ if (typeof value === 'string') {
98
+ return parse(value);
99
+ }
100
+ return value;
101
+ },
102
+ };
103
+ }
104
+ export function timestampDate() {
105
+ return {
106
+ ts: 'Date',
107
+ toDb: (value) => value.toISOString(),
108
+ fromDb: (value) => value instanceof Date ? value : new Date(String(value)),
109
+ };
110
+ }
111
+ export function dateString() {
112
+ return {
113
+ ts: 'string',
114
+ toDb: (value) => value,
115
+ fromDb: (value) => value instanceof Date ? value.toISOString().slice(0, 10) : String(value),
116
+ };
117
+ }
118
+ export const codecs = {
119
+ numberBoolean,
120
+ stringJson,
121
+ timestampDate,
122
+ dateString,
123
+ };
124
+ //# sourceMappingURL=column-codecs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-codecs.js","sourceRoot":"","sources":["../src/column-codecs.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  * - Zod schemas for runtime validation and OpenAPI
11
11
  */
12
12
  export * from './blobs';
13
+ export * from './column-codecs';
13
14
  export * from './conflict';
14
15
  export * from './kysely-serialize';
15
16
  export * from './logger';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,cAAc,SAAS,CAAC;AAExB,cAAc,YAAY,CAAC;AAE3B,cAAc,oBAAoB,CAAC;AAEnC,cAAc,UAAU,CAAC;AAEzB,cAAc,SAAS,CAAC;AAExB,cAAc,WAAW,CAAC;AAE1B,cAAc,UAAU,CAAC;AAEzB,cAAc,mBAAmB,CAAC;AAElC,cAAc,aAAa,CAAC;AAE5B,cAAc,cAAc,CAAC;AAE7B,cAAc,SAAS,CAAC;AAExB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,cAAc,SAAS,CAAC;AAExB,cAAc,iBAAiB,CAAC;AAEhC,cAAc,YAAY,CAAC;AAE3B,cAAc,oBAAoB,CAAC;AAEnC,cAAc,UAAU,CAAC;AAEzB,cAAc,SAAS,CAAC;AAExB,cAAc,WAAW,CAAC;AAE1B,cAAc,UAAU,CAAC;AAEzB,cAAc,mBAAmB,CAAC;AAElC,cAAc,aAAa,CAAC;AAE5B,cAAc,cAAc,CAAC;AAE7B,cAAc,SAAS,CAAC;AAExB,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -11,6 +11,8 @@
11
11
  */
12
12
  // Blob transport/storage types and utilities (protocol types come from ./schemas)
13
13
  export * from './blobs.js';
14
+ // Column-level codecs shared by typegen and runtime paths
15
+ export * from './column-codecs.js';
14
16
  // Conflict detection utilities
15
17
  export * from './conflict.js';
16
18
  // Kysely plugin utilities
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,cAAc,SAAS,CAAC;AACxB,+BAA+B;AAC/B,cAAc,YAAY,CAAC;AAC3B,0BAA0B;AAC1B,cAAc,oBAAoB,CAAC;AACnC,oBAAoB;AACpB,cAAc,UAAU,CAAC;AACzB,uBAAuB;AACvB,cAAc,SAAS,CAAC;AACxB,gBAAgB;AAChB,cAAc,WAAW,CAAC;AAC1B,uCAAuC;AACvC,cAAc,UAAU,CAAC;AACzB,kCAAkC;AAClC,cAAc,mBAAmB,CAAC;AAClC,wBAAwB;AACxB,cAAc,aAAa,CAAC;AAC5B,4BAA4B;AAC5B,cAAc,cAAc,CAAC;AAC7B,oEAAoE;AACpE,cAAc,SAAS,CAAC;AACxB,2BAA2B;AAC3B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,cAAc,SAAS,CAAC;AACxB,0DAA0D;AAC1D,cAAc,iBAAiB,CAAC;AAChC,+BAA+B;AAC/B,cAAc,YAAY,CAAC;AAC3B,0BAA0B;AAC1B,cAAc,oBAAoB,CAAC;AACnC,oBAAoB;AACpB,cAAc,UAAU,CAAC;AACzB,uBAAuB;AACvB,cAAc,SAAS,CAAC;AACxB,gBAAgB;AAChB,cAAc,WAAW,CAAC;AAC1B,uCAAuC;AACvC,cAAc,UAAU,CAAC;AACzB,kCAAkC;AAClC,cAAc,mBAAmB,CAAC;AAClC,wBAAwB;AACxB,cAAc,aAAa,CAAC;AAC5B,4BAA4B;AAC5B,cAAc,cAAc,CAAC;AAC7B,oEAAoE;AACpE,cAAc,SAAS,CAAC;AACxB,2BAA2B;AAC3B,cAAc,SAAS,CAAC"}
@@ -95,7 +95,7 @@ export declare const SyncBootstrapStateSchema: z.ZodObject<{
95
95
  export type SyncBootstrapState = z.infer<typeof SyncBootstrapStateSchema>;
96
96
  export declare const SyncSubscriptionRequestSchema: z.ZodObject<{
97
97
  id: z.ZodString;
98
- shape: z.ZodString;
98
+ table: z.ZodString;
99
99
  scopes: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
100
100
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
101
101
  cursor: z.ZodNumber;
@@ -115,7 +115,7 @@ export declare const SyncPullRequestSchema: z.ZodObject<{
115
115
  dedupeRows: z.ZodOptional<z.ZodBoolean>;
116
116
  subscriptions: z.ZodArray<z.ZodObject<{
117
117
  id: z.ZodString;
118
- shape: z.ZodString;
118
+ table: z.ZodString;
119
119
  scopes: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
120
120
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
121
121
  cursor: z.ZodNumber;
@@ -297,7 +297,7 @@ export declare const SyncCombinedRequestSchema: z.ZodObject<{
297
297
  dedupeRows: z.ZodOptional<z.ZodBoolean>;
298
298
  subscriptions: z.ZodArray<z.ZodObject<{
299
299
  id: z.ZodString;
300
- shape: z.ZodString;
300
+ table: z.ZodString;
301
301
  scopes: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
302
302
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
303
303
  cursor: z.ZodNumber;
@@ -85,7 +85,7 @@ export const SyncBootstrapStateSchema = z.object({
85
85
  // ============================================================================
86
86
  export const SyncSubscriptionRequestSchema = z.object({
87
87
  id: z.string().min(1),
88
- shape: z.string().min(1),
88
+ table: z.string().min(1),
89
89
  scopes: ScopeValuesSchema,
90
90
  params: z.record(z.string(), z.unknown()).optional(),
91
91
  cursor: z.number().int(),
@@ -9,6 +9,10 @@
9
9
  * Scope pattern string, e.g., 'user:{user_id}', 'project:{project_id}'
10
10
  */
11
11
  export type ScopePattern = string;
12
+ /**
13
+ * Scope value for a single scope key.
14
+ */
15
+ export type ScopeValue = string | string[];
12
16
  /**
13
17
  * Scope values - the actual values for scope variables.
14
18
  * Values can be single strings or arrays (for multi-value subscriptions).
@@ -18,7 +22,7 @@ export type ScopePattern = string;
18
22
  * { project_id: ['P1', 'P2'] }
19
23
  * { year: '2025', month: '03' }
20
24
  */
21
- export type ScopeValues = Record<string, string | string[]>;
25
+ export type ScopeValues = Record<string, ScopeValue>;
22
26
  /**
23
27
  * Stored scopes on a change - always single values (not arrays).
24
28
  * This is what gets stored in the JSONB column.
@@ -27,6 +31,38 @@ export type ScopeValues = Record<string, string | string[]>;
27
31
  * { user_id: 'U1', project_id: 'P1' }
28
32
  */
29
33
  export type StoredScopes = Record<string, string>;
34
+ /**
35
+ * Extract scope keys from a scope pattern at the type level.
36
+ *
37
+ * @example
38
+ * ScopeKeysFromPattern<'user:{user_id}'> // 'user_id'
39
+ * ScopeKeysFromPattern<'event:{year}:{month}'> // 'year' | 'month'
40
+ */
41
+ export type ScopeKeysFromPattern<Pattern extends ScopePattern> = string extends Pattern ? string : Pattern extends `${string}{${infer Key}}${infer Rest}` ? Key | ScopeKeysFromPattern<Rest> : never;
42
+ /**
43
+ * Resolve the pattern string from a scope definition.
44
+ */
45
+ export type ScopePatternFromDefinition<Definition extends ScopeDefinition> = Definition extends ScopePattern ? Definition : Definition extends {
46
+ pattern: infer Pattern extends ScopePattern;
47
+ } ? Pattern : never;
48
+ /**
49
+ * Extract scope keys from a list of scope definitions.
50
+ */
51
+ export type ScopeKeysFromDefinitions<Definitions extends readonly ScopeDefinition[]> = ScopeKeysFromPattern<ScopePatternFromDefinition<Definitions[number]>>;
52
+ /**
53
+ * Scope values constrained to known scope keys.
54
+ *
55
+ * Unknown keys are rejected at compile-time when literals are used.
56
+ */
57
+ export type ScopeValuesForKeys<ScopeKeys extends string> = Partial<Record<ScopeKeys, ScopeValue>>;
58
+ /**
59
+ * Scope values inferred from scope definitions.
60
+ */
61
+ export type ScopeValuesFromPatterns<Definitions extends readonly ScopeDefinition[]> = ScopeValuesForKeys<ScopeKeysFromDefinitions<Definitions>>;
62
+ /**
63
+ * Stored scopes constrained to known scope keys.
64
+ */
65
+ export type StoredScopesForKeys<ScopeKeys extends string> = Partial<Record<ScopeKeys, string>>;
30
66
  /**
31
67
  * Simplified scope definition.
32
68
  * Can be a simple pattern string or an object with explicit column mapping.
@@ -42,10 +78,17 @@ export type StoredScopes = Record<string, string>;
42
78
  * ]
43
79
  * ```
44
80
  */
45
- export type ScopeDefinition = string | {
46
- pattern: string;
81
+ export type ScopeDefinition = ScopePattern | {
82
+ pattern: ScopePattern;
47
83
  column: string;
48
84
  };
85
+ /**
86
+ * Keep scope definitions as a typed tuple for downstream inference.
87
+ *
88
+ * @example
89
+ * const scopes = defineScopePatterns(['user:{user_id}'] as const);
90
+ */
91
+ export declare function defineScopePatterns<const Definitions extends readonly ScopeDefinition[]>(scopes: Definitions): Definitions;
49
92
  /**
50
93
  * Normalize scope definitions to a pattern-to-column map.
51
94
  *
@@ -53,7 +96,7 @@ export type ScopeDefinition = string | {
53
96
  * normalizeScopes(['user:{user_id}'])
54
97
  * // → { 'user:{user_id}': 'user_id' }
55
98
  */
56
- export declare function normalizeScopes(scopes: ScopeDefinition[]): Record<string, string>;
99
+ export declare function normalizeScopes(scopes: readonly ScopeDefinition[]): Record<ScopePattern, string>;
57
100
  /**
58
101
  * Extract variable names from a scope pattern.
59
102
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scopes/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA+B3E;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EAAE,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBxB;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CAIhE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scopes/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,CAAC,OAAO,SAAS,YAAY,IAC3D,MAAM,SAAS,OAAO,GAClB,MAAM,GACN,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,EAAE,GACpD,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAChC,KAAK,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,0BAA0B,CAAC,UAAU,SAAS,eAAe,IACvE,UAAU,SAAS,YAAY,GAC3B,UAAU,GACV,UAAU,SAAS;IAAE,OAAO,EAAE,MAAM,OAAO,SAAS,YAAY,CAAA;CAAE,GAChE,OAAO,GACP,KAAK,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,wBAAwB,CAClC,WAAW,SAAS,SAAS,eAAe,EAAE,IAC5C,oBAAoB,CAAC,0BAA0B,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,SAAS,SAAS,MAAM,IAAI,OAAO,CAChE,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAC9B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,CACjC,WAAW,SAAS,SAAS,eAAe,EAAE,IAC5C,kBAAkB,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,SAAS,SAAS,MAAM,IAAI,OAAO,CACjE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAC1B,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,CAAC,WAAW,SAAS,SAAS,eAAe,EAAE,EACpD,MAAM,EAAE,WAAW,GAAG,WAAW,CAElC;AA+BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,eAAe,EAAE,GACjC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAgB9B;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CAIhE"}
@@ -5,6 +5,15 @@
5
5
  * Scopes are stored as JSONB on changes for flexible filtering.
6
6
  * Patterns use `{placeholder}` syntax to extract or inject values.
7
7
  */
8
+ /**
9
+ * Keep scope definitions as a typed tuple for downstream inference.
10
+ *
11
+ * @example
12
+ * const scopes = defineScopePatterns(['user:{user_id}'] as const);
13
+ */
14
+ export function defineScopePatterns(scopes) {
15
+ return scopes;
16
+ }
8
17
  // ── Pattern parsing (internal helpers) ───────────────────────────────
9
18
  /**
10
19
  * Extract the placeholder name from a pattern.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scopes/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8CH,0IAAwE;AAExE;;;GAGG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAIlC;IACP,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE;QACjB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE;QACtB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE;KAClB,CAAC;AAAA,CACH;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAiB;IAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC;AAAA,CACpC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAyB,EACD;IACxB,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,iDAAiD,CACzE,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACf;AAED,4JAAwE;AAExE;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAqB,EAAY;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CAC3C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scopes/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2GH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAEjC,MAAmB,EAAe;IAClC,OAAO,MAAM,CAAC;AAAA,CACf;AAED,0IAAwE;AAExE;;;GAGG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAIlC;IACP,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE;QACjB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE;QACtB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE;KAClB,CAAC;AAAA,CACH;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAiB;IAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC;AAAA,CACpC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAkC,EACJ;IAC9B,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,iDAAiD,CACzE,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACf;AAED,4JAAwE;AAExE;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAqB,EAAY;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CAC3C"}
package/dist/types.d.ts CHANGED
@@ -111,6 +111,15 @@ export interface SyncTransport {
111
111
  fetchSnapshotChunk(request: {
112
112
  chunkId: string;
113
113
  }, options?: SyncTransportOptions): Promise<Uint8Array>;
114
+ /**
115
+ * Optional streaming snapshot chunk download.
116
+ *
117
+ * When implemented, clients can decode and apply large bootstrap chunks
118
+ * incrementally without materializing the entire chunk in memory.
119
+ */
120
+ fetchSnapshotChunkStream?(request: {
121
+ chunkId: string;
122
+ }, options?: SyncTransportOptions): Promise<ReadableStream<Uint8Array>>;
114
123
  /**
115
124
  * Optional blob operations.
116
125
  * When present, enables blob upload/download functionality.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAMhF;;GAEG;AACH,UAAU,qBAAqB;IAC7B,WAAW,EAAE,KAAK,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,2BAA2B;IACnC,WAAW,EAAE,IAAI,CAAC;IAClB,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,6BAA6B;IAC7B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,2BAA2B,CAAC;AAEhC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,IAAI,CAAC;IACf,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC;IAChB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,mBAAmB,CAAC;AAM9D;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QACV,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;QAC9B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACxC,CAAC,CAAC;IAEH;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEvE;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,CACF,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC;;OAEG;IACH,kBAAkB,CAChB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,EAC5B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;OAGG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,MAAM,CAAC;aACP,IAAI,CAAC;IAHvB,YACE,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,oBAAQ,EACf,IAAI,CAAC,oBAAQ,EAI9B;CACF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4IH;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGzB,MAAM;IACN,IAAI;IAHtB,YACE,OAAe,EACC,MAAe,EACf,IAAa,EAC7B;QACA,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHC,MAAM;oBACN,IAAI;QAGpB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IAAA,CAClC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuJH;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGzB,MAAM;IACN,IAAI;IAHtB,YACE,OAAe,EACC,MAAe,EACf,IAAa,EAC7B;QACA,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHC,MAAM;oBACN,IAAI;QAGpB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IAAA,CAClC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/core",
3
- "version": "0.0.1-98",
3
+ "version": "0.0.2-126",
4
4
  "description": "Core protocol types and shared utilities for the Syncular sync framework",
5
5
  "license": "MIT",
6
6
  "author": "Benjamin Kniffler",
@@ -0,0 +1,228 @@
1
+ export type ColumnCodecDialect = 'sqlite' | 'postgres';
2
+
3
+ export interface ColumnCodecTypeImport {
4
+ name: string;
5
+ from: string;
6
+ }
7
+
8
+ export type ColumnCodecType =
9
+ | string
10
+ | { type: string; import?: ColumnCodecTypeImport };
11
+
12
+ export interface ColumnCodec<App, Db> {
13
+ ts: ColumnCodecType;
14
+ toDb(value: App): Db;
15
+ fromDb(value: Db): App;
16
+ dialects?: Partial<
17
+ Record<
18
+ ColumnCodecDialect,
19
+ {
20
+ toDb?(value: App): Db;
21
+ fromDb?(value: Db): App;
22
+ }
23
+ >
24
+ >;
25
+ }
26
+
27
+ export type AnyColumnCodec = ColumnCodec<unknown, unknown>;
28
+
29
+ export interface ColumnCodecColumn {
30
+ table: string;
31
+ column: string;
32
+ sqlType?: string;
33
+ nullable?: boolean;
34
+ isPrimaryKey?: boolean;
35
+ hasDefault?: boolean;
36
+ dialect?: ColumnCodecDialect;
37
+ }
38
+
39
+ export type TableColumnCodecs = Record<string, AnyColumnCodec>;
40
+
41
+ export type ColumnCodecSource = (
42
+ column: ColumnCodecColumn
43
+ ) => AnyColumnCodec | undefined;
44
+
45
+ function hasCodecs(tableCodecs: TableColumnCodecs): boolean {
46
+ return Object.keys(tableCodecs).length > 0;
47
+ }
48
+
49
+ function resolveCodecToDb(
50
+ codec: AnyColumnCodec,
51
+ dialect: ColumnCodecDialect
52
+ ): (value: unknown) => unknown {
53
+ return codec.dialects?.[dialect]?.toDb ?? codec.toDb;
54
+ }
55
+
56
+ function resolveCodecFromDb(
57
+ codec: AnyColumnCodec,
58
+ dialect: ColumnCodecDialect
59
+ ): (value: unknown) => unknown {
60
+ return codec.dialects?.[dialect]?.fromDb ?? codec.fromDb;
61
+ }
62
+
63
+ export function toTableColumnCodecs(
64
+ table: string,
65
+ codecSource: ColumnCodecSource | undefined,
66
+ columns: Iterable<string>,
67
+ options: {
68
+ dialect?: ColumnCodecDialect;
69
+ sqlTypes?: Record<string, string | undefined>;
70
+ } = {}
71
+ ): TableColumnCodecs {
72
+ if (!codecSource) return {};
73
+ const out: TableColumnCodecs = {};
74
+
75
+ for (const column of columns) {
76
+ if (column.length === 0) continue;
77
+ const codec = codecSource({
78
+ table,
79
+ column,
80
+ sqlType: options.sqlTypes?.[column],
81
+ dialect: options.dialect,
82
+ });
83
+ if (codec) out[column] = codec;
84
+ }
85
+
86
+ return out;
87
+ }
88
+
89
+ export function applyCodecToDbValue(
90
+ codec: AnyColumnCodec,
91
+ value: unknown,
92
+ dialect: ColumnCodecDialect = 'sqlite'
93
+ ): unknown {
94
+ if (value === null || value === undefined) return value;
95
+ const transform = resolveCodecToDb(codec, dialect);
96
+ return transform(value);
97
+ }
98
+
99
+ export function applyCodecFromDbValue(
100
+ codec: AnyColumnCodec,
101
+ value: unknown,
102
+ dialect: ColumnCodecDialect = 'sqlite'
103
+ ): unknown {
104
+ if (value === null || value === undefined) return value;
105
+ const transform = resolveCodecFromDb(codec, dialect);
106
+ return transform(value);
107
+ }
108
+
109
+ export function applyCodecsToDbRow(
110
+ row: Record<string, unknown>,
111
+ tableCodecs: TableColumnCodecs,
112
+ dialect: ColumnCodecDialect = 'sqlite'
113
+ ): Record<string, unknown> {
114
+ if (!hasCodecs(tableCodecs)) return { ...row };
115
+
116
+ const transformed: Record<string, unknown> = { ...row };
117
+ for (const [column, codec] of Object.entries(tableCodecs)) {
118
+ if (!(column in transformed)) continue;
119
+ transformed[column] = applyCodecToDbValue(
120
+ codec,
121
+ transformed[column],
122
+ dialect
123
+ );
124
+ }
125
+ return transformed;
126
+ }
127
+
128
+ export function applyCodecsFromDbRow(
129
+ row: Record<string, unknown>,
130
+ tableCodecs: TableColumnCodecs,
131
+ dialect: ColumnCodecDialect = 'sqlite'
132
+ ): Record<string, unknown> {
133
+ if (!hasCodecs(tableCodecs)) return { ...row };
134
+
135
+ const transformed: Record<string, unknown> = { ...row };
136
+ for (const [column, codec] of Object.entries(tableCodecs)) {
137
+ if (!(column in transformed)) continue;
138
+ transformed[column] = applyCodecFromDbValue(
139
+ codec,
140
+ transformed[column],
141
+ dialect
142
+ );
143
+ }
144
+ return transformed;
145
+ }
146
+
147
+ function parseBooleanValue(value: unknown): boolean {
148
+ if (typeof value === 'boolean') return value;
149
+ if (typeof value === 'number') return value === 1;
150
+ if (typeof value === 'string') {
151
+ const normalized = value.trim().toLowerCase();
152
+ return normalized === '1' || normalized === 'true';
153
+ }
154
+ return Boolean(value);
155
+ }
156
+
157
+ export function numberBoolean(): ColumnCodec<
158
+ boolean,
159
+ number | boolean | string
160
+ > {
161
+ return {
162
+ ts: 'boolean',
163
+ toDb: (value) => (value ? 1 : 0),
164
+ fromDb: (value) => parseBooleanValue(value),
165
+ dialects: {
166
+ postgres: {
167
+ toDb: (value) => value,
168
+ fromDb: (value) => parseBooleanValue(value),
169
+ },
170
+ },
171
+ };
172
+ }
173
+
174
+ export interface StringJsonCodecOptions<T> {
175
+ ts?: ColumnCodecType;
176
+ import?: ColumnCodecTypeImport;
177
+ stringify?: (value: T) => string;
178
+ parse?: (value: string) => T;
179
+ }
180
+
181
+ export function stringJson<T = unknown>(
182
+ options: StringJsonCodecOptions<T> = {}
183
+ ): ColumnCodec<T, string | T> {
184
+ const stringify = options.stringify ?? ((value: T) => JSON.stringify(value));
185
+ const parse = options.parse ?? ((value: string) => JSON.parse(value) as T);
186
+
187
+ const ts: ColumnCodecType =
188
+ options.ts ??
189
+ (options.import
190
+ ? { type: options.import.name, import: options.import }
191
+ : 'unknown');
192
+
193
+ return {
194
+ ts,
195
+ toDb: (value) => stringify(value),
196
+ fromDb: (value) => {
197
+ if (typeof value === 'string') {
198
+ return parse(value);
199
+ }
200
+ return value as T;
201
+ },
202
+ };
203
+ }
204
+
205
+ export function timestampDate(): ColumnCodec<Date, string | Date> {
206
+ return {
207
+ ts: 'Date',
208
+ toDb: (value) => value.toISOString(),
209
+ fromDb: (value) =>
210
+ value instanceof Date ? value : new Date(String(value)),
211
+ };
212
+ }
213
+
214
+ export function dateString(): ColumnCodec<string, string | Date> {
215
+ return {
216
+ ts: 'string',
217
+ toDb: (value) => value,
218
+ fromDb: (value) =>
219
+ value instanceof Date ? value.toISOString().slice(0, 10) : String(value),
220
+ };
221
+ }
222
+
223
+ export const codecs = {
224
+ numberBoolean,
225
+ stringJson,
226
+ timestampDate,
227
+ dateString,
228
+ };
package/src/index.ts CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  // Blob transport/storage types and utilities (protocol types come from ./schemas)
14
14
  export * from './blobs';
15
+ // Column-level codecs shared by typegen and runtime paths
16
+ export * from './column-codecs';
15
17
  // Conflict detection utilities
16
18
  export * from './conflict';
17
19
  // Kysely plugin utilities
@@ -121,7 +121,7 @@ export type SyncBootstrapState = z.infer<typeof SyncBootstrapStateSchema>;
121
121
 
122
122
  export const SyncSubscriptionRequestSchema = z.object({
123
123
  id: z.string().min(1),
124
- shape: z.string().min(1),
124
+ table: z.string().min(1),
125
125
  scopes: ScopeValuesSchema,
126
126
  params: z.record(z.string(), z.unknown()).optional(),
127
127
  cursor: z.number().int(),
@@ -13,6 +13,11 @@
13
13
  */
14
14
  export type ScopePattern = string;
15
15
 
16
+ /**
17
+ * Scope value for a single scope key.
18
+ */
19
+ export type ScopeValue = string | string[];
20
+
16
21
  /**
17
22
  * Scope values - the actual values for scope variables.
18
23
  * Values can be single strings or arrays (for multi-value subscriptions).
@@ -22,7 +27,7 @@ export type ScopePattern = string;
22
27
  * { project_id: ['P1', 'P2'] }
23
28
  * { year: '2025', month: '03' }
24
29
  */
25
- export type ScopeValues = Record<string, string | string[]>;
30
+ export type ScopeValues = Record<string, ScopeValue>;
26
31
 
27
32
  /**
28
33
  * Stored scopes on a change - always single values (not arrays).
@@ -33,6 +38,60 @@ export type ScopeValues = Record<string, string | string[]>;
33
38
  */
34
39
  export type StoredScopes = Record<string, string>;
35
40
 
41
+ /**
42
+ * Extract scope keys from a scope pattern at the type level.
43
+ *
44
+ * @example
45
+ * ScopeKeysFromPattern<'user:{user_id}'> // 'user_id'
46
+ * ScopeKeysFromPattern<'event:{year}:{month}'> // 'year' | 'month'
47
+ */
48
+ export type ScopeKeysFromPattern<Pattern extends ScopePattern> =
49
+ string extends Pattern
50
+ ? string
51
+ : Pattern extends `${string}{${infer Key}}${infer Rest}`
52
+ ? Key | ScopeKeysFromPattern<Rest>
53
+ : never;
54
+
55
+ /**
56
+ * Resolve the pattern string from a scope definition.
57
+ */
58
+ export type ScopePatternFromDefinition<Definition extends ScopeDefinition> =
59
+ Definition extends ScopePattern
60
+ ? Definition
61
+ : Definition extends { pattern: infer Pattern extends ScopePattern }
62
+ ? Pattern
63
+ : never;
64
+
65
+ /**
66
+ * Extract scope keys from a list of scope definitions.
67
+ */
68
+ export type ScopeKeysFromDefinitions<
69
+ Definitions extends readonly ScopeDefinition[],
70
+ > = ScopeKeysFromPattern<ScopePatternFromDefinition<Definitions[number]>>;
71
+
72
+ /**
73
+ * Scope values constrained to known scope keys.
74
+ *
75
+ * Unknown keys are rejected at compile-time when literals are used.
76
+ */
77
+ export type ScopeValuesForKeys<ScopeKeys extends string> = Partial<
78
+ Record<ScopeKeys, ScopeValue>
79
+ >;
80
+
81
+ /**
82
+ * Scope values inferred from scope definitions.
83
+ */
84
+ export type ScopeValuesFromPatterns<
85
+ Definitions extends readonly ScopeDefinition[],
86
+ > = ScopeValuesForKeys<ScopeKeysFromDefinitions<Definitions>>;
87
+
88
+ /**
89
+ * Stored scopes constrained to known scope keys.
90
+ */
91
+ export type StoredScopesForKeys<ScopeKeys extends string> = Partial<
92
+ Record<ScopeKeys, string>
93
+ >;
94
+
36
95
  /**
37
96
  * Simplified scope definition.
38
97
  * Can be a simple pattern string or an object with explicit column mapping.
@@ -48,7 +107,21 @@ export type StoredScopes = Record<string, string>;
48
107
  * ]
49
108
  * ```
50
109
  */
51
- export type ScopeDefinition = string | { pattern: string; column: string };
110
+ export type ScopeDefinition =
111
+ | ScopePattern
112
+ | { pattern: ScopePattern; column: string };
113
+
114
+ /**
115
+ * Keep scope definitions as a typed tuple for downstream inference.
116
+ *
117
+ * @example
118
+ * const scopes = defineScopePatterns(['user:{user_id}'] as const);
119
+ */
120
+ export function defineScopePatterns<
121
+ const Definitions extends readonly ScopeDefinition[],
122
+ >(scopes: Definitions): Definitions {
123
+ return scopes;
124
+ }
52
125
 
53
126
  // ── Pattern parsing (internal helpers) ───────────────────────────────
54
127
 
@@ -87,9 +160,9 @@ function getPlaceholderName(pattern: string): string | null {
87
160
  * // → { 'user:{user_id}': 'user_id' }
88
161
  */
89
162
  export function normalizeScopes(
90
- scopes: ScopeDefinition[]
91
- ): Record<string, string> {
92
- const result: Record<string, string> = {};
163
+ scopes: readonly ScopeDefinition[]
164
+ ): Record<ScopePattern, string> {
165
+ const result: Record<ScopePattern, string> = {};
93
166
  for (const scope of scopes) {
94
167
  if (typeof scope === 'string') {
95
168
  const placeholder = getPlaceholderName(scope);
package/src/types.ts CHANGED
@@ -136,6 +136,17 @@ export interface SyncTransport {
136
136
  options?: SyncTransportOptions
137
137
  ): Promise<Uint8Array>;
138
138
 
139
+ /**
140
+ * Optional streaming snapshot chunk download.
141
+ *
142
+ * When implemented, clients can decode and apply large bootstrap chunks
143
+ * incrementally without materializing the entire chunk in memory.
144
+ */
145
+ fetchSnapshotChunkStream?(
146
+ request: { chunkId: string },
147
+ options?: SyncTransportOptions
148
+ ): Promise<ReadableStream<Uint8Array>>;
149
+
139
150
  /**
140
151
  * Optional blob operations.
141
152
  * When present, enables blob upload/download functionality.