@nebulr-group/bridge-auth-core 0.1.2 → 0.4.0-beta.0

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 (131) hide show
  1. package/dist/billing/bridge-subscription.d.ts +71 -0
  2. package/dist/billing/bridge-subscription.d.ts.map +1 -0
  3. package/dist/billing/bridge-subscription.js +209 -0
  4. package/dist/billing/bridge-subscription.js.map +1 -0
  5. package/dist/billing/entitlements-store.d.ts +61 -0
  6. package/dist/billing/entitlements-store.d.ts.map +1 -0
  7. package/dist/billing/entitlements-store.js +127 -0
  8. package/dist/billing/entitlements-store.js.map +1 -0
  9. package/dist/billing/fetch-billing-state.d.ts +9 -0
  10. package/dist/billing/fetch-billing-state.d.ts.map +1 -0
  11. package/dist/billing/fetch-billing-state.js +22 -0
  12. package/dist/billing/fetch-billing-state.js.map +1 -0
  13. package/dist/billing/lock-signal.d.ts +6 -0
  14. package/dist/billing/lock-signal.d.ts.map +1 -0
  15. package/dist/billing/lock-signal.js +8 -0
  16. package/dist/billing/lock-signal.js.map +1 -0
  17. package/dist/billing/quota-store.d.ts +86 -0
  18. package/dist/billing/quota-store.d.ts.map +1 -0
  19. package/dist/billing/quota-store.js +180 -0
  20. package/dist/billing/quota-store.js.map +1 -0
  21. package/dist/billing/types.d.ts +64 -0
  22. package/dist/billing/types.d.ts.map +1 -0
  23. package/dist/billing/types.js +49 -0
  24. package/dist/billing/types.js.map +1 -0
  25. package/dist/billing/use-bridge.d.ts +131 -0
  26. package/dist/billing/use-bridge.d.ts.map +1 -0
  27. package/dist/billing/use-bridge.js +181 -0
  28. package/dist/billing/use-bridge.js.map +1 -0
  29. package/dist/bridge-auth.d.ts +36 -1
  30. package/dist/bridge-auth.d.ts.map +1 -1
  31. package/dist/bridge-auth.js +57 -3
  32. package/dist/bridge-auth.js.map +1 -1
  33. package/dist/direct-auth.d.ts +1 -0
  34. package/dist/direct-auth.d.ts.map +1 -1
  35. package/dist/direct-auth.js +7 -0
  36. package/dist/direct-auth.js.map +1 -1
  37. package/dist/errors.d.ts +11 -0
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/errors.js +14 -0
  40. package/dist/errors.js.map +1 -1
  41. package/dist/flags/attribute-providers.d.ts +229 -0
  42. package/dist/flags/attribute-providers.d.ts.map +1 -0
  43. package/dist/flags/attribute-providers.js +375 -0
  44. package/dist/flags/attribute-providers.js.map +1 -0
  45. package/dist/flags/dev-attribute-provider.d.ts +67 -0
  46. package/dist/flags/dev-attribute-provider.d.ts.map +1 -0
  47. package/dist/flags/dev-attribute-provider.js +200 -0
  48. package/dist/flags/dev-attribute-provider.js.map +1 -0
  49. package/dist/flags/evaluator.d.ts +58 -0
  50. package/dist/flags/evaluator.d.ts.map +1 -0
  51. package/dist/flags/evaluator.js +160 -0
  52. package/dist/flags/evaluator.js.map +1 -0
  53. package/dist/flags/flag.d.ts +199 -0
  54. package/dist/flags/flag.d.ts.map +1 -0
  55. package/dist/flags/flag.js +337 -0
  56. package/dist/flags/flag.js.map +1 -0
  57. package/dist/flags/identity.d.ts +77 -0
  58. package/dist/flags/identity.d.ts.map +1 -0
  59. package/dist/flags/identity.js +134 -0
  60. package/dist/flags/identity.js.map +1 -0
  61. package/dist/flags/index.d.ts +20 -0
  62. package/dist/flags/index.d.ts.map +1 -0
  63. package/dist/flags/index.js +21 -0
  64. package/dist/flags/index.js.map +1 -0
  65. package/dist/flags/operators.d.ts +63 -0
  66. package/dist/flags/operators.d.ts.map +1 -0
  67. package/dist/flags/operators.js +299 -0
  68. package/dist/flags/operators.js.map +1 -0
  69. package/dist/flags/propagation.d.ts +16 -0
  70. package/dist/flags/propagation.d.ts.map +1 -0
  71. package/dist/flags/propagation.js +107 -0
  72. package/dist/flags/propagation.js.map +1 -0
  73. package/dist/flags/realtime.d.ts +328 -0
  74. package/dist/flags/realtime.d.ts.map +1 -0
  75. package/dist/flags/realtime.js +504 -0
  76. package/dist/flags/realtime.js.map +1 -0
  77. package/dist/flags/runtime-mode.d.ts +32 -0
  78. package/dist/flags/runtime-mode.d.ts.map +1 -0
  79. package/dist/flags/runtime-mode.js +84 -0
  80. package/dist/flags/runtime-mode.js.map +1 -0
  81. package/dist/flags/telemetry.d.ts +79 -0
  82. package/dist/flags/telemetry.d.ts.map +1 -0
  83. package/dist/flags/telemetry.js +286 -0
  84. package/dist/flags/telemetry.js.map +1 -0
  85. package/dist/http.d.ts.map +1 -1
  86. package/dist/http.js +11 -1
  87. package/dist/http.js.map +1 -1
  88. package/dist/index.d.ts +14 -2
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +16 -1
  91. package/dist/index.js.map +1 -1
  92. package/dist/management-types.d.ts +38 -0
  93. package/dist/management-types.d.ts.map +1 -1
  94. package/dist/route-guard.d.ts.map +1 -1
  95. package/dist/route-guard.js +15 -5
  96. package/dist/route-guard.js.map +1 -1
  97. package/dist/token-manager.d.ts +3 -1
  98. package/dist/token-manager.d.ts.map +1 -1
  99. package/dist/token-manager.js +10 -6
  100. package/dist/token-manager.js.map +1 -1
  101. package/dist/types.d.ts +10 -2
  102. package/dist/types.d.ts.map +1 -1
  103. package/dist/usage/index.d.ts +3 -0
  104. package/dist/usage/index.d.ts.map +1 -0
  105. package/dist/usage/index.js +4 -0
  106. package/dist/usage/index.js.map +1 -0
  107. package/dist/usage/storage/durable-storage.d.ts +47 -0
  108. package/dist/usage/storage/durable-storage.d.ts.map +1 -0
  109. package/dist/usage/storage/durable-storage.js +27 -0
  110. package/dist/usage/storage/durable-storage.js.map +1 -0
  111. package/dist/usage/storage/index.d.ts +7 -0
  112. package/dist/usage/storage/index.d.ts.map +1 -0
  113. package/dist/usage/storage/index.js +28 -0
  114. package/dist/usage/storage/index.js.map +1 -0
  115. package/dist/usage/storage/indexeddb-storage.d.ts +18 -0
  116. package/dist/usage/storage/indexeddb-storage.d.ts.map +1 -0
  117. package/dist/usage/storage/indexeddb-storage.js +159 -0
  118. package/dist/usage/storage/indexeddb-storage.js.map +1 -0
  119. package/dist/usage/storage/node-fs-storage.d.ts +29 -0
  120. package/dist/usage/storage/node-fs-storage.d.ts.map +1 -0
  121. package/dist/usage/storage/node-fs-storage.js +180 -0
  122. package/dist/usage/storage/node-fs-storage.js.map +1 -0
  123. package/dist/usage/storage/noop-storage.d.ts +17 -0
  124. package/dist/usage/storage/noop-storage.d.ts.map +1 -0
  125. package/dist/usage/storage/noop-storage.js +67 -0
  126. package/dist/usage/storage/noop-storage.js.map +1 -0
  127. package/dist/usage/usage-reporter.d.ts +64 -0
  128. package/dist/usage/usage-reporter.d.ts.map +1 -0
  129. package/dist/usage/usage-reporter.js +234 -0
  130. package/dist/usage/usage-reporter.js.map +1 -0
  131. package/package.json +2 -1
