@syncular/core 0.0.1-123 → 0.0.1-125

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.
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/core",
3
- "version": "0.0.1-123",
3
+ "version": "0.0.1-125",
4
4
  "description": "Core protocol types and shared utilities for the Syncular sync framework",
5
5
  "license": "MIT",
6
6
  "author": "Benjamin Kniffler",
@@ -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);