@featureflip/edge 0.0.0-stage → 2.14.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 (37) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +88 -2
  3. package/dist/edge-sdk/src/client.d.ts +35 -0
  4. package/dist/edge-sdk/src/client.d.ts.map +1 -0
  5. package/dist/edge-sdk/src/config.d.ts +42 -0
  6. package/dist/edge-sdk/src/config.d.ts.map +1 -0
  7. package/dist/edge-sdk/src/index.d.ts +7 -0
  8. package/dist/edge-sdk/src/index.d.ts.map +1 -0
  9. package/dist/edge-sdk/src/snapshot.d.ts +61 -0
  10. package/dist/edge-sdk/src/snapshot.d.ts.map +1 -0
  11. package/dist/edge-sdk/src/store.d.ts +21 -0
  12. package/dist/edge-sdk/src/store.d.ts.map +1 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.mjs +947 -0
  15. package/dist/js-sdk/src/core/evaluator.d.ts +37 -0
  16. package/dist/js-sdk/src/core/evaluator.d.ts.map +1 -0
  17. package/dist/js-sdk/src/core/events.d.ts +77 -0
  18. package/dist/js-sdk/src/core/events.d.ts.map +1 -0
  19. package/dist/js-sdk/src/core/identity.d.ts +13 -0
  20. package/dist/js-sdk/src/core/identity.d.ts.map +1 -0
  21. package/dist/js-sdk/src/core/resolve-detail.d.ts +42 -0
  22. package/dist/js-sdk/src/core/resolve-detail.d.ts.map +1 -0
  23. package/dist/js-sdk/src/core/shared-core.d.ts +170 -0
  24. package/dist/js-sdk/src/core/shared-core.d.ts.map +1 -0
  25. package/dist/js-sdk/src/core/store.d.ts +94 -0
  26. package/dist/js-sdk/src/core/store.d.ts.map +1 -0
  27. package/dist/js-sdk/src/core/types.d.ts +128 -0
  28. package/dist/js-sdk/src/core/types.d.ts.map +1 -0
  29. package/dist/js-sdk/src/core/unevaluable.d.ts +28 -0
  30. package/dist/js-sdk/src/core/unevaluable.d.ts.map +1 -0
  31. package/dist/js-sdk/src/core/validate-snapshot.d.ts +38 -0
  32. package/dist/js-sdk/src/core/validate-snapshot.d.ts.map +1 -0
  33. package/dist/js-sdk/src/platform/browser.d.ts +5 -0
  34. package/dist/js-sdk/src/platform/browser.d.ts.map +1 -0
  35. package/dist/js-sdk/src/platform/types.d.ts +31 -0
  36. package/dist/js-sdk/src/platform/types.d.ts.map +1 -0
  37. package/package.json +56 -4