@@ -0,0 +1,63 @@
1
+ export declare const OPERATORS: readonly ["eq", "neq", "contains", "not_contains", "in", "not_in", "gt", "lt", "between", "regex", "exists", "not_exists"];
2
+ export type Operator = (typeof OPERATORS)[number];
3
+ export declare const OPERATOR_VERSION: 1;
4
+ export type AttributeType = 'string' | 'number' | 'boolean' | 'date';
5
+ export declare function isOperator(value: unknown): value is Operator;
6
+ export declare function isOperatorValidForType(op: Operator, type: AttributeType): boolean;
7
+ export declare function validOperatorsForType(type: AttributeType): ReadonlyArray<Operator>;
8
+ export declare const CONDITIONS_PER_RULE_MAX = 50;
9
+ export type ConditionValue = string | number | boolean | null;
10
+ export interface Condition {
11
+ attribute: string;
12
+ operator: Operator;
13
+ values: ReadonlyArray<ConditionValue>;
14
+ }
15
+ /**
16
+ * Evaluate a single condition against an attribute value.
17
+ *
18
+ * @param condition The condition (attribute, operator, values) from the rule.
19
+ * @param attributeValue The value of the named attribute in the eval context.
20
+ * May be undefined / null if the SDK didn't supply it.
21
+ * @returns true if the condition matches; false otherwise.
22
+ *
23
+ * Operator semantics:
24
+ * eq attributeValue === values[0]
25
+ * neq attributeValue !== values[0]
26
+ * contains String(attributeValue).includes(String(values[0]))
27
+ * not_contains ! contains
28
+ * in values.includes(attributeValue)
29
+ * not_in ! in
30
+ * gt Number(attributeValue) > Number(values[0])
31
+ * lt Number(attributeValue) < Number(values[0])
32
+ * between Number(values[0]) <= Number(attributeValue) <= Number(values[1])
33
+ * (values[0] and values[1] are auto-swapped if out of order)
34
+ * regex new RegExp(String(values[0])).test(String(attributeValue))
35
+ * exists attributeValue !== undefined && attributeValue !== null
36
+ * not_exists ! exists
37
+ *
38
+ * Fail-safe rule: any malformed input (wrong number of values, non-numeric
39
+ * value for a numeric operator, invalid regex, oversized input) returns false
40
+ * rather than throwing. The server must still validate at save time; this
41
+ * function is intentionally lenient at runtime so a bad rule never crashes
42
+ * the consuming app.
43
+ */
44
+ export declare function evaluateCondition(condition: Condition, attributeValue: unknown): boolean;
45
+ export interface ValidationError {
46
+ /** Index of the condition within its containing branch (or -1 if global). */
47
+ conditionIndex: number;
48
+ attribute: string;
49
+ operator: Operator;
50
+ message: string;
51
+ }
52
+ /**
53
+ * Validate a list of conditions against a known attribute type map at save time.
54
+ *
55
+ * @param conditions The conditions to validate (e.g. a branch's `conditions`).
56
+ * @param attributeTypes Map of attribute key → known type. If an attribute is
57
+ * not in the map its type is treated as unknown and
58
+ * validation only checks operator membership in the
59
+ * locked set (not type compatibility).
60
+ * @returns list of validation errors; empty list means valid.
61
+ */
62
+ export declare function validateConditions(conditions: ReadonlyArray<Condition>, attributeTypes?: Readonly<Record<string, AttributeType>>): ValidationError[];
63
+ //# sourceMappingURL=operators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/flags/operators.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,SAAS,4HAaZ,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAarE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAEjF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,CAElF;AAqBD,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAI1C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;CACvC;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CA4FxF;AAID,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,EACpC,cAAc,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAM,GAC3D,eAAe,EAAE,CAwGnB"}
@@ -0,0 +1,299 @@
1
+ // The locked operator set for Bridge Feature Flags v1.
2
+ //
3
+ // This module is the SINGLE SOURCE OF TRUTH for both:
4
+ // - bridge-api server-side rule evaluation
5
+ // - bridge-* SDK client-side rule evaluation (via auth-core)
6
+ //
7
+ // Adding or removing an operator is a breaking change of the v1 contract.
8
+ // The `OPERATOR_VERSION` constant is forward-compat space — a stored rule
9
+ // carries the operator-set version it was authored against, so future
10
+ // expansions of the closed set can be migrated cleanly.
11
+ export const OPERATORS = [
12
+ 'eq',
13
+ 'neq',
14
+ 'contains',
15
+ 'not_contains',
16
+ 'in',
17
+ 'not_in',
18
+ 'gt',
19
+ 'lt',
20
+ 'between',
21
+ 'regex',
22
+ 'exists',
23
+ 'not_exists',
24
+ ];
25
+ export const OPERATOR_VERSION = 1;
26
+ // Which operators are valid for which attribute type. Used by:
27
+ // - Server-side save-time validation (reject mixed-type rules)
28
+ // - Admin UI operator picker (filter dropdown by attribute type)
29
+ // - SDK eval (defensive — should already be validated server-side)
30
+ const VALID_OPERATORS_BY_TYPE = {
31
+ string: ['eq', 'neq', 'contains', 'not_contains', 'in', 'not_in', 'regex', 'exists', 'not_exists'],
32
+ number: ['eq', 'neq', 'gt', 'lt', 'between', 'in', 'not_in', 'exists', 'not_exists'],
33
+ boolean: ['eq', 'neq', 'exists', 'not_exists'],
34
+ date: ['eq', 'neq', 'gt', 'lt', 'between', 'exists', 'not_exists'],
35
+ };
36
+ export function isOperator(value) {
37
+ return typeof value === 'string' && OPERATORS.includes(value);
38
+ }
39
+ export function isOperatorValidForType(op, type) {
40
+ return VALID_OPERATORS_BY_TYPE[type]?.includes(op) ?? false;
41
+ }
42
+ export function validOperatorsForType(type) {
43
+ return VALID_OPERATORS_BY_TYPE[type] ?? [];
44
+ }
45
+ // ── Safety limits ───────────────────────────────────────────────────────────
46
+ //
47
+ // Bounds on inputs that protect against denial-of-service or pathological
48
+ // rules. These are deliberately generous — they exist to draw a line, not to
49
+ // constrain reasonable use. Anything beyond these limits is treated as a
50
+ // non-match rather than evaluated (fail-safe).
51
+ // Cap regex input length to mitigate ReDoS on malicious patterns. Inputs
52
+ // longer than this are treated as non-matching rather than evaluated.
53
+ // Note: a real sandboxed regex engine (e.g. re2-wasm) is a future hardening
54
+ // step. v1 caps input + uses try/catch around the standard engine.
55
+ const REGEX_INPUT_MAX = 10_000;
56
+ // Hard cap on the number of items in `in` / `not_in` value arrays.
57
+ const IN_LIST_MAX = 1_000;
58
+ // Hard cap on the number of conditions allowed in a single rule (across
59
+ // all branches combined). Enforced at save time by the server, exposed here
60
+ // so the UI can surface the limit consistently.
61
+ export const CONDITIONS_PER_RULE_MAX = 50;
62
+ // ── Evaluation ──────────────────────────────────────────────────────────────
63
+ /**
64
+ * Evaluate a single condition against an attribute value.
65
+ *
66
+ * @param condition The condition (attribute, operator, values) from the rule.
67
+ * @param attributeValue The value of the named attribute in the eval context.
68
+ * May be undefined / null if the SDK didn't supply it.
69
+ * @returns true if the condition matches; false otherwise.
70
+ *
71
+ * Operator semantics:
72
+ * eq attributeValue === values[0]
73
+ * neq attributeValue !== values[0]
74
+ * contains String(attributeValue).includes(String(values[0]))
75
+ * not_contains ! contains
76
+ * in values.includes(attributeValue)
77
+ * not_in ! in
78
+ * gt Number(attributeValue) > Number(values[0])
79
+ * lt Number(attributeValue) < Number(values[0])
80
+ * between Number(values[0]) <= Number(attributeValue) <= Number(values[1])
81
+ * (values[0] and values[1] are auto-swapped if out of order)
82
+ * regex new RegExp(String(values[0])).test(String(attributeValue))
83
+ * exists attributeValue !== undefined && attributeValue !== null
84
+ * not_exists ! exists
85
+ *
86
+ * Fail-safe rule: any malformed input (wrong number of values, non-numeric
87
+ * value for a numeric operator, invalid regex, oversized input) returns false
88
+ * rather than throwing. The server must still validate at save time; this
89
+ * function is intentionally lenient at runtime so a bad rule never crashes
90
+ * the consuming app.
91
+ */
92
+ export function evaluateCondition(condition, attributeValue) {
93
+ const { operator, values } = condition;
94
+ // exists / not_exists handle missing values specially — short-circuit first
95
+ if (operator === 'exists') {
96
+ return attributeValue !== undefined && attributeValue !== null;
97
+ }
98
+ if (operator === 'not_exists') {
99
+ return attributeValue === undefined || attributeValue === null;
100
+ }
101
+ // For every other operator: a missing attribute is always a non-match
102
+ if (attributeValue === undefined || attributeValue === null) {
103
+ return false;
104
+ }
105
+ switch (operator) {
106
+ case 'eq':
107
+ return values.length > 0 && values[0] === attributeValue;
108
+ case 'neq':
109
+ return values.length > 0 && values[0] !== attributeValue;
110
+ case 'contains': {
111
+ if (values.length === 0)
112
+ return false;
113
+ return String(attributeValue).includes(String(values[0]));
114
+ }
115
+ case 'not_contains': {
116
+ if (values.length === 0)
117
+ return false;
118
+ return !String(attributeValue).includes(String(values[0]));
119
+ }
120
+ case 'in': {
121
+ if (values.length === 0 || values.length > IN_LIST_MAX)
122
+ return false;
123
+ return values.includes(attributeValue);
124
+ }
125
+ case 'not_in': {
126
+ // An empty `not_in` list is vacuously true (no values to exclude).
127
+ if (values.length > IN_LIST_MAX)
128
+ return false;
129
+ return !values.includes(attributeValue);
130
+ }
131
+ case 'gt': {
132
+ if (values.length === 0)
133
+ return false;
134
+ const n = Number(attributeValue);
135
+ const t = Number(values[0]);
136
+ if (Number.isNaN(n) || Number.isNaN(t))
137
+ return false;
138
+ return n > t;
139
+ }
140
+ case 'lt': {
141
+ if (values.length === 0)
142
+ return false;
143
+ const n = Number(attributeValue);
144
+ const t = Number(values[0]);
145
+ if (Number.isNaN(n) || Number.isNaN(t))
146
+ return false;
147
+ return n < t;
148
+ }
149
+ case 'between': {
150
+ if (values.length < 2)
151
+ return false;
152
+ const n = Number(attributeValue);
153
+ const a = Number(values[0]);
154
+ const b = Number(values[1]);
155
+ if (Number.isNaN(n) || Number.isNaN(a) || Number.isNaN(b))
156
+ return false;
157
+ const [lo, hi] = a <= b ? [a, b] : [b, a];
158
+ return n >= lo && n <= hi;
159
+ }
160
+ case 'regex': {
161
+ if (values.length === 0)
162
+ return false;
163
+ const input = String(attributeValue);
164
+ if (input.length > REGEX_INPUT_MAX)
165
+ return false;
166
+ try {
167
+ const re = new RegExp(String(values[0]));
168
+ return re.test(input);
169
+ }
170
+ catch {
171
+ // Invalid regex pattern — fail-safe: treat as non-match.
172
+ return false;
173
+ }
174
+ }
175
+ default: {
176
+ // Exhaustiveness check — `operator` is typed as Operator, so this
177
+ // branch should be unreachable. If it's hit, the rule was authored
178
+ // against a future operator set and we should fail-safe.
179
+ const _exhaustive = operator;
180
+ void _exhaustive;
181
+ return false;
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Validate a list of conditions against a known attribute type map at save time.
187
+ *
188
+ * @param conditions The conditions to validate (e.g. a branch's `conditions`).
189
+ * @param attributeTypes Map of attribute key → known type. If an attribute is
190
+ * not in the map its type is treated as unknown and
191
+ * validation only checks operator membership in the
192
+ * locked set (not type compatibility).
193
+ * @returns list of validation errors; empty list means valid.
194
+ */
195
+ export function validateConditions(conditions, attributeTypes = {}) {
196
+ const errors = [];
197
+ conditions.forEach((c, i) => {
198
+ if (!isOperator(c.operator)) {
199
+ errors.push({
200
+ conditionIndex: i,
201
+ attribute: c.attribute,
202
+ operator: c.operator,
203
+ message: `Unknown operator "${c.operator}". Valid operators: ${OPERATORS.join(', ')}.`,
204
+ });
205
+ return;
206
+ }
207
+ // Per-operator structural validation
208
+ switch (c.operator) {
209
+ case 'between':
210
+ if (c.values.length !== 2) {
211
+ errors.push({
212
+ conditionIndex: i,
213
+ attribute: c.attribute,
214
+ operator: c.operator,
215
+ message: `Operator "between" requires exactly 2 values, got ${c.values.length}.`,
216
+ });
217
+ }
218
+ break;
219
+ case 'in':
220
+ case 'not_in':
221
+ if (c.values.length === 0) {
222
+ errors.push({
223
+ conditionIndex: i,
224
+ attribute: c.attribute,
225
+ operator: c.operator,
226
+ message: `Operator "${c.operator}" requires at least 1 value.`,
227
+ });
228
+ }
229
+ else if (c.values.length > IN_LIST_MAX) {
230
+ errors.push({
231
+ conditionIndex: i,
232
+ attribute: c.attribute,
233
+ operator: c.operator,
234
+ message: `Operator "${c.operator}" supports at most ${IN_LIST_MAX} values, got ${c.values.length}.`,
235
+ });
236
+ }
237
+ break;
238
+ case 'exists':
239
+ case 'not_exists':
240
+ if (c.values.length !== 0) {
241
+ errors.push({
242
+ conditionIndex: i,
243
+ attribute: c.attribute,
244
+ operator: c.operator,
245
+ message: `Operator "${c.operator}" takes no values, got ${c.values.length}.`,
246
+ });
247
+ }
248
+ break;
249
+ case 'regex':
250
+ if (c.values.length !== 1) {
251
+ errors.push({
252
+ conditionIndex: i,
253
+ attribute: c.attribute,
254
+ operator: c.operator,
255
+ message: `Operator "regex" requires exactly 1 value, got ${c.values.length}.`,
256
+ });
257
+ }
258
+ else {
259
+ try {
260
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
261
+ const _ = new RegExp(String(c.values[0]));
262
+ }
263
+ catch (e) {
264
+ const msg = e instanceof Error ? e.message : String(e);
265
+ errors.push({
266
+ conditionIndex: i,
267
+ attribute: c.attribute,
268
+ operator: c.operator,
269
+ message: `Invalid regex pattern: ${msg}`,
270
+ });
271
+ }
272
+ }
273
+ break;
274
+ default:
275
+ // Most binary operators expect exactly 1 value
276
+ if (c.values.length !== 1) {
277
+ errors.push({
278
+ conditionIndex: i,
279
+ attribute: c.attribute,
280
+ operator: c.operator,
281
+ message: `Operator "${c.operator}" requires exactly 1 value, got ${c.values.length}.`,
282
+ });
283
+ }
284
+ break;
285
+ }
286
+ // Type-vs-operator compatibility (only when the attribute's type is known)
287
+ const type = attributeTypes[c.attribute];
288
+ if (type && !isOperatorValidForType(c.operator, type)) {
289
+ errors.push({
290
+ conditionIndex: i,
291
+ attribute: c.attribute,
292
+ operator: c.operator,
293
+ message: `Operator "${c.operator}" cannot be used with attribute "${c.attribute}" of type ${type}. Valid operators for ${type}: ${validOperatorsForType(type).join(', ')}.`,
294
+ });
295
+ }
296
+ });
297
+ return errors;
298
+ }
299
+ //# sourceMappingURL=operators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operators.js","sourceRoot":"","sources":["../../src/flags/operators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { EvalContext } from './evaluator.js';
2
+ /** Canonical HTTP header carrying the serialized eval context. */
3
+ export declare const BRIDGE_CONTEXT_HEADER: "x-bridge-context";
4
+ /** Serialize an eval context into a base64url-encoded JSON string. */
5
+ export declare function serializeContext(ctx: EvalContext): string;
6
+ /**
7
+ * Parse the header value back into an EvalContext. Returns `undefined` if the
8
+ * value is missing, malformed, or carries an unknown wire version. Callers
9
+ * should treat undefined as "no context shipped" — never throw on the request
10
+ * path.
11
+ */
12
+ export declare function deserializeContext(headerValue: string | undefined | null): EvalContext | undefined;
13
+ export declare function serverInstanceId(): string;
14
+ /** Test-only — reset the cached server-instance id. */
15
+ export declare function __resetServerInstanceId(): void;
16
+ //# sourceMappingURL=propagation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propagation.d.ts","sourceRoot":"","sources":["../../src/flags/propagation.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAOlD,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,EAAG,kBAA2B,CAAC;AAWjE,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAMzD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,WAAW,GAAG,SAAS,CAoBlG;AAcD,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
@@ -0,0 +1,107 @@
1
+ // Frontend → backend context propagation (TBP-171).
2
+ //
3
+ // The frontend SDK serializes the eval context into a header on outgoing
4
+ // HTTP requests; the backend SDK / NestJS guard / Express middleware reads
5
+ // the same header and rehydrates the context for backend evals. Same flag,
6
+ // same answer, on both ends of the wire.
7
+ //
8
+ // Header name + format are part of the SDK ↔ backend contract — don't
9
+ // change without a coordinated rollout.
10
+ import { generateAnonymousId } from './identity.js';
11
+ /** Canonical HTTP header carrying the serialized eval context. */
12
+ export const BRIDGE_CONTEXT_HEADER = 'x-bridge-context';
13
+ /** Wire format version — bump when the JSON shape changes incompatibly. */
14
+ const WIRE_VERSION = 1;
15
+ /** Serialize an eval context into a base64url-encoded JSON string. */
16
+ export function serializeContext(ctx) {
17
+ const wire = { v: WIRE_VERSION };
18
+ if (ctx.identity)
19
+ wire.i = ctx.identity;
20
+ // Omit empty attributes object — keep the wire small.
21
+ if (ctx.attributes && Object.keys(ctx.attributes).length > 0)
22
+ wire.a = ctx.attributes;
23
+ return base64UrlEncode(JSON.stringify(wire));
24
+ }
25
+ /**
26
+ * Parse the header value back into an EvalContext. Returns `undefined` if the
27
+ * value is missing, malformed, or carries an unknown wire version. Callers
28
+ * should treat undefined as "no context shipped" — never throw on the request
29
+ * path.
30
+ */
31
+ export function deserializeContext(headerValue) {
32
+ if (typeof headerValue !== 'string' || headerValue.length === 0)
33
+ return undefined;
34
+ let json;
35
+ try {
36
+ json = base64UrlDecode(headerValue);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(json);
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ if (!parsed || typeof parsed !== 'object')
49
+ return undefined;
50
+ if (parsed.v !== WIRE_VERSION)
51
+ return undefined;
52
+ return {
53
+ identity: typeof parsed.i === 'string' ? parsed.i : undefined,
54
+ attributes: parsed.a && typeof parsed.a === 'object' ? { ...parsed.a } : {},
55
+ };
56
+ }
57
+ /**
58
+ * Generate a stable per-process server-instance ID for backend SDKs that
59
+ * want to evaluate system-level flags (TBP-172). The first call mints a UUID
60
+ * v4; subsequent calls return the same value for the lifetime of the process.
61
+ *
62
+ * The ID is INTENTIONALLY ephemeral across restarts — system flags should
63
+ * target either a small set of stable identifiers (region, version, role) or
64
+ * a hash of those, not the auto-generated process ID. The process ID is
65
+ * primarily for telemetry / debugging where "which server replied to me"
66
+ * matters.
67
+ */
68
+ let _serverInstanceId;
69
+ export function serverInstanceId() {
70
+ if (!_serverInstanceId) {
71
+ _serverInstanceId = `srv_${generateAnonymousId().replace(/^anon_/, '')}`;
72
+ }
73
+ return _serverInstanceId;
74
+ }
75
+ /** Test-only — reset the cached server-instance id. */
76
+ export function __resetServerInstanceId() {
77
+ _serverInstanceId = undefined;
78
+ }
79
+ // ── base64url helpers (no dep on Buffer; works in browser + node) ───────────
80
+ function base64UrlEncode(input) {
81
+ // Use globalThis.btoa when available (browsers, modern Node), fall back to Buffer.
82
+ const g = globalThis;
83
+ let b64;
84
+ if (typeof g.btoa === 'function') {
85
+ // btoa handles binary strings — convert UTF-8 to binary string first
86
+ b64 = g.btoa(unescape(encodeURIComponent(input)));
87
+ }
88
+ else if (typeof Buffer !== 'undefined') {
89
+ b64 = Buffer.from(input, 'utf-8').toString('base64');
90
+ }
91
+ else {
92
+ throw new Error('No base64 encoder available');
93
+ }
94
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
95
+ }
96
+ function base64UrlDecode(input) {
97
+ const padded = input.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (input.length % 4)) % 4);
98
+ const g = globalThis;
99
+ if (typeof g.atob === 'function') {
100
+ return decodeURIComponent(escape(g.atob(padded)));
101
+ }
102
+ if (typeof Buffer !== 'undefined') {
103
+ return Buffer.from(padded, 'base64').toString('utf-8');
104
+ }
105
+ throw new Error('No base64 decoder available');
106
+ }
107
+ //# sourceMappingURL=propagation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/flags/propagation.ts"],"names":[],"mappings":"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"}