@nebulr-group/bridge-auth-core 0.1.2 → 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/bridge-subscription.d.ts +71 -0
- package/dist/billing/bridge-subscription.d.ts.map +1 -0
- package/dist/billing/bridge-subscription.js +209 -0
- package/dist/billing/bridge-subscription.js.map +1 -0
- package/dist/billing/entitlements-store.d.ts +61 -0
- package/dist/billing/entitlements-store.d.ts.map +1 -0
- package/dist/billing/entitlements-store.js +127 -0
- package/dist/billing/entitlements-store.js.map +1 -0
- package/dist/billing/fetch-billing-state.d.ts +9 -0
- package/dist/billing/fetch-billing-state.d.ts.map +1 -0
- package/dist/billing/fetch-billing-state.js +22 -0
- package/dist/billing/fetch-billing-state.js.map +1 -0
- package/dist/billing/lock-signal.d.ts +6 -0
- package/dist/billing/lock-signal.d.ts.map +1 -0
- package/dist/billing/lock-signal.js +8 -0
- package/dist/billing/lock-signal.js.map +1 -0
- package/dist/billing/quota-store.d.ts +86 -0
- package/dist/billing/quota-store.d.ts.map +1 -0
- package/dist/billing/quota-store.js +180 -0
- package/dist/billing/quota-store.js.map +1 -0
- package/dist/billing/types.d.ts +64 -0
- package/dist/billing/types.d.ts.map +1 -0
- package/dist/billing/types.js +49 -0
- package/dist/billing/types.js.map +1 -0
- package/dist/billing/use-bridge.d.ts +131 -0
- package/dist/billing/use-bridge.d.ts.map +1 -0
- package/dist/billing/use-bridge.js +181 -0
- package/dist/billing/use-bridge.js.map +1 -0
- package/dist/bridge-auth.d.ts +39 -1
- package/dist/bridge-auth.d.ts.map +1 -1
- package/dist/bridge-auth.js +89 -6
- package/dist/bridge-auth.js.map +1 -1
- package/dist/direct-auth.d.ts +1 -0
- package/dist/direct-auth.d.ts.map +1 -1
- package/dist/direct-auth.js +7 -0
- package/dist/direct-auth.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -1
- package/dist/flags/attribute-providers.d.ts +229 -0
- package/dist/flags/attribute-providers.d.ts.map +1 -0
- package/dist/flags/attribute-providers.js +375 -0
- package/dist/flags/attribute-providers.js.map +1 -0
- package/dist/flags/dev-attribute-provider.d.ts +67 -0
- package/dist/flags/dev-attribute-provider.d.ts.map +1 -0
- package/dist/flags/dev-attribute-provider.js +200 -0
- package/dist/flags/dev-attribute-provider.js.map +1 -0
- package/dist/flags/evaluator.d.ts +58 -0
- package/dist/flags/evaluator.d.ts.map +1 -0
- package/dist/flags/evaluator.js +160 -0
- package/dist/flags/evaluator.js.map +1 -0
- package/dist/flags/flag.d.ts +199 -0
- package/dist/flags/flag.d.ts.map +1 -0
- package/dist/flags/flag.js +337 -0
- package/dist/flags/flag.js.map +1 -0
- package/dist/flags/identity.d.ts +77 -0
- package/dist/flags/identity.d.ts.map +1 -0
- package/dist/flags/identity.js +134 -0
- package/dist/flags/identity.js.map +1 -0
- package/dist/flags/index.d.ts +20 -0
- package/dist/flags/index.d.ts.map +1 -0
- package/dist/flags/index.js +21 -0
- package/dist/flags/index.js.map +1 -0
- package/dist/flags/operators.d.ts +63 -0
- package/dist/flags/operators.d.ts.map +1 -0
- package/dist/flags/operators.js +299 -0
- package/dist/flags/operators.js.map +1 -0
- package/dist/flags/propagation.d.ts +16 -0
- package/dist/flags/propagation.d.ts.map +1 -0
- package/dist/flags/propagation.js +107 -0
- package/dist/flags/propagation.js.map +1 -0
- package/dist/flags/realtime.d.ts +353 -0
- package/dist/flags/realtime.d.ts.map +1 -0
- package/dist/flags/realtime.js +779 -0
- package/dist/flags/realtime.js.map +1 -0
- package/dist/flags/runtime-mode.d.ts +32 -0
- package/dist/flags/runtime-mode.d.ts.map +1 -0
- package/dist/flags/runtime-mode.js +84 -0
- package/dist/flags/runtime-mode.js.map +1 -0
- package/dist/flags/telemetry.d.ts +79 -0
- package/dist/flags/telemetry.d.ts.map +1 -0
- package/dist/flags/telemetry.js +286 -0
- package/dist/flags/telemetry.js.map +1 -0
- package/dist/http.d.ts +4 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +44 -12
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/management-types.d.ts +38 -0
- package/dist/management-types.d.ts.map +1 -1
- package/dist/route-guard.d.ts.map +1 -1
- package/dist/route-guard.js +15 -5
- package/dist/route-guard.js.map +1 -1
- package/dist/token-manager.d.ts +3 -1
- package/dist/token-manager.d.ts.map +1 -1
- package/dist/token-manager.js +10 -6
- package/dist/token-manager.js.map +1 -1
- package/dist/types.d.ts +10 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/usage/index.d.ts +3 -0
- package/dist/usage/index.d.ts.map +1 -0
- package/dist/usage/index.js +4 -0
- package/dist/usage/index.js.map +1 -0
- package/dist/usage/storage/durable-storage.d.ts +47 -0
- package/dist/usage/storage/durable-storage.d.ts.map +1 -0
- package/dist/usage/storage/durable-storage.js +27 -0
- package/dist/usage/storage/durable-storage.js.map +1 -0
- package/dist/usage/storage/index.d.ts +7 -0
- package/dist/usage/storage/index.d.ts.map +1 -0
- package/dist/usage/storage/index.js +28 -0
- package/dist/usage/storage/index.js.map +1 -0
- package/dist/usage/storage/indexeddb-storage.d.ts +18 -0
- package/dist/usage/storage/indexeddb-storage.d.ts.map +1 -0
- package/dist/usage/storage/indexeddb-storage.js +159 -0
- package/dist/usage/storage/indexeddb-storage.js.map +1 -0
- package/dist/usage/storage/node-fs-storage.d.ts +29 -0
- package/dist/usage/storage/node-fs-storage.d.ts.map +1 -0
- package/dist/usage/storage/node-fs-storage.js +180 -0
- package/dist/usage/storage/node-fs-storage.js.map +1 -0
- package/dist/usage/storage/noop-storage.d.ts +17 -0
- package/dist/usage/storage/noop-storage.d.ts.map +1 -0
- package/dist/usage/storage/noop-storage.js +67 -0
- package/dist/usage/storage/noop-storage.js.map +1 -0
- package/dist/usage/usage-reporter.d.ts +64 -0
- package/dist/usage/usage-reporter.d.ts.map +1 -0
- package/dist/usage/usage-reporter.js +234 -0
- package/dist/usage/usage-reporter.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type AttributeGetter = () => unknown;
|
|
2
|
+
export type AttributeBulkGetter = () => Record<string, unknown> | undefined | null;
|
|
3
|
+
export interface SetOptions {
|
|
4
|
+
/**
|
|
5
|
+
* When false, this attribute's reads do NOT participate in
|
|
6
|
+
* `onAttributeObserved` telemetry. Default true.
|
|
7
|
+
*
|
|
8
|
+
* Useful for high-frequency keys (e.g. cursor position, scroll offset)
|
|
9
|
+
* where the dev needs the value in flag evals but doesn't need the
|
|
10
|
+
* telemetry overhead.
|
|
11
|
+
*/
|
|
12
|
+
observed?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Dev-managed AttributeProvider — the single backend for the `bridge.attributes`
|
|
16
|
+
* surface. One instance is created per SDK init and registered with the
|
|
17
|
+
* AttributeProviderRegistry. The order of registration determines whose
|
|
18
|
+
* keys win on collision via `collectSync` merge order (per-call attrs >
|
|
19
|
+
* setContext > providers — locked decision #20). Dev's provider is registered
|
|
20
|
+
* LAST so its keys beat the framework providers.
|
|
21
|
+
*/
|
|
22
|
+
export declare class DevAttributeProvider {
|
|
23
|
+
readonly name = "dev";
|
|
24
|
+
readonly namespace: 'custom';
|
|
25
|
+
private readonly _entries;
|
|
26
|
+
private readonly _bulkEntries;
|
|
27
|
+
private readonly _subscribers;
|
|
28
|
+
/** Static one-shot value. `opts.observed` defaults to true. */
|
|
29
|
+
set(key: string, value: unknown, opts?: SetOptions): void;
|
|
30
|
+
/** Live-bound: getter re-invoked on every flag eval. */
|
|
31
|
+
bind(key: string, getter: AttributeGetter, opts?: SetOptions): void;
|
|
32
|
+
/**
|
|
33
|
+
* Bulk getter returning `Record<string, unknown>`. Reserved keys inside
|
|
34
|
+
* the returned map are silently dropped (a `console.warn` fires once per
|
|
35
|
+
* reserved key per session to surface the typo).
|
|
36
|
+
*/
|
|
37
|
+
bindMany(getter: AttributeBulkGetter, opts?: SetOptions): void;
|
|
38
|
+
/** Remove a key (static or bound). Bulk getters are removed via `clearBulk()`. */
|
|
39
|
+
unset(key: string): void;
|
|
40
|
+
/** Remove every bulk getter. */
|
|
41
|
+
clearBulk(): void;
|
|
42
|
+
/** Remove every entry (test/teardown). */
|
|
43
|
+
clear(): void;
|
|
44
|
+
/**
|
|
45
|
+
* AttributeProvider contract — invoked synchronously on the FF 2.0 hot
|
|
46
|
+
* eval path. Returns the merged attribute map.
|
|
47
|
+
*
|
|
48
|
+
* Merge order within the dev provider: bulk getters first (so individual
|
|
49
|
+
* `set`/`bind` calls win over a bulk that happens to repeat a key).
|
|
50
|
+
* Getter exceptions are isolated — one throwing key doesn't break the rest.
|
|
51
|
+
*/
|
|
52
|
+
provide(): Record<string, unknown>;
|
|
53
|
+
/** Read-side convenience used by the public `bridge.attributes.get()`. */
|
|
54
|
+
get(): Record<string, unknown>;
|
|
55
|
+
/**
|
|
56
|
+
* Whether the key opts out of `onAttributeObserved` telemetry. Looked up
|
|
57
|
+
* by the framework SDK at observation time; bulk-supplied keys default to
|
|
58
|
+
* the bulk entry's `observed` flag (or true).
|
|
59
|
+
*/
|
|
60
|
+
isObserved(key: string): boolean;
|
|
61
|
+
/** Svelte store contract — subscribe to attribute-map snapshots. */
|
|
62
|
+
subscribe(fn: (map: Record<string, unknown>) => void): () => void;
|
|
63
|
+
private _notify;
|
|
64
|
+
}
|
|
65
|
+
/** Exposed for tests in other packages that want to validate the reserved set. */
|
|
66
|
+
export declare const __TEST_RESERVED_PREFIXES: readonly string[];
|
|
67
|
+
//# sourceMappingURL=dev-attribute-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-attribute-provider.d.ts","sourceRoot":"","sources":["../../src/flags/dev-attribute-provider.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC;AAC5C,MAAM,MAAM,mBAAmB,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;AAEnF,MAAM,WAAW,UAAU;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA4BD;;;;;;;GAOG;AACH,qBAAa,oBAAoB;IAC/B,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAY;IAIxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IAGjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAElF,+DAA+D;IAC/D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI;IAczD,wDAAwD;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI;IAcnE;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI;IAS9D,kFAAkF;IAClF,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,gCAAgC;IAChC,SAAS,IAAI,IAAI;IAMjB,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAMb;;;;;;;OAOG;IACH,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA6BlC,0EAA0E;IAC1E,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI9B;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAWhC,oEAAoE;IACpE,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAYjE,OAAO,CAAC,OAAO;CAgBhB;AAED,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAAsB,CAAC"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// Phase 5 (TBP-288/328/329/330) — dev-managed AttributeProvider.
|
|
2
|
+
//
|
|
3
|
+
// Backs the `bridge.attributes` surface in framework SDKs (bridge-svelte etc.).
|
|
4
|
+
// Three contribution modes — all coexist in one provider instance:
|
|
5
|
+
//
|
|
6
|
+
// set(key, value) → static one-shot value
|
|
7
|
+
// bind(key, getter) → live; getter is called on every flag eval
|
|
8
|
+
// bindMany(getter) → bulk; getter returns Record<string, unknown>
|
|
9
|
+
//
|
|
10
|
+
// Reserved namespace: keys starting with `bridge:` (and the legacy aliases
|
|
11
|
+
// `app:`, `tenant:`, `user:` reserved for bridge-managed attribute scopes)
|
|
12
|
+
// are REJECTED at write time with a clear console.warn — they don't end up
|
|
13
|
+
// in the provider map. Reads via get() return only the dev-contributed keys.
|
|
14
|
+
const RESERVED_PREFIXES = ['bridge:'];
|
|
15
|
+
function isReserved(key) {
|
|
16
|
+
for (const p of RESERVED_PREFIXES) {
|
|
17
|
+
if (key.startsWith(p))
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function warnReserved(key, context) {
|
|
23
|
+
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
|
24
|
+
// eslint-disable-next-line no-console
|
|
25
|
+
console.warn(`[bridge.attributes.${context}] key "${key}" is in the reserved \`bridge:\` namespace — write rejected. ` +
|
|
26
|
+
`Use a custom prefix (e.g. \`app.${key.split(':')[1] ?? key}\`) instead.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Dev-managed AttributeProvider — the single backend for the `bridge.attributes`
|
|
31
|
+
* surface. One instance is created per SDK init and registered with the
|
|
32
|
+
* AttributeProviderRegistry. The order of registration determines whose
|
|
33
|
+
* keys win on collision via `collectSync` merge order (per-call attrs >
|
|
34
|
+
* setContext > providers — locked decision #20). Dev's provider is registered
|
|
35
|
+
* LAST so its keys beat the framework providers.
|
|
36
|
+
*/
|
|
37
|
+
export class DevAttributeProvider {
|
|
38
|
+
name = 'dev';
|
|
39
|
+
namespace = 'custom';
|
|
40
|
+
// Single map keyed by attribute key for `static` + `bound` entries.
|
|
41
|
+
// Bulk entries are kept in a parallel list (no single key).
|
|
42
|
+
_entries = new Map();
|
|
43
|
+
_bulkEntries = [];
|
|
44
|
+
// Subscriptions for the Svelte store contract (TBP-328 AC: "subscribable").
|
|
45
|
+
_subscribers = new Set();
|
|
46
|
+
/** Static one-shot value. `opts.observed` defaults to true. */
|
|
47
|
+
set(key, value, opts) {
|
|
48
|
+
if (isReserved(key)) {
|
|
49
|
+
warnReserved(key, 'set');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this._entries.set(key, {
|
|
53
|
+
kind: 'static',
|
|
54
|
+
key,
|
|
55
|
+
value,
|
|
56
|
+
observed: opts?.observed ?? true,
|
|
57
|
+
});
|
|
58
|
+
this._notify();
|
|
59
|
+
}
|
|
60
|
+
/** Live-bound: getter re-invoked on every flag eval. */
|
|
61
|
+
bind(key, getter, opts) {
|
|
62
|
+
if (isReserved(key)) {
|
|
63
|
+
warnReserved(key, 'bind');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this._entries.set(key, {
|
|
67
|
+
kind: 'bound',
|
|
68
|
+
key,
|
|
69
|
+
getter,
|
|
70
|
+
observed: opts?.observed ?? true,
|
|
71
|
+
});
|
|
72
|
+
this._notify();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Bulk getter returning `Record<string, unknown>`. Reserved keys inside
|
|
76
|
+
* the returned map are silently dropped (a `console.warn` fires once per
|
|
77
|
+
* reserved key per session to surface the typo).
|
|
78
|
+
*/
|
|
79
|
+
bindMany(getter, opts) {
|
|
80
|
+
this._bulkEntries.push({
|
|
81
|
+
kind: 'bulk',
|
|
82
|
+
bulkGetter: getter,
|
|
83
|
+
observed: opts?.observed ?? true,
|
|
84
|
+
});
|
|
85
|
+
this._notify();
|
|
86
|
+
}
|
|
87
|
+
/** Remove a key (static or bound). Bulk getters are removed via `clearBulk()`. */
|
|
88
|
+
unset(key) {
|
|
89
|
+
if (this._entries.delete(key))
|
|
90
|
+
this._notify();
|
|
91
|
+
}
|
|
92
|
+
/** Remove every bulk getter. */
|
|
93
|
+
clearBulk() {
|
|
94
|
+
if (this._bulkEntries.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
this._bulkEntries.length = 0;
|
|
97
|
+
this._notify();
|
|
98
|
+
}
|
|
99
|
+
/** Remove every entry (test/teardown). */
|
|
100
|
+
clear() {
|
|
101
|
+
this._entries.clear();
|
|
102
|
+
this._bulkEntries.length = 0;
|
|
103
|
+
this._notify();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* AttributeProvider contract — invoked synchronously on the FF 2.0 hot
|
|
107
|
+
* eval path. Returns the merged attribute map.
|
|
108
|
+
*
|
|
109
|
+
* Merge order within the dev provider: bulk getters first (so individual
|
|
110
|
+
* `set`/`bind` calls win over a bulk that happens to repeat a key).
|
|
111
|
+
* Getter exceptions are isolated — one throwing key doesn't break the rest.
|
|
112
|
+
*/
|
|
113
|
+
provide() {
|
|
114
|
+
const out = {};
|
|
115
|
+
for (const entry of this._bulkEntries) {
|
|
116
|
+
try {
|
|
117
|
+
const m = entry.bulkGetter();
|
|
118
|
+
if (m && typeof m === 'object') {
|
|
119
|
+
for (const [k, v] of Object.entries(m)) {
|
|
120
|
+
if (isReserved(k))
|
|
121
|
+
continue;
|
|
122
|
+
out[k] = v;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Skip a throwing bulk getter for this eval.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
for (const entry of this._entries.values()) {
|
|
131
|
+
try {
|
|
132
|
+
if (entry.kind === 'static') {
|
|
133
|
+
out[entry.key] = entry.value;
|
|
134
|
+
}
|
|
135
|
+
else if (entry.kind === 'bound') {
|
|
136
|
+
out[entry.key] = entry.getter();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Skip a throwing getter; other keys still flow through.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
/** Read-side convenience used by the public `bridge.attributes.get()`. */
|
|
146
|
+
get() {
|
|
147
|
+
return this.provide();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Whether the key opts out of `onAttributeObserved` telemetry. Looked up
|
|
151
|
+
* by the framework SDK at observation time; bulk-supplied keys default to
|
|
152
|
+
* the bulk entry's `observed` flag (or true).
|
|
153
|
+
*/
|
|
154
|
+
isObserved(key) {
|
|
155
|
+
const direct = this._entries.get(key);
|
|
156
|
+
if (direct)
|
|
157
|
+
return direct.observed;
|
|
158
|
+
// Bulk entries don't track per-key observation; use the most-recently
|
|
159
|
+
// added bulk entry's flag if any, else default true.
|
|
160
|
+
if (this._bulkEntries.length > 0) {
|
|
161
|
+
return this._bulkEntries[this._bulkEntries.length - 1].observed;
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
/** Svelte store contract — subscribe to attribute-map snapshots. */
|
|
166
|
+
subscribe(fn) {
|
|
167
|
+
this._subscribers.add(fn);
|
|
168
|
+
try {
|
|
169
|
+
fn(this.provide());
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// ignore subscriber errors
|
|
173
|
+
}
|
|
174
|
+
return () => {
|
|
175
|
+
this._subscribers.delete(fn);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
_notify() {
|
|
179
|
+
if (this._subscribers.size === 0)
|
|
180
|
+
return;
|
|
181
|
+
let snapshot;
|
|
182
|
+
try {
|
|
183
|
+
snapshot = this.provide();
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
for (const fn of this._subscribers) {
|
|
189
|
+
try {
|
|
190
|
+
fn(snapshot);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// ignore subscriber errors
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** Exposed for tests in other packages that want to validate the reserved set. */
|
|
199
|
+
export const __TEST_RESERVED_PREFIXES = RESERVED_PREFIXES;
|
|
200
|
+
//# sourceMappingURL=dev-attribute-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-attribute-provider.js","sourceRoot":"","sources":["../../src/flags/dev-attribute-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AttributeType, Condition, Operator } from './operators.js';
|
|
2
|
+
/** A branch is a list of conditions (AND-ed) + the value returned on match. */
|
|
3
|
+
export interface Branch {
|
|
4
|
+
conditions: Condition[];
|
|
5
|
+
returnValue: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface Rule {
|
|
8
|
+
/** First-match-wins. */
|
|
9
|
+
branches: Branch[];
|
|
10
|
+
/** Returned when no branch matches. */
|
|
11
|
+
otherwiseValue: unknown;
|
|
12
|
+
/** 0-100. Applies to the whole rule. */
|
|
13
|
+
rolloutPct: number;
|
|
14
|
+
/** When set, the flag uses a saved group's branches; `branches` is ignored. */
|
|
15
|
+
groupRef?: string;
|
|
16
|
+
}
|
|
17
|
+
export type FlagState = 'off' | 'on' | 'on-with-rule';
|
|
18
|
+
export interface EvalContext {
|
|
19
|
+
/** Stable per-eval identity. Required when rolloutPct < 100. */
|
|
20
|
+
identity?: string;
|
|
21
|
+
/** Flat or nested attribute map. */
|
|
22
|
+
attributes: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface EvalResult {
|
|
25
|
+
value: unknown;
|
|
26
|
+
/** Which branch fired, 0-indexed. -1 if otherwise was returned. */
|
|
27
|
+
variantIndex: number;
|
|
28
|
+
matched: boolean;
|
|
29
|
+
excludedByRollout: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve a dotted-path attribute name against the eval context.
|
|
33
|
+
* Tries the flat key first, then walks dots.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveAttribute(ctx: EvalContext, attribute: string): unknown;
|
|
36
|
+
/**
|
|
37
|
+
* 32-bit FNV-1a hash of `${flagKey}|${identity}` mod 100. Same bucket for same
|
|
38
|
+
* inputs across server and SDK. Used for rule-level rollout and (future)
|
|
39
|
+
* variant assignment in L: Experiments.
|
|
40
|
+
*/
|
|
41
|
+
export declare function bucket(flagKey: string, identity: string): number;
|
|
42
|
+
/** Evaluate a single branch's conditions against the context. AND between conditions. */
|
|
43
|
+
export declare function evaluateBranch(branch: Branch, ctx: EvalContext): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Evaluate a Rule (branches + otherwise + rollout). First-match-wins; rollout
|
|
46
|
+
* applies to the whole rule (excluded users fall through to otherwise).
|
|
47
|
+
*/
|
|
48
|
+
export declare function evaluateRule(rule: Rule, flagKey: string, ctx: EvalContext): EvalResult;
|
|
49
|
+
export interface RuleValidationError {
|
|
50
|
+
branchIndex: number;
|
|
51
|
+
conditionIndex: number;
|
|
52
|
+
attribute?: string;
|
|
53
|
+
operator?: string;
|
|
54
|
+
message: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function validateRule(rule: Rule, attributeTypes?: Readonly<Record<string, AttributeType>>): RuleValidationError[];
|
|
57
|
+
export type { Operator, AttributeType, Condition };
|
|
58
|
+
//# sourceMappingURL=evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/flags/evaluator.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AASzE,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,uCAAuC;IACvC,cAAc,EAAE,OAAO,CAAC;IACxB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,cAAc,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAY7E;AAID;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQhE;AAID,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAGxE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,UAAU,CAwBtF;AAWD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,cAAc,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAM,GAC3D,mBAAmB,EAAE,CAsEvB;AAGD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Bridge Feature Flags 2.0 rule evaluator.
|
|
2
|
+
//
|
|
3
|
+
// This module is the SINGLE SOURCE OF TRUTH for both:
|
|
4
|
+
// - bridge-api server-side eval
|
|
5
|
+
// - bridge-* SDK client-side eval
|
|
6
|
+
//
|
|
7
|
+
// Imports `evaluateCondition` from the operator module in the same package
|
|
8
|
+
// (./operators.js). Server-side bridge-api imports from
|
|
9
|
+
// `@nebulr-group/bridge-auth-core` and gets identical semantics.
|
|
10
|
+
//
|
|
11
|
+
// Companion module: ./operators.ts (operator set + per-condition eval +
|
|
12
|
+
// save-time validation). This file builds the rule layer (branches + rollout)
|
|
13
|
+
// on top of those primitives.
|
|
14
|
+
import { evaluateCondition } from './operators.js';
|
|
15
|
+
import { isOperator, isOperatorValidForType, validOperatorsForType, } from './operators.js';
|
|
16
|
+
// ── Attribute resolution ────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a dotted-path attribute name against the eval context.
|
|
19
|
+
* Tries the flat key first, then walks dots.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveAttribute(ctx, attribute) {
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(ctx.attributes, attribute)) {
|
|
23
|
+
return ctx.attributes[attribute];
|
|
24
|
+
}
|
|
25
|
+
const parts = attribute.split('.');
|
|
26
|
+
let current = ctx.attributes;
|
|
27
|
+
for (const part of parts) {
|
|
28
|
+
if (current === undefined || current === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (typeof current !== 'object')
|
|
31
|
+
return undefined;
|
|
32
|
+
current = current[part];
|
|
33
|
+
}
|
|
34
|
+
return current;
|
|
35
|
+
}
|
|
36
|
+
// ── Stable hash bucketing ───────────────────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* 32-bit FNV-1a hash of `${flagKey}|${identity}` mod 100. Same bucket for same
|
|
39
|
+
* inputs across server and SDK. Used for rule-level rollout and (future)
|
|
40
|
+
* variant assignment in L: Experiments.
|
|
41
|
+
*/
|
|
42
|
+
export function bucket(flagKey, identity) {
|
|
43
|
+
const input = `${flagKey}|${identity}`;
|
|
44
|
+
let hash = 0x811c9dc5;
|
|
45
|
+
for (let i = 0; i < input.length; i++) {
|
|
46
|
+
hash ^= input.charCodeAt(i);
|
|
47
|
+
hash = (hash + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)) >>> 0;
|
|
48
|
+
}
|
|
49
|
+
return hash % 100;
|
|
50
|
+
}
|
|
51
|
+
// ── Branch + rule evaluation ────────────────────────────────────────────────
|
|
52
|
+
/** Evaluate a single branch's conditions against the context. AND between conditions. */
|
|
53
|
+
export function evaluateBranch(branch, ctx) {
|
|
54
|
+
if (!branch.conditions || branch.conditions.length === 0)
|
|
55
|
+
return false;
|
|
56
|
+
return branch.conditions.every((c) => evaluateCondition(c, resolveAttribute(ctx, c.attribute)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Evaluate a Rule (branches + otherwise + rollout). First-match-wins; rollout
|
|
60
|
+
* applies to the whole rule (excluded users fall through to otherwise).
|
|
61
|
+
*/
|
|
62
|
+
export function evaluateRule(rule, flagKey, ctx) {
|
|
63
|
+
const rolloutPct = clampPct(rule.rolloutPct ?? 100);
|
|
64
|
+
if (rolloutPct < 100) {
|
|
65
|
+
if (!ctx.identity) {
|
|
66
|
+
return { value: rule.otherwiseValue, variantIndex: -1, matched: false, excludedByRollout: true };
|
|
67
|
+
}
|
|
68
|
+
if (bucket(flagKey, ctx.identity) >= rolloutPct) {
|
|
69
|
+
return { value: rule.otherwiseValue, variantIndex: -1, matched: false, excludedByRollout: true };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const branches = rule.branches ?? [];
|
|
73
|
+
for (let i = 0; i < branches.length; i++) {
|
|
74
|
+
if (evaluateBranch(branches[i], ctx)) {
|
|
75
|
+
return {
|
|
76
|
+
value: branches[i].returnValue,
|
|
77
|
+
variantIndex: i,
|
|
78
|
+
matched: true,
|
|
79
|
+
excludedByRollout: false,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { value: rule.otherwiseValue, variantIndex: -1, matched: false, excludedByRollout: false };
|
|
84
|
+
}
|
|
85
|
+
function clampPct(p) {
|
|
86
|
+
if (!Number.isFinite(p))
|
|
87
|
+
return 100;
|
|
88
|
+
if (p < 0)
|
|
89
|
+
return 0;
|
|
90
|
+
if (p > 100)
|
|
91
|
+
return 100;
|
|
92
|
+
return p;
|
|
93
|
+
}
|
|
94
|
+
const RULE_CONDITIONS_HARD_MAX = 50;
|
|
95
|
+
export function validateRule(rule, attributeTypes = {}) {
|
|
96
|
+
const errors = [];
|
|
97
|
+
if (!rule || typeof rule !== 'object') {
|
|
98
|
+
return [{ branchIndex: -1, conditionIndex: -1, message: 'Rule must be an object.' }];
|
|
99
|
+
}
|
|
100
|
+
const branches = rule.branches ?? [];
|
|
101
|
+
let totalConditions = 0;
|
|
102
|
+
branches.forEach((branch, bi) => {
|
|
103
|
+
if (!branch.conditions || branch.conditions.length === 0) {
|
|
104
|
+
errors.push({
|
|
105
|
+
branchIndex: bi,
|
|
106
|
+
conditionIndex: -1,
|
|
107
|
+
message: `Branch ${bi} has no conditions.`,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
branch.conditions.forEach((c, ci) => {
|
|
112
|
+
totalConditions++;
|
|
113
|
+
if (!isOperator(c.operator)) {
|
|
114
|
+
errors.push({
|
|
115
|
+
branchIndex: bi,
|
|
116
|
+
conditionIndex: ci,
|
|
117
|
+
attribute: c.attribute,
|
|
118
|
+
operator: c.operator,
|
|
119
|
+
message: `Unknown operator "${c.operator}".`,
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const opType = attributeTypes[c.attribute];
|
|
124
|
+
if (opType && !isOperatorValidForType(c.operator, opType)) {
|
|
125
|
+
errors.push({
|
|
126
|
+
branchIndex: bi,
|
|
127
|
+
conditionIndex: ci,
|
|
128
|
+
attribute: c.attribute,
|
|
129
|
+
operator: c.operator,
|
|
130
|
+
message: `Operator "${c.operator}" not valid for type ${opType}. Valid: ${validOperatorsForType(opType).join(', ')}.`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
if (totalConditions > RULE_CONDITIONS_HARD_MAX) {
|
|
136
|
+
errors.push({
|
|
137
|
+
branchIndex: -1,
|
|
138
|
+
conditionIndex: -1,
|
|
139
|
+
message: `Rule has ${totalConditions} conditions; max is ${RULE_CONDITIONS_HARD_MAX}.`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (rule.rolloutPct !== undefined) {
|
|
143
|
+
if (typeof rule.rolloutPct !== 'number' || rule.rolloutPct < 0 || rule.rolloutPct > 100) {
|
|
144
|
+
errors.push({
|
|
145
|
+
branchIndex: -1,
|
|
146
|
+
conditionIndex: -1,
|
|
147
|
+
message: `rolloutPct must be a number in [0, 100], got ${rule.rolloutPct}.`,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (rule.groupRef && branches.length > 0) {
|
|
152
|
+
errors.push({
|
|
153
|
+
branchIndex: -1,
|
|
154
|
+
conditionIndex: -1,
|
|
155
|
+
message: 'Rule cannot have both an inline `branches` and a `groupRef`.',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return errors;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../src/flags/evaluator.ts"],"names":[],"mappings":"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"}
|