package/dist/index.mjs ADDED
@@ -0,0 +1,947 @@
1
+ //#region ../js-sdk/src/core/events.ts
2
+ var e = 1e4, t = class extends Error {
3
+ status;
4
+ constructor(e) {
5
+ super(`Events endpoint responded ${e}.`), this.status = e, this.name = "EventSendError";
6
+ }
7
+ get retryable() {
8
+ return this.status >= 500 || this.status === 429;
9
+ }
10
+ };
11
+ function n(e) {
12
+ return e instanceof t ? e.retryable : !0;
13
+ }
14
+ function r(e) {
15
+ if (e.metadata === void 0) return e;
16
+ try {
17
+ return JSON.stringify(e.metadata), e;
18
+ } catch (t) {
19
+ return console.warn(`[featureflip] dropping non-serializable metadata on event "${e.flagKey}":`, t), {
20
+ ...e,
21
+ metadata: void 0
22
+ };
23
+ }
24
+ }
25
+ var i = class {
26
+ sender;
27
+ flushInterval;
28
+ options;
29
+ queue = [];
30
+ flushTimer = null;
31
+ closed = !1;
32
+ flushPromise = null;
33
+ flushBatchSize;
34
+ maxQueueSize;
35
+ nextAutoFlushAt = 0;
36
+ constructor(t, n, r, i = e, a = {}) {
37
+ this.sender = t, this.flushInterval = n, this.options = a, this.maxQueueSize = i >= 1 ? i : e, this.flushBatchSize = r >= 1 ? r : 1;
38
+ }
39
+ get size() {
40
+ return this.queue.length;
41
+ }
42
+ start() {
43
+ this.flushTimer ||= setInterval(() => {
44
+ this.flush();
45
+ }, this.flushInterval);
46
+ }
47
+ enqueue(e) {
48
+ this.closed || (this.queue.push(r(e)), this.trimToBound(), this.options.flushOnFullBatch !== !1 && this.queue.length >= this.flushBatchSize && Date.now() >= this.nextAutoFlushAt && this.flush());
49
+ }
50
+ async flush() {
51
+ if (this.queue.length === 0) return;
52
+ if (this.flushPromise) return this.flushPromise;
53
+ let e = this.options.maxBatchesPerFlush, t = e !== void 0 && e >= 1 ? e : Infinity;
54
+ return this.flushPromise = (async () => {
55
+ for (let e = 0; this.queue.length > 0 && e < t; e++) {
56
+ let e = this.queue.splice(0, this.flushBatchSize);
57
+ try {
58
+ await this.sender.sendEvents({ events: e }), this.nextAutoFlushAt = 0;
59
+ } catch (t) {
60
+ if (n(t)) {
61
+ this.requeue(e), this.nextAutoFlushAt = Date.now() + this.flushInterval;
62
+ return;
63
+ }
64
+ console.warn(`[featureflip] dropping ${e.length} analytics event(s) the events endpoint rejected permanently:`, t);
65
+ }
66
+ }
67
+ })().finally(() => {
68
+ this.flushPromise = null;
69
+ }), this.flushPromise;
70
+ }
71
+ requeue(e) {
72
+ this.closed || e.length === 0 || (this.queue = e.concat(this.queue), this.trimToBound());
73
+ }
74
+ trimToBound() {
75
+ let e = this.queue.length - this.maxQueueSize;
76
+ e <= 0 || (this.queue.splice(0, e), console.warn(`[featureflip] event queue is full; dropped ${e} of the oldest analytics event(s)`));
77
+ }
78
+ async close() {
79
+ this.closed = !0, this.flushTimer &&= (clearInterval(this.flushTimer), null), await this.flush(), this.queue.length = 0;
80
+ }
81
+ }, a = "featureflip-js/2.14.0", o = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+(\/[!#$%&'*+.^_`|~0-9A-Za-z-]+)?$/;
82
+ function s(e) {
83
+ let t = [a];
84
+ for (let n of e ?? []) typeof n == "string" && o.test(n) ? t.push(n) : console.warn(`[featureflip] ignoring wrapper ${JSON.stringify(n)}: not a valid "name/version" product token`);
85
+ return t.join(" ");
86
+ }
87
+ var c = -62135596800, l = 253402300799;
88
+ function u(e, t, n) {
89
+ let r = n(`${e}:${t}`);
90
+ return ((r[0] | r[1] << 8 | r[2] << 16 | r[3] << 24 >>> 0) >>> 0) % 100;
91
+ }
92
+ function d(e, t) {
93
+ let n = e[t];
94
+ if (n !== void 0) return n;
95
+ if (t === "userId") return e.user_id;
96
+ if (t === "user_id") return e.userId;
97
+ }
98
+ function f(e) {
99
+ return e.replace(/_/g, "").toLowerCase();
100
+ }
101
+ function ee(e, t, n) {
102
+ switch (e) {
103
+ case "equals": return n.some((e) => t === e);
104
+ case "notequals": return n.every((e) => t !== e);
105
+ case "contains": return n.some((e) => t.includes(e));
106
+ case "notcontains": return n.every((e) => !t.includes(e));
107
+ case "startswith": return n.some((e) => t.startsWith(e));
108
+ case "endswith": return n.some((e) => t.endsWith(e));
109
+ case "in": return n.includes(t);
110
+ case "notin": return !n.includes(t);
111
+ case "matchesregex": return n.some((e) => {
112
+ try {
113
+ return new RegExp(e).test(t);
114
+ } catch {
115
+ return !1;
116
+ }
117
+ });
118
+ case "greaterthan": return n.some((e) => p(t, e, ">"));
119
+ case "greaterthanorequal": return n.some((e) => p(t, e, ">="));
120
+ case "lessthan": return n.some((e) => p(t, e, "<"));
121
+ case "lessthanorequal": return n.some((e) => p(t, e, "<="));
122
+ case "before": return n.some((e) => g(t, e, "<"));
123
+ case "after": return n.some((e) => g(t, e, ">"));
124
+ case "semverequals": return n.some((e) => b(t, e, "="));
125
+ case "semvergreaterthan": return n.some((e) => b(t, e, ">"));
126
+ case "semvergreaterthanorequal": return n.some((e) => b(t, e, ">="));
127
+ case "semverlessthan": return n.some((e) => b(t, e, "<"));
128
+ case "semverlessthanorequal": return n.some((e) => b(t, e, "<="));
129
+ default: return null;
130
+ }
131
+ }
132
+ function p(e, t, n) {
133
+ let r = parseFloat(e), i = parseFloat(t);
134
+ if (isNaN(r) || isNaN(i)) return !1;
135
+ switch (n) {
136
+ case ">": return r > i;
137
+ case "<": return r < i;
138
+ case ">=": return r >= i;
139
+ case "<=": return r <= i;
140
+ }
141
+ }
142
+ var te = /^[\t\n\v\f\r ]+|[\t\n\v\f\r ]+$/g, ne = /[\u0000-\u001f\u007f-\u009f\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/, re = /^(\d{4}-\d{2}-\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2}))?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/, ie = [
143
+ 0,
144
+ 31,
145
+ 28,
146
+ 31,
147
+ 30,
148
+ 31,
149
+ 30,
150
+ 31,
151
+ 31,
152
+ 30,
153
+ 31,
154
+ 30,
155
+ 31
156
+ ];
157
+ function ae(e) {
158
+ let t = Number(e.slice(0, 4)), n = Number(e.slice(5, 7)), r = Number(e.slice(8, 10));
159
+ if (n < 1 || n > 12 || r < 1) return !1;
160
+ let i = +(n === 2 && t % 4 == 0 && (t % 100 != 0 || t % 400 == 0));
161
+ return r <= ie[n] + i;
162
+ }
163
+ function m(e) {
164
+ let t = re.exec(e);
165
+ if (t === null) return null;
166
+ let [, n, r, i, a, o, s] = t;
167
+ if (!ae(n)) return null;
168
+ if (r === void 0) return `${n}T00:00:00Z`;
169
+ if (r >= "24") return null;
170
+ let c = o ? `${o}000`.slice(0, 4) : "", l = s ?? "Z";
171
+ return l.length === 5 && (l = `${l.slice(0, 3)}:${l.slice(3)}`), `${n}T${r}:${i}:${a ?? "00"}${c}${l}`;
172
+ }
173
+ function h(e) {
174
+ let t = e.replace(te, "");
175
+ if (t.length === 0 || ne.test(t)) return null;
176
+ if (/^[+-]?\d+$/.test(t)) {
177
+ let e = Number(t);
178
+ return !Number.isFinite(e) || e < c || e > l ? null : e * 1e3;
179
+ }
180
+ let n = m(t);
181
+ if (n === null) return null;
182
+ let r = Date.parse(n);
183
+ if (Number.isNaN(r)) return null;
184
+ let i = Math.floor(r / 1e3);
185
+ return i < c || i > l ? null : r;
186
+ }
187
+ function g(e, t, n) {
188
+ let r = h(e), i = h(t);
189
+ return r === null || i === null ? !1 : n === ">" ? r > i : r < i;
190
+ }
191
+ function _(e) {
192
+ return e.length > 0 && /^[0-9]+$/.test(e);
193
+ }
194
+ function v(e) {
195
+ if (e === void 0) return null;
196
+ let t = e.trim();
197
+ if (t.length === 0) return null;
198
+ (t[0] === "v" || t[0] === "V") && (t = t.slice(1));
199
+ let n = t.indexOf("+");
200
+ n >= 0 && (t = t.slice(0, n));
201
+ let r, i, a = t.indexOf("-");
202
+ if (a >= 0) {
203
+ r = t.slice(0, a);
204
+ let e = t.slice(a + 1);
205
+ if (e.length === 0 || (i = e.split("."), i.some((e) => e.length === 0))) return null;
206
+ } else r = t, i = [];
207
+ if (r.length === 0) return null;
208
+ let o = r.split(".");
209
+ return o.some((e) => !_(e)) ? null : {
210
+ release: o,
211
+ prerelease: i
212
+ };
213
+ }
214
+ function y(e, t) {
215
+ return e = e.replace(/^0+/, ""), t = t.replace(/^0+/, ""), e.length === t.length ? e < t ? -1 : +(e > t) : e.length < t.length ? -1 : 1;
216
+ }
217
+ function oe(e, t) {
218
+ let n = _(e), r = _(t);
219
+ return n && r ? y(e, t) : n ? -1 : r ? 1 : e < t ? -1 : +(e > t);
220
+ }
221
+ function se(e, t) {
222
+ if (e.length === 0 && t.length === 0) return 0;
223
+ if (e.length === 0) return 1;
224
+ if (t.length === 0) return -1;
225
+ let n = Math.min(e.length, t.length);
226
+ for (let r = 0; r < n; r++) {
227
+ let n = oe(e[r], t[r]);
228
+ if (n !== 0) return n;
229
+ }
230
+ return e.length === t.length ? 0 : e.length < t.length ? -1 : 1;
231
+ }
232
+ function ce(e, t) {
233
+ let n = Math.max(e.release.length, t.release.length);
234
+ for (let r = 0; r < n; r++) {
235
+ let n = y(r < e.release.length ? e.release[r] : "0", r < t.release.length ? t.release[r] : "0");
236
+ if (n !== 0) return n;
237
+ }
238
+ return se(e.prerelease, t.prerelease);
239
+ }
240
+ function b(e, t, n) {
241
+ let r = v(e), i = v(t);
242
+ if (r === null || i === null) return !1;
243
+ let a = ce(r, i);
244
+ switch (n) {
245
+ case ">": return a > 0;
246
+ case "<": return a < 0;
247
+ case ">=": return a >= 0;
248
+ case "<=": return a <= 0;
249
+ case "=": return a === 0;
250
+ }
251
+ }
252
+ var le = /* @__PURE__ */ new Set([
253
+ "semverequals",
254
+ "semvergreaterthan",
255
+ "semvergreaterthanorequal",
256
+ "semverlessthan",
257
+ "semverlessthanorequal",
258
+ "matchesregex",
259
+ "before",
260
+ "after"
261
+ ]), ue = /* @__PURE__ */ new Set([
262
+ "equals",
263
+ "notequals",
264
+ "in",
265
+ "notin"
266
+ ]);
267
+ function de(e) {
268
+ if (e.trim() === "") return null;
269
+ let t = Number(e);
270
+ return Number.isFinite(t) ? t : null;
271
+ }
272
+ function x(e, t) {
273
+ let n = d(t, e.attribute);
274
+ if (n == null) return e.negate;
275
+ let r = f(e.operator);
276
+ if (typeof n == "number" && Number.isFinite(n) && ue.has(r)) {
277
+ let t = e.values.some((e) => {
278
+ let t = de(e);
279
+ return t !== null && t === n;
280
+ }), i = r === "equals" || r === "in" ? t : !t;
281
+ return e.negate ? !i : i;
282
+ }
283
+ let i = le.has(r), a = String(n), o = ee(r, i ? a : a.toLowerCase(), i ? e.values : e.values.map((e) => e.toLowerCase()));
284
+ return o === null ? !1 : e.negate ? !o : o;
285
+ }
286
+ function S(e, t, n) {
287
+ return e.length === 0 ? !0 : t === "And" ? e.every((e) => x(e, n)) : e.some((e) => x(e, n));
288
+ }
289
+ function fe(e, t) {
290
+ return e.length === 0 || e.every((e) => S(e.conditions, e.operator, t));
291
+ }
292
+ function C(e, t, n) {
293
+ if (e.type === "Fixed") return e.variation ?? "";
294
+ let r = e.bucketBy ?? "userId", i = d(t, r), a = i == null ? "" : String(i), o = e.variations ?? [];
295
+ if (o.length === 0) return e.variation ?? "";
296
+ if (a === "" && (r === "userId" || r === "user_id") && o.length > 0) return o[0].key;
297
+ let s = u(e.salt ?? "", a, n), c = 0;
298
+ for (let e of o) if (c += e.weight, s < c) return e.key;
299
+ return o[o.length - 1].key;
300
+ }
301
+ function w(e, t, n, r = {}) {
302
+ return E(e, t, n, r, 0, /* @__PURE__ */ new Map());
303
+ }
304
+ function T(e, t, n, r, i) {
305
+ return E(e, t, n, r, 0, i);
306
+ }
307
+ function E(e, t, n, r, i, a) {
308
+ if (i > 10) return {
309
+ value: e.variations.find((t) => t.key === e.offVariation)?.value ?? null,
310
+ variationKey: e.offVariation,
311
+ reason: "Error"
312
+ };
313
+ if (!e.enabled) return {
314
+ value: e.variations.find((t) => t.key === e.offVariation)?.value ?? null,
315
+ variationKey: e.offVariation,
316
+ reason: "FlagDisabled"
317
+ };
318
+ for (let o of e.prerequisites ?? []) {
319
+ let s = a.get(o.prerequisiteFlagKey);
320
+ if (!s) {
321
+ let c = r[o.prerequisiteFlagKey];
322
+ if (!c) {
323
+ let t = {
324
+ value: e.variations.find((t) => t.key === e.offVariation)?.value ?? null,
325
+ variationKey: e.offVariation,
326
+ reason: "PrerequisiteFailed",
327
+ prerequisiteKey: o.prerequisiteFlagKey
328
+ };
329
+ return a.set(e.key, t), t;
330
+ }
331
+ s = E(c, t, n, r, i + 1, a), a.set(o.prerequisiteFlagKey, s);
332
+ }
333
+ if (s.reason === "Error") {
334
+ let t = {
335
+ value: e.variations.find((t) => t.key === e.offVariation)?.value ?? null,
336
+ variationKey: e.offVariation,
337
+ reason: "Error"
338
+ };
339
+ return a.set(e.key, t), t;
340
+ }
341
+ if (s.variationKey !== o.expectedVariationKey) {
342
+ let t = {
343
+ value: e.variations.find((t) => t.key === e.offVariation)?.value ?? null,
344
+ variationKey: e.offVariation,
345
+ reason: "PrerequisiteFailed",
346
+ prerequisiteKey: o.prerequisiteFlagKey
347
+ };
348
+ return a.set(e.key, t), t;
349
+ }
350
+ }
351
+ let o = [...e.rules].sort((e, t) => e.priority - t.priority);
352
+ for (let r of o) {
353
+ let i;
354
+ if (r.segmentKey) {
355
+ if (n.getSegment) {
356
+ let e = n.getSegment(r.segmentKey);
357
+ i = e ? S(e.conditions, e.conditionLogic, t) : !1;
358
+ } else i = !1;
359
+ } else i = fe(r.conditionGroups, t);
360
+ if (i) {
361
+ let i = C(r.serve, t, n.md5), o = {
362
+ value: e.variations.find((e) => e.key === i)?.value ?? null,
363
+ variationKey: i,
364
+ reason: "RuleMatch",
365
+ ruleId: r.id
366
+ };
367
+ return a.set(e.key, o), o;
368
+ }
369
+ }
370
+ let s = C(e.fallthrough, t, n.md5), c = {
371
+ value: e.variations.find((e) => e.key === s)?.value ?? null,
372
+ variationKey: s,
373
+ reason: "Fallthrough"
374
+ };
375
+ return a.set(e.key, c), c;
376
+ }
377
+ //#endregion
378
+ //#region ../js-sdk/src/core/resolve-detail.ts
379
+ function D(e, t, n, r, i, a, o) {
380
+ if (!e) return {
381
+ value: n,
382
+ reason: "FlagNotFound"
383
+ };
384
+ try {
385
+ let s = typeof i == "function" ? i() : i, c = {
386
+ md5: (e) => r.md5(e),
387
+ getSegment: (e) => r.getSegment(e)
388
+ }, l = o ? T(e, t, c, s, o) : w(e, t, c, s), u = l.variationKey ? e.variations.find((e) => e.key === l.variationKey) : void 0, d = l.variationKey && !u ? "Error" : l.reason, f = l.value !== void 0 && l.value !== null ? l.value : n;
389
+ return a && typeof l.value !== a && (f = n, d = "Error"), {
390
+ value: f,
391
+ variationKey: l.variationKey,
392
+ reason: d,
393
+ ruleId: l.ruleId,
394
+ prerequisiteKey: l.prerequisiteKey
395
+ };
396
+ } catch (e) {
397
+ return r.onError?.(e), {
398
+ value: n,
399
+ reason: "Error"
400
+ };
401
+ }
402
+ }
403
+ //#endregion
404
+ //#region ../js-sdk/src/core/validate-snapshot.ts
405
+ var O = class extends Error {
406
+ constructor(e) {
407
+ super(e), this.name = "MalformedPayloadError";
408
+ }
409
+ };
410
+ function k(e) {
411
+ N(e?.flags, "flags"), N(e?.segments, "segments");
412
+ for (let t of e.flags) pe(t);
413
+ for (let t of e.segments) me(t);
414
+ }
415
+ function pe(e) {
416
+ if (P(e, "flag"), M(e.type, "flag.type"), A(e.fallthrough, "flag.fallthrough"), e.rules !== void 0 && e.rules !== null) {
417
+ N(e.rules, `flag[${e.key}].rules`);
418
+ for (let t of e.rules) if (A(t?.serve, `rule[${t?.id}].serve`), t?.conditionGroups !== void 0 && t.conditionGroups !== null) {
419
+ N(t.conditionGroups, `rule[${t.id}].conditionGroups`);
420
+ for (let e of t.conditionGroups) M(e?.operator, `rule[${t.id}].conditionGroup.operator`), j(e?.conditions, `rule[${t.id}].conditionGroup`);
421
+ }
422
+ }
423
+ }
424
+ function me(e) {
425
+ P(e, "segment"), M(e.conditionLogic, `segment[${e.key}].conditionLogic`), j(e.conditions, `segment[${e.key}]`);
426
+ }
427
+ function A(e, t) {
428
+ P(e, t), M(e.type, `${t}.type`);
429
+ }
430
+ function j(e, t) {
431
+ if (e != null) {
432
+ N(e, `${t}.conditions`);
433
+ for (let n of e) M(n?.operator, `${t}.condition.operator`);
434
+ }
435
+ }
436
+ function M(e, t) {
437
+ if (typeof e != "string") throw new O(`${t} must be a string, got ${F(e)}`);
438
+ }
439
+ function N(e, t) {
440
+ if (!Array.isArray(e)) throw new O(`${t} must be an array, got ${F(e)}`);
441
+ }
442
+ function P(e, t) {
443
+ if (typeof e != "object" || !e || Array.isArray(e)) throw new O(`${t} must be an object, got ${F(e)}`);
444
+ }
445
+ function F(e) {
446
+ return e === null ? "null" : Array.isArray(e) ? "array" : typeof e;
447
+ }
448
+ //#endregion
449
+ //#region ../js-sdk/src/core/unevaluable.ts
450
+ var I = /* @__PURE__ */ new Set(["Fixed", "Rollout"]), L = /* @__PURE__ */ new Set(["And", "Or"]);
451
+ function R(e) {
452
+ let t = z(e?.fallthrough, "fallthrough");
453
+ if (t) return t;
454
+ for (let t of e?.rules ?? []) {
455
+ let e = z(t?.serve, `rule[${t?.id}].serve`);
456
+ if (e) return e;
457
+ for (let e of t?.conditionGroups ?? []) if (e?.operator && !L.has(e.operator)) return `rule[${t?.id}].conditionGroup.operator "${e?.operator}" is not a condition logic this SDK version understands`;
458
+ }
459
+ return null;
460
+ }
461
+ function he(e) {
462
+ return e?.conditionLogic && !L.has(e.conditionLogic) ? `conditionLogic "${e?.conditionLogic}" is not a condition logic this SDK version understands` : null;
463
+ }
464
+ function z(e, t) {
465
+ return e?.type && !I.has(e.type) ? `${t}.type "${e?.type}" is not a serve type this SDK version understands` : null;
466
+ }
467
+ function ge(e) {
468
+ let t = [];
469
+ return {
470
+ flags: e.flags.filter((e) => {
471
+ let n = R(e);
472
+ return n && t.push({
473
+ kind: "flag",
474
+ key: e?.key,
475
+ reason: n
476
+ }), n === null;
477
+ }),
478
+ segments: e.segments.filter((e) => {
479
+ let n = he(e);
480
+ return n && t.push({
481
+ kind: "segment",
482
+ key: e?.key,
483
+ reason: n
484
+ }), n === null;
485
+ }),
486
+ dropped: t
487
+ };
488
+ }
489
+ //#endregion
490
+ //#region ../js-sdk/src/core/shared-core.ts
491
+ function _e(e) {
492
+ let t = e.user_id ?? e.userId;
493
+ return t == null ? void 0 : String(t);
494
+ }
495
+ //#endregion
496
+ //#region src/config.ts
497
+ var B = {
498
+ baseUrl: "https://eval.featureflip.io",
499
+ ttlSeconds: 60,
500
+ maxStaleSeconds: 86400,
501
+ loadTimeoutMs: 1e3,
502
+ flushBatchSize: 100
503
+ };
504
+ function ve(e) {
505
+ if (!e || typeof e.sdkKey != "string" || e.sdkKey === "") throw Error("[featureflip-edge] sdkKey is required");
506
+ return {
507
+ sdkKey: e.sdkKey,
508
+ baseUrl: (e.baseUrl ?? B.baseUrl).replace(/\/+$/, ""),
509
+ ttlSeconds: e.ttlSeconds ?? B.ttlSeconds,
510
+ maxStaleSeconds: e.maxStaleSeconds ?? B.maxStaleSeconds,
511
+ loadTimeoutMs: e.loadTimeoutMs ?? B.loadTimeoutMs,
512
+ store: e.store,
513
+ wrappers: e.wrappers ?? [],
514
+ flushBatchSize: e.flushBatchSize ?? B.flushBatchSize,
515
+ fetch: e.fetch ?? ((e, t) => fetch(e, t))
516
+ };
517
+ }
518
+ //#endregion
519
+ //#region ../js-sdk/src/platform/browser.ts
520
+ var V = [
521
+ 7,
522
+ 12,
523
+ 17,
524
+ 22,
525
+ 7,
526
+ 12,
527
+ 17,
528
+ 22,
529
+ 7,
530
+ 12,
531
+ 17,
532
+ 22,
533
+ 7,
534
+ 12,
535
+ 17,
536
+ 22,
537
+ 5,
538
+ 9,
539
+ 14,
540
+ 20,
541
+ 5,
542
+ 9,
543
+ 14,
544
+ 20,
545
+ 5,
546
+ 9,
547
+ 14,
548
+ 20,
549
+ 5,
550
+ 9,
551
+ 14,
552
+ 20,
553
+ 4,
554
+ 11,
555
+ 16,
556
+ 23,
557
+ 4,
558
+ 11,
559
+ 16,
560
+ 23,
561
+ 4,
562
+ 11,
563
+ 16,
564
+ 23,
565
+ 4,
566
+ 11,
567
+ 16,
568
+ 23,
569
+ 6,
570
+ 10,
571
+ 15,
572
+ 21,
573
+ 6,
574
+ 10,
575
+ 15,
576
+ 21,
577
+ 6,
578
+ 10,
579
+ 15,
580
+ 21,
581
+ 6,
582
+ 10,
583
+ 15,
584
+ 21
585
+ ], H = /* @__PURE__ */ new Uint32Array(64);
586
+ for (let e = 0; e < 64; e++) H[e] = Math.floor(2 ** 32 * Math.abs(Math.sin(e + 1))) >>> 0;
587
+ function ye(e) {
588
+ let t = new TextEncoder().encode(e), n = t.length * 8, r = (56 - (t.length + 1) % 64 + 64) % 64, i = new Uint8Array(t.length + 1 + r + 8);
589
+ i.set(t), i[t.length] = 128;
590
+ let a = new DataView(i.buffer);
591
+ a.setUint32(i.length - 8, n >>> 0, !0), a.setUint32(i.length - 4, 0, !0);
592
+ let o = 1732584193, s = 4023233417, c = 2562383102, l = 271733878;
593
+ for (let e = 0; e < i.length; e += 64) {
594
+ let t = /* @__PURE__ */ new Uint32Array(16);
595
+ for (let n = 0; n < 16; n++) t[n] = a.getUint32(e + n * 4, !0);
596
+ let n = o, r = s, i = c, u = l;
597
+ for (let e = 0; e < 64; e++) {
598
+ let a, o;
599
+ e < 16 ? (a = r & i | ~r & u, o = e) : e < 32 ? (a = u & r | ~u & i, o = (5 * e + 1) % 16) : e < 48 ? (a = r ^ i ^ u, o = (3 * e + 5) % 16) : (a = i ^ (r | ~u), o = 7 * e % 16), a = a + n + H[e] + t[o] >>> 0, n = u, u = i, i = r, r = r + (a << V[e] | a >>> 32 - V[e]) >>> 0;
600
+ }
601
+ o = o + n >>> 0, s = s + r >>> 0, c = c + i >>> 0, l = l + u >>> 0;
602
+ }
603
+ let u = /* @__PURE__ */ new Uint8Array(16), d = new DataView(u.buffer);
604
+ return d.setUint32(0, o, !0), d.setUint32(4, s, !0), d.setUint32(8, c, !0), d.setUint32(12, l, !0), u;
605
+ }
606
+ //#endregion
607
+ //#region src/snapshot.ts
608
+ var U = class e {
609
+ ready;
610
+ version;
611
+ flags;
612
+ flagList;
613
+ deps;
614
+ record;
615
+ constructor(e, t, n, r, i) {
616
+ let a = Object.create(null);
617
+ for (let t of e) a[t.key] = t;
618
+ let o = new Map(t.map((e) => [e.key, e]));
619
+ this.flags = a, this.flagList = e, this.version = n, this.ready = r, this.record = i, this.deps = {
620
+ md5: ye,
621
+ getSegment: (e) => o.get(e)
622
+ };
623
+ }
624
+ static fromResponse(t, n) {
625
+ k(t);
626
+ let { flags: r, segments: i, dropped: a } = ge(t);
627
+ for (let e of a) console.warn(`[featureflip-edge] dropping ${e.kind} "${e.key}": ${e.reason}. This SDK version may be older than the flag configuration; the rest of the configuration was applied.`);
628
+ return new e(r, i, t.version, !0, n);
629
+ }
630
+ static empty(t) {
631
+ return new e([], [], void 0, !1, t);
632
+ }
633
+ boolVariation(e, t, n) {
634
+ return this.evaluate(e, t, n, "boolean").value;
635
+ }
636
+ stringVariation(e, t, n) {
637
+ return this.evaluate(e, t, n, "string").value;
638
+ }
639
+ numberVariation(e, t, n) {
640
+ return this.evaluate(e, t, n, "number").value;
641
+ }
642
+ jsonVariation(e, t, n) {
643
+ return this.evaluate(e, t, n).value;
644
+ }
645
+ variationDetail(e, t, n) {
646
+ return this.evaluate(e, t, n);
647
+ }
648
+ bootstrapValues(e) {
649
+ let t = /* @__PURE__ */ new Map(), n = {};
650
+ for (let r of this.flagList) {
651
+ if (r.clientSideVisible !== !0) continue;
652
+ let i = D(r, e, null, this.depsFor(r.key), this.flags, void 0, t);
653
+ i.reason !== "Error" && Object.defineProperty(n, r.key, {
654
+ value: i.value,
655
+ enumerable: !0,
656
+ writable: !0,
657
+ configurable: !0
658
+ });
659
+ }
660
+ return n;
661
+ }
662
+ depsFor(e) {
663
+ return {
664
+ ...this.deps,
665
+ onError: (t) => console.warn(`[featureflip-edge] evaluation threw for "${e}":`, t)
666
+ };
667
+ }
668
+ evaluate(e, t, n, r) {
669
+ let i = D(this.flags[e], t, n, this.depsFor(e), this.flags, r);
670
+ try {
671
+ this.record(e, t, i);
672
+ } catch (t) {
673
+ console.warn(`[featureflip-edge] evaluation recorder threw for "${e}":`, t);
674
+ }
675
+ return i;
676
+ }
677
+ }, W = "x-featureflip-fetched-at", G = "[featureflip-edge]";
678
+ async function be(e, t) {
679
+ let n = new TextEncoder().encode(e + "\n" + t), r = await crypto.subtle.digest("SHA-256", n);
680
+ return `https://featureflip-edge.invalid/config/${Array.from(new Uint8Array(r), (e) => e.toString(16).padStart(2, "0")).join("")}`;
681
+ }
682
+ var K = !1, q = {
683
+ get: async () => void 0,
684
+ put: async () => {}
685
+ };
686
+ function xe(e, t) {
687
+ let n = t ?? globalThis.caches?.default;
688
+ return n ? {
689
+ async get() {
690
+ try {
691
+ let t = await n.match(e);
692
+ if (!t) return;
693
+ let r = Number(t.headers.get(W));
694
+ if (!t.headers.has("x-featureflip-fetched-at") || !Number.isFinite(r)) throw Error(`cache entry has a missing or invalid ${W} header`);
695
+ let i = await t.json();
696
+ return k(i), {
697
+ data: i,
698
+ fetchedAt: r
699
+ };
700
+ } catch (e) {
701
+ console.warn(`${G} ignoring unreadable cached config:`, e);
702
+ return;
703
+ }
704
+ },
705
+ async put(t, r) {
706
+ try {
707
+ await n.put(e, new Response(JSON.stringify(t.data), { headers: {
708
+ "content-type": "application/json",
709
+ "cache-control": `max-age=${Math.max(0, Math.floor(r))}`,
710
+ [W]: String(t.fetchedAt)
711
+ } }));
712
+ } catch (e) {
713
+ console.warn(`${G} failed to write config to the Cache API:`, e);
714
+ }
715
+ }
716
+ } : (K || (K = !0, console.warn(`${G} the Cache API is unavailable here; running memory-only (config is not shared between isolates).`)), q);
717
+ }
718
+ //#endregion
719
+ //#region src/client.ts
720
+ var J = "[featureflip-edge]", Y = 3e4, Se = 15e3, Ce = 1e4, X = 3e4, we = 5, Z = 3e4;
721
+ function Te(e) {
722
+ return new Ee(ve(e));
723
+ }
724
+ var Q = class extends Error {
725
+ status;
726
+ constructor(e) {
727
+ super(`SDK key rejected (${e})`), this.status = e, this.name = "KeyRejectedError";
728
+ }
729
+ }, Ee = class {
730
+ config;
731
+ memory;
732
+ storePromise;
733
+ inflight;
734
+ backoffUntil = 0;
735
+ warnedNoWaitUntil = !1;
736
+ lastSendAttemptAt = 0;
737
+ eventBackoffUntil = 0;
738
+ pendingSend;
739
+ eventFlush = Promise.resolve();
740
+ identity;
741
+ events;
742
+ record;
743
+ emptySnapshot;
744
+ constructor(e) {
745
+ this.config = e, this.identity = s(["featureflip-edge/2.14.0", ...e.wrappers]), this.events = new i({ sendEvents: (e) => this.sendEvents(e) }, X, e.flushBatchSize, void 0, {
746
+ flushOnFullBatch: !1,
747
+ maxBatchesPerFlush: we
748
+ }), this.record = (e, t, n) => {
749
+ this.events.enqueue({
750
+ type: "Evaluation",
751
+ flagKey: e,
752
+ userId: _e(t ?? {}),
753
+ variation: n.variationKey,
754
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
755
+ prerequisiteKey: n.prerequisiteKey
756
+ });
757
+ }, this.emptySnapshot = U.empty(this.record);
758
+ }
759
+ async load(e) {
760
+ !e && !this.warnedNoWaitUntil && (this.warnedNoWaitUntil = !0, console.warn(`${J} running without waitUntil; background refresh may be cut off. Pass the request ctx to load(), or await flush() before responding.`));
761
+ let t;
762
+ try {
763
+ t = await this.resolveSnapshot(e);
764
+ } catch (e) {
765
+ console.warn(`${J} load failed; serving the last good config or defaults:`, e), t = this.usableCopy()?.snapshot ?? this.emptySnapshot;
766
+ }
767
+ return e && this.scheduleFlush(e), t;
768
+ }
769
+ flush() {
770
+ return this.flushEvents(!1);
771
+ }
772
+ async flushEvents(e) {
773
+ try {
774
+ if (await this.abandonStalledSend(), this.events.size === 0) return;
775
+ let t = Date.now();
776
+ if (t < this.eventBackoffUntil || e && this.events.size < this.config.flushBatchSize && t - this.lastSendAttemptAt < Ce) return;
777
+ this.eventFlush = this.events.flush(), await this.eventFlush;
778
+ } catch (e) {
779
+ console.warn(`${J} event flush failed:`, e);
780
+ }
781
+ }
782
+ async abandonStalledSend() {
783
+ let e = this.pendingSend;
784
+ !e || Date.now() - e.startedAt <= Z || (e.abandon(), await this.eventFlush.catch(() => {}));
785
+ }
786
+ async resolveSnapshot(e) {
787
+ let t = this.usableCopy();
788
+ return t ||= (await this.promoteStoredCopy(), this.usableCopy()), t ? (Date.now() - t.fetchedAt > this.config.ttlSeconds * 1e3 && this.refresh(e), t.snapshot) : this.coldLoad(e);
789
+ }
790
+ usableCopy() {
791
+ let e = this.memory;
792
+ if (e) return Date.now() - e.fetchedAt <= this.config.maxStaleSeconds * 1e3 ? e : void 0;
793
+ }
794
+ async promoteStoredCopy() {
795
+ let e = await this.store();
796
+ if (!e) return;
797
+ let t;
798
+ try {
799
+ t = await e.get();
800
+ } catch (e) {
801
+ console.warn(`${J} config store read failed:`, e);
802
+ return;
803
+ }
804
+ if (t && !(Date.now() - t.fetchedAt > this.config.maxStaleSeconds * 1e3) && !(this.memory && this.memory.fetchedAt >= t.fetchedAt)) try {
805
+ let e = U.fromResponse(t.data, this.record);
806
+ this.memory = {
807
+ data: t.data,
808
+ fetchedAt: t.fetchedAt,
809
+ snapshot: e
810
+ };
811
+ } catch (e) {
812
+ console.warn(`${J} ignoring unusable stored config:`, e);
813
+ }
814
+ }
815
+ async coldLoad(e) {
816
+ let t = this.refresh(e);
817
+ if (!t || this.inBackoff()) return this.usableCopy()?.snapshot ?? this.emptySnapshot;
818
+ let n, r = new Promise((e) => {
819
+ n = e;
820
+ }), i = setTimeout(() => n(!0), this.config.loadTimeoutMs), a = await Promise.race([t.loaded.then(() => !1), r]);
821
+ return clearTimeout(i), a === !0 && (this.backOff(), t.timeoutWarned || (t.timeoutWarned = !0, console.warn(`${J} no config within ${this.config.loadTimeoutMs}ms; serving defaults while the fetch completes in the background.`))), this.usableCopy()?.snapshot ?? this.emptySnapshot;
822
+ }
823
+ inBackoff() {
824
+ return Date.now() < this.backoffUntil;
825
+ }
826
+ backOff() {
827
+ this.backoffUntil = Date.now() + Se;
828
+ }
829
+ refresh(e) {
830
+ let t = Date.now(), n = this.inflight;
831
+ if (n && t - n.startedAt > Y && (this.inflight = n = void 0, console.warn(`${J} config refresh failed:`, /* @__PURE__ */ Error(`GET /v1/sdk/flags did not settle within ${Y}ms; abandoned`)), this.backOff()), !n) {
832
+ if (this.inBackoff()) return;
833
+ n = this.startFetch(t), this.inflight = n;
834
+ }
835
+ return e && this.handOff(e, n.settled), n;
836
+ }
837
+ startFetch(e) {
838
+ let t = Promise.resolve(), n = {
839
+ startedAt: e,
840
+ loaded: Promise.resolve(),
841
+ settled: Promise.resolve(),
842
+ timeoutWarned: !1
843
+ };
844
+ n.loaded = (async () => {
845
+ try {
846
+ let n = await this.fetchConfig(), r = U.fromResponse(n, this.record), i = {
847
+ data: n,
848
+ fetchedAt: Date.now(),
849
+ snapshot: r
850
+ };
851
+ if (this.backoffUntil = 0, this.memory && this.memory.fetchedAt > e) return;
852
+ this.memory = i, t = this.persist(i);
853
+ } catch (e) {
854
+ if (this.inflight !== n) return;
855
+ this.backOff(), e instanceof Q ? console.warn(`${J} SDK key rejected (${e.status})`) : console.warn(`${J} config refresh failed:`, e);
856
+ }
857
+ })(), n.settled = n.loaded.then(() => t);
858
+ let r = () => {
859
+ this.inflight === n && (this.inflight = void 0);
860
+ };
861
+ return n.settled.then(r, r), n;
862
+ }
863
+ async fetchConfig() {
864
+ let e = this.config.fetch, t = await e(`${this.config.baseUrl}/v1/sdk/flags`, {
865
+ method: "GET",
866
+ headers: this.headers()
867
+ });
868
+ if (t.status === 401 || t.status === 403) throw $(t), new Q(t.status);
869
+ if (!t.ok) throw $(t), Error(`GET /v1/sdk/flags responded ${t.status}`);
870
+ return await t.json();
871
+ }
872
+ async persist(e) {
873
+ let t = await this.store();
874
+ if (t) try {
875
+ await t.put({
876
+ data: e.data,
877
+ fetchedAt: e.fetchedAt
878
+ }, this.config.maxStaleSeconds);
879
+ } catch (e) {
880
+ console.warn(`${J} config store write failed:`, e);
881
+ }
882
+ }
883
+ store() {
884
+ return this.storePromise ??= (async () => {
885
+ if (this.config.store) return this.config.store;
886
+ try {
887
+ return xe(await be(this.config.baseUrl, this.config.sdkKey));
888
+ } catch (e) {
889
+ console.warn(`${J} cannot derive the config cache key; running memory-only:`, e);
890
+ return;
891
+ }
892
+ })(), this.storePromise;
893
+ }
894
+ scheduleFlush(e) {
895
+ let t = new Promise((e) => setTimeout(e, 0)).then(() => this.flushEvents(!0));
896
+ this.handOff(e, t);
897
+ }
898
+ handOff(e, t) {
899
+ try {
900
+ e.waitUntil(t);
901
+ } catch (e) {
902
+ console.warn(`${J} ctx.waitUntil threw; background work may be cut off:`, e);
903
+ }
904
+ }
905
+ sendEvents(e) {
906
+ let n = Date.now();
907
+ return this.lastSendAttemptAt = n, new Promise((r, i) => {
908
+ let a = {
909
+ startedAt: n,
910
+ abandon: () => {
911
+ this.pendingSend === a && (this.pendingSend = void 0);
912
+ let t = /* @__PURE__ */ Error(`POST /v1/sdk/events did not settle within ${Z}ms; abandoned`);
913
+ console.warn(`${J} failed to send ${e.events.length} analytics event(s); they stay queued for the next flush:`, t), i(t);
914
+ }
915
+ };
916
+ this.pendingSend = a, this.postEvents(e).then(() => {
917
+ this.pendingSend === a && (this.pendingSend = void 0, r());
918
+ }, (n) => {
919
+ this.pendingSend === a && (this.pendingSend = void 0, (!(n instanceof t) || n.retryable) && (this.eventBackoffUntil = Date.now() + X, console.warn(`${J} failed to send ${e.events.length} analytics event(s); they stay queued and are retried in ${X / 1e3}s:`, n)), i(n));
920
+ });
921
+ });
922
+ }
923
+ async postEvents(e) {
924
+ let n = this.config.fetch, r = await n(`${this.config.baseUrl}/v1/sdk/events`, {
925
+ method: "POST",
926
+ headers: {
927
+ ...this.headers(),
928
+ "Content-Type": "application/json"
929
+ },
930
+ body: JSON.stringify(e)
931
+ });
932
+ if ($(r), !r.ok) throw new t(r.status);
933
+ }
934
+ headers() {
935
+ return {
936
+ Authorization: this.config.sdkKey,
937
+ "X-Featureflip-SDK": this.identity
938
+ };
939
+ }
940
+ };
941
+ function $(e) {
942
+ try {
943
+ e.body?.cancel().catch(() => {});
944
+ } catch {}
945
+ }
946
+ //#endregion
947
+ export { Te as createEdgeClient };