@blamejs/core 0.7.106 → 0.8.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 (51) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/NOTICE +17 -1
  3. package/README.md +4 -3
  4. package/index.js +16 -0
  5. package/lib/asyncapi-bindings.js +160 -0
  6. package/lib/asyncapi-traits.js +143 -0
  7. package/lib/asyncapi.js +531 -0
  8. package/lib/audit.js +6 -0
  9. package/lib/auth/acr-vocabulary.js +265 -0
  10. package/lib/auth/auth-time-tracker.js +111 -0
  11. package/lib/auth/elevation-grant.js +306 -0
  12. package/lib/auth/sd-jwt-vc-disclosure.js +95 -0
  13. package/lib/auth/sd-jwt-vc-holder.js +203 -0
  14. package/lib/auth/sd-jwt-vc-issuer.js +197 -0
  15. package/lib/auth/sd-jwt-vc.js +526 -0
  16. package/lib/auth/step-up-policy.js +335 -0
  17. package/lib/auth/step-up.js +445 -0
  18. package/lib/compliance-ai-act-logging.js +186 -0
  19. package/lib/compliance-ai-act-prohibited.js +205 -0
  20. package/lib/compliance-ai-act-risk.js +189 -0
  21. package/lib/compliance-ai-act-transparency.js +200 -0
  22. package/lib/compliance-ai-act.js +558 -0
  23. package/lib/compliance.js +2 -0
  24. package/lib/crypto.js +32 -0
  25. package/lib/flag-cache.js +136 -0
  26. package/lib/flag-evaluation-context.js +135 -0
  27. package/lib/flag-providers.js +279 -0
  28. package/lib/flag-targeting.js +210 -0
  29. package/lib/flag.js +284 -0
  30. package/lib/inbox.js +367 -0
  31. package/lib/mail-arc-sign.js +372 -0
  32. package/lib/mail-auth.js +2 -0
  33. package/lib/middleware/ai-act-disclosure.js +166 -0
  34. package/lib/middleware/asyncapi-serve.js +136 -0
  35. package/lib/middleware/flag-context.js +76 -0
  36. package/lib/middleware/index.js +15 -0
  37. package/lib/middleware/openapi-serve.js +143 -0
  38. package/lib/middleware/require-step-up.js +186 -0
  39. package/lib/openapi-paths-builder.js +248 -0
  40. package/lib/openapi-schema-walk.js +192 -0
  41. package/lib/openapi-security.js +169 -0
  42. package/lib/openapi-yaml.js +154 -0
  43. package/lib/openapi.js +443 -0
  44. package/lib/pqc-software.js +195 -0
  45. package/lib/vault/index.js +3 -0
  46. package/lib/vault-aad.js +259 -0
  47. package/lib/vendor/MANIFEST.json +29 -0
  48. package/lib/vendor/noble-post-quantum.cjs +18 -0
  49. package/lib/ws-client.js +829 -0
  50. package/package.json +1 -1
  51. package/sbom.cyclonedx.json +6 -6
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ /**
3
+ * Flag targeting — rule-based evaluation against an operator's
4
+ * evaluation-context object (subject id, role, region, custom
5
+ * attributes). Operators describe targeting in declarative JSON; the
6
+ * framework evaluates without expression-injection risk.
7
+ *
8
+ * Rule shape:
9
+ *
10
+ * { variant: "on", conditions: [
11
+ * { attribute: "user.role", op: "eq", value: "admin" },
12
+ * { attribute: "user.region", op: "in", value: ["EU", "UK"] },
13
+ * { attribute: "user.tier", op: "gte", value: 2 },
14
+ * ] }
15
+ *
16
+ * Operators are: eq / neq / in / nin / gt / gte / lt / lte / startsWith
17
+ * / endsWith / contains / regex / exists / not_exists / between.
18
+ *
19
+ * Evaluation is conjunctive across `conditions` (all must pass for
20
+ * the variant to apply). Multiple rules are evaluated in declaration
21
+ * order; first match wins. If no rule matches, the flag's default
22
+ * variant is returned.
23
+ *
24
+ * Per the validation-tier policy: rule-shape validation throws at
25
+ * boot (config-time entry-point); evaluation hot-path returns
26
+ * structured falsey on bad-shape rather than throwing.
27
+ */
28
+
29
+ var validateOpts = require("./validate-opts");
30
+ var { defineClass } = require("./framework-error");
31
+ var FlagError = defineClass("FlagError", { alwaysPermanent: true });
32
+
33
+ var VALID_OPS = [
34
+ "eq", "neq", "in", "nin", "gt", "gte", "lt", "lte",
35
+ "starts_with", "ends_with", "contains",
36
+ "regex", "exists", "not_exists", "between",
37
+ ];
38
+
39
+ function _readPath(ctx, attribute) {
40
+ if (typeof attribute !== "string" || attribute.length === 0) return undefined;
41
+ if (!ctx || typeof ctx !== "object") return undefined;
42
+ var parts = attribute.split(".");
43
+ var current = ctx;
44
+ for (var i = 0; i < parts.length; i += 1) {
45
+ if (current == null || typeof current !== "object") return undefined;
46
+ current = current[parts[i]];
47
+ }
48
+ return current;
49
+ }
50
+
51
+ function _evaluateCondition(condition, ctx) {
52
+ if (!condition || typeof condition !== "object") return false;
53
+ if (typeof condition.op !== "string") return false;
54
+ if (VALID_OPS.indexOf(condition.op) === -1) return false;
55
+
56
+ var presented = _readPath(ctx, condition.attribute);
57
+ switch (condition.op) {
58
+ case "eq": return presented === condition.value;
59
+ case "neq": return presented !== condition.value;
60
+ case "in": return Array.isArray(condition.value) &&
61
+ condition.value.indexOf(presented) !== -1;
62
+ case "nin": return Array.isArray(condition.value) &&
63
+ condition.value.indexOf(presented) === -1;
64
+ case "gt": return typeof presented === "number" &&
65
+ typeof condition.value === "number" &&
66
+ presented > condition.value;
67
+ case "gte": return typeof presented === "number" &&
68
+ typeof condition.value === "number" &&
69
+ presented >= condition.value;
70
+ case "lt": return typeof presented === "number" &&
71
+ typeof condition.value === "number" &&
72
+ presented < condition.value;
73
+ case "lte": return typeof presented === "number" &&
74
+ typeof condition.value === "number" &&
75
+ presented <= condition.value;
76
+ case "starts_with": return typeof presented === "string" &&
77
+ typeof condition.value === "string" &&
78
+ presented.indexOf(condition.value) === 0;
79
+ case "ends_with": return typeof presented === "string" &&
80
+ typeof condition.value === "string" &&
81
+ presented.length >= condition.value.length &&
82
+ presented.slice(-condition.value.length) === condition.value;
83
+ case "contains": return typeof presented === "string" &&
84
+ typeof condition.value === "string" &&
85
+ presented.indexOf(condition.value) !== -1;
86
+ case "regex":
87
+ // Regex bounded — operator-supplied regex compiled at rule-validate
88
+ // time and re-used here. Refuse to evaluate if regex isn't pre-
89
+ // compiled (defense against runtime regex compilation per call).
90
+ if (!(condition._compiledRegex instanceof RegExp)) return false;
91
+ return typeof presented === "string" &&
92
+ condition._compiledRegex.test(presented);
93
+ case "exists": return presented !== undefined;
94
+ case "not_exists": return presented === undefined;
95
+ case "between": return Array.isArray(condition.value) &&
96
+ condition.value.length === 2 &&
97
+ typeof presented === "number" &&
98
+ presented >= condition.value[0] &&
99
+ presented <= condition.value[1];
100
+ default: return false;
101
+ }
102
+ }
103
+
104
+ function evaluateRules(rules, ctx, defaultVariant) {
105
+ if (!Array.isArray(rules)) return { variant: defaultVariant, ruleIndex: -1, reason: "default" };
106
+ for (var i = 0; i < rules.length; i += 1) {
107
+ var rule = rules[i];
108
+ if (!rule || typeof rule !== "object") continue;
109
+ if (!Array.isArray(rule.conditions)) continue;
110
+ var allPass = true;
111
+ for (var j = 0; j < rule.conditions.length; j += 1) {
112
+ if (!_evaluateCondition(rule.conditions[j], ctx)) {
113
+ allPass = false; break;
114
+ }
115
+ }
116
+ if (allPass) {
117
+ return { variant: rule.variant, ruleIndex: i, reason: "targeting_match" };
118
+ }
119
+ }
120
+ return { variant: defaultVariant, ruleIndex: -1, reason: "default" };
121
+ }
122
+
123
+ function validateRules(rules, label) {
124
+ label = label || "rules";
125
+ if (rules == null) return [];
126
+ if (!Array.isArray(rules)) {
127
+ throw new FlagError("flag/bad-rules",
128
+ label + ": rules must be an array of rule objects");
129
+ }
130
+ var validated = [];
131
+ for (var i = 0; i < rules.length; i += 1) {
132
+ var rule = rules[i];
133
+ if (!rule || typeof rule !== "object") {
134
+ throw new FlagError("flag/bad-rule",
135
+ label + "[" + i + "]: rule must be an object");
136
+ }
137
+ validateOpts(rule, ["variant", "conditions", "weight"], label + "[" + i + "]");
138
+ validateOpts.requireNonEmptyString(rule.variant, label + "[" + i + "].variant",
139
+ FlagError, "flag/bad-rule");
140
+ if (!Array.isArray(rule.conditions)) {
141
+ throw new FlagError("flag/bad-rule",
142
+ label + "[" + i + "].conditions: must be an array");
143
+ }
144
+ var validatedConds = [];
145
+ for (var j = 0; j < rule.conditions.length; j += 1) {
146
+ var cond = rule.conditions[j];
147
+ var clabel = label + "[" + i + "].conditions[" + j + "]";
148
+ if (!cond || typeof cond !== "object") {
149
+ throw new FlagError("flag/bad-condition",
150
+ clabel + ": condition must be an object");
151
+ }
152
+ validateOpts(cond, ["attribute", "op", "value"], clabel);
153
+ validateOpts.requireNonEmptyString(cond.attribute, clabel + ".attribute",
154
+ FlagError, "flag/bad-condition");
155
+ if (VALID_OPS.indexOf(cond.op) === -1) {
156
+ throw new FlagError("flag/bad-condition",
157
+ clabel + ".op: must be one of " + VALID_OPS.join(", ") +
158
+ " - got " + JSON.stringify(cond.op));
159
+ }
160
+ var validatedCond = {
161
+ attribute: cond.attribute,
162
+ op: cond.op,
163
+ value: cond.value,
164
+ };
165
+ if (cond.op === "regex") {
166
+ if (typeof cond.value !== "string") {
167
+ throw new FlagError("flag/bad-condition",
168
+ clabel + ".value: regex op requires a string value");
169
+ }
170
+ if (cond.value.length > 200) {
171
+ throw new FlagError("flag/bad-condition",
172
+ clabel + ".value: regex pattern must be <= 200 chars (DoS defense)");
173
+ }
174
+ try {
175
+ // allow:dynamic-regex — operator-supplied targeting pattern, length-bounded to 200 chars above
176
+ validatedCond._compiledRegex = new RegExp(cond.value);
177
+ } catch (e) {
178
+ throw new FlagError("flag/bad-condition",
179
+ clabel + ".value: invalid regex - " + e.message);
180
+ }
181
+ }
182
+ if (cond.op === "between") {
183
+ if (!Array.isArray(cond.value) || cond.value.length !== 2 ||
184
+ typeof cond.value[0] !== "number" || typeof cond.value[1] !== "number") {
185
+ throw new FlagError("flag/bad-condition",
186
+ clabel + ".value: between op requires [number, number]");
187
+ }
188
+ }
189
+ if ((cond.op === "in" || cond.op === "nin") && !Array.isArray(cond.value)) {
190
+ throw new FlagError("flag/bad-condition",
191
+ clabel + ".value: " + cond.op + " op requires an array value");
192
+ }
193
+ validatedConds.push(validatedCond);
194
+ }
195
+ validated.push({
196
+ variant: rule.variant,
197
+ conditions: validatedConds,
198
+ weight: (typeof rule.weight === "number") ? rule.weight : null,
199
+ });
200
+ }
201
+ return validated;
202
+ }
203
+
204
+ module.exports = {
205
+ evaluateRules: evaluateRules,
206
+ validateRules: validateRules,
207
+ VALID_OPS: VALID_OPS,
208
+ _readPath: _readPath,
209
+ FlagError: FlagError,
210
+ };
package/lib/flag.js ADDED
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ /**
3
+ * b.flag — feature-flag client per the OpenFeature specification
4
+ * (https://openfeature.dev/specification/).
5
+ *
6
+ * var flag = b.flag.create({
7
+ * provider: b.flag.providers.localFile({ path: "./flags.json" }),
8
+ * defaultEvaluationContext: { environment: "production" },
9
+ * });
10
+ *
11
+ * var enabled = flag.getBoolean("new-checkout-flow", { targetingKey: req.user.id });
12
+ * var sample = flag.getString ("greeting-banner", { targetingKey: req.user.id }, "default-text");
13
+ * var rate = flag.getNumber ("upsell-rate", { targetingKey: req.user.id }, 0);
14
+ * var cfg = flag.getObject ("checkout-config", { targetingKey: req.user.id }, {});
15
+ *
16
+ * var details = flag.getDetails("new-checkout-flow", ctx);
17
+ * // → { value, variant, reason, metadata }
18
+ *
19
+ * flag.middleware() → request-time middleware that attaches a
20
+ * per-request `flag` accessor onto req.
21
+ *
22
+ * Per the validation-tier policy: create() throws on bad opts; the
23
+ * hot-path getValue / getBoolean / etc. NEVER throw — they return the
24
+ * operator-supplied default + emit `flag.evaluation.error` on the
25
+ * audit chain so the operator sees the problem without taking down
26
+ * the request.
27
+ */
28
+
29
+ var validateOpts = require("./validate-opts");
30
+ var lazyRequire = require("./lazy-require");
31
+ var providersMod = require("./flag-providers");
32
+ var contextMod = require("./flag-evaluation-context");
33
+ var targeting = require("./flag-targeting");
34
+ var cacheMod = require("./flag-cache");
35
+ var { defineClass } = require("./framework-error");
36
+ var FlagError = defineClass("FlagError", { alwaysPermanent: true });
37
+
38
+ var audit = lazyRequire(function () { return require("./audit"); });
39
+
40
+ function _validateHooks(rawHooks) {
41
+ var out = { before: [], after: [], error: [], finally: [] };
42
+ if (rawHooks == null) return out;
43
+ if (typeof rawHooks !== "object") {
44
+ throw new FlagError("flag/bad-hooks",
45
+ "create: hooks must be an object { before, after, error, finally }");
46
+ }
47
+ var stages = ["before", "after", "error", "finally"];
48
+ for (var i = 0; i < stages.length; i += 1) {
49
+ var stage = stages[i];
50
+ if (rawHooks[stage] == null) continue;
51
+ var arr = Array.isArray(rawHooks[stage]) ? rawHooks[stage] : [rawHooks[stage]];
52
+ for (var j = 0; j < arr.length; j += 1) {
53
+ if (typeof arr[j] !== "function") {
54
+ throw new FlagError("flag/bad-hooks",
55
+ "create: hooks." + stage + "[" + j + "] must be a function");
56
+ }
57
+ }
58
+ out[stage] = arr.slice();
59
+ }
60
+ return out;
61
+ }
62
+
63
+ function create(opts) {
64
+ opts = opts || {};
65
+ validateOpts(opts, [
66
+ "provider", "providers", "defaultEvaluationContext",
67
+ "audit", "errorHandler", "hooks",
68
+ ], "flag.create");
69
+ var providers = [];
70
+ if (opts.provider) {
71
+ if (typeof opts.provider.evaluate !== "function") {
72
+ throw new FlagError("flag/bad-provider",
73
+ "create: provider must implement .evaluate(flagKey, ctx)");
74
+ }
75
+ providers.push(opts.provider);
76
+ }
77
+ if (Array.isArray(opts.providers)) {
78
+ for (var i = 0; i < opts.providers.length; i += 1) {
79
+ if (typeof opts.providers[i].evaluate !== "function") {
80
+ throw new FlagError("flag/bad-provider",
81
+ "create: providers[" + i + "] must implement .evaluate()");
82
+ }
83
+ providers.push(opts.providers[i]);
84
+ }
85
+ }
86
+ if (providers.length === 0) {
87
+ throw new FlagError("flag/no-provider",
88
+ "create: at least one provider is required - pass `provider` or `providers`");
89
+ }
90
+ var defaultCtx = contextMod.create(opts.defaultEvaluationContext || {});
91
+ var auditOn = opts.audit !== false;
92
+ var errorHandler = (typeof opts.errorHandler === "function")
93
+ ? opts.errorHandler : null;
94
+ var hooks = _validateHooks(opts.hooks);
95
+
96
+ function _emitErrorAudit(flagKey, err, ctx) {
97
+ if (!auditOn) return;
98
+ try {
99
+ audit().safeEmit({
100
+ action: "flag.evaluation.error",
101
+ outcome: "fail",
102
+ actor: { targetingKey: ctx && ctx.targetingKey || null },
103
+ metadata: {
104
+ flagKey: flagKey,
105
+ message: err && err.message || String(err),
106
+ code: err && err.code || "flag/unknown",
107
+ },
108
+ });
109
+ } catch (_e) { /* drop-silent */ }
110
+ }
111
+
112
+ function _runHook(stage, info) {
113
+ var arr = hooks[stage];
114
+ if (!arr || arr.length === 0) return;
115
+ for (var i = 0; i < arr.length; i += 1) {
116
+ try { arr[i](info); } catch (_e) { /* drop-silent — hooks are observability, not blocking */ }
117
+ }
118
+ }
119
+
120
+ function _evaluate(flagKey, ctx) {
121
+ var mergedCtx = contextMod.merge(defaultCtx, ctx || {});
122
+ var startMs = Date.now();
123
+ _runHook("before", { flagKey: flagKey, ctx: mergedCtx });
124
+ for (var i = 0; i < providers.length; i += 1) {
125
+ try {
126
+ var result = providers[i].evaluate(flagKey, mergedCtx);
127
+ if (result && result.reason !== "flag_not_found") {
128
+ if (auditOn) {
129
+ try {
130
+ audit().safeEmit({
131
+ action: "flag.evaluated",
132
+ outcome: "success",
133
+ actor: { targetingKey: mergedCtx.targetingKey || null },
134
+ metadata: {
135
+ flagKey: flagKey,
136
+ variant: result.variant,
137
+ reason: result.reason,
138
+ provider: providers[i].kind || null,
139
+ },
140
+ });
141
+ } catch (_e) { /* drop-silent */ }
142
+ }
143
+ _runHook("after", { flagKey: flagKey, ctx: mergedCtx, result: result, elapsedMs: Date.now() - startMs });
144
+ _runHook("finally", { flagKey: flagKey, ctx: mergedCtx, result: result });
145
+ return result;
146
+ }
147
+ } catch (err) {
148
+ _emitErrorAudit(flagKey, err, mergedCtx);
149
+ _runHook("error", { flagKey: flagKey, ctx: mergedCtx, err: err });
150
+ if (errorHandler) {
151
+ try { errorHandler({ flagKey: flagKey, err: err, ctx: mergedCtx }); }
152
+ catch (_e2) { /* drop-silent */ }
153
+ }
154
+ }
155
+ }
156
+ var notFound = {
157
+ value: undefined,
158
+ variant: null,
159
+ reason: "flag_not_found",
160
+ metadata: { flagKey: flagKey, providers: providers.map(function (p) { return p.kind; }) },
161
+ };
162
+ _runHook("after", { flagKey: flagKey, ctx: mergedCtx, result: notFound, elapsedMs: Date.now() - startMs });
163
+ _runHook("finally", { flagKey: flagKey, ctx: mergedCtx, result: notFound });
164
+ return notFound;
165
+ }
166
+
167
+ function _coerceBoolean(v) {
168
+ if (v === true || v === false) return v;
169
+ if (v === "true") return true;
170
+ if (v === "false") return false;
171
+ if (v === 1) return true;
172
+ if (v === 0) return false;
173
+ return null;
174
+ }
175
+
176
+ return {
177
+ getValue: function (flagKey, ctx, defaultValue) {
178
+ var r = _evaluate(flagKey, ctx);
179
+ if (r.value === undefined) return defaultValue;
180
+ return r.value;
181
+ },
182
+ getDetails: function (flagKey, ctx) {
183
+ return _evaluate(flagKey, ctx);
184
+ },
185
+ getBoolean: function (flagKey, ctx, defaultValue) {
186
+ var r = _evaluate(flagKey, ctx);
187
+ if (r.value === undefined) return defaultValue === true;
188
+ var coerced = _coerceBoolean(r.value);
189
+ return coerced != null ? coerced : (defaultValue === true);
190
+ },
191
+ getString: function (flagKey, ctx, defaultValue) {
192
+ var r = _evaluate(flagKey, ctx);
193
+ if (typeof r.value === "string") return r.value;
194
+ return (typeof defaultValue === "string") ? defaultValue : "";
195
+ },
196
+ getNumber: function (flagKey, ctx, defaultValue) {
197
+ var r = _evaluate(flagKey, ctx);
198
+ if (typeof r.value === "number" && isFinite(r.value)) return r.value;
199
+ return (typeof defaultValue === "number") ? defaultValue : 0;
200
+ },
201
+ getObject: function (flagKey, ctx, defaultValue) {
202
+ var r = _evaluate(flagKey, ctx);
203
+ if (r.value && typeof r.value === "object") return r.value;
204
+ return defaultValue == null ? {} : defaultValue;
205
+ },
206
+ list: function () {
207
+ var keys = Object.create(null);
208
+ for (var i = 0; i < providers.length; i += 1) {
209
+ if (typeof providers[i].list === "function") {
210
+ var arr = providers[i].list();
211
+ for (var j = 0; j < arr.length; j += 1) keys[arr[j]] = true;
212
+ }
213
+ }
214
+ return Object.keys(keys);
215
+ },
216
+ providers: providers.slice(),
217
+ defaultEvaluationContext: defaultCtx,
218
+ getValues: function (flagKeys, ctx) {
219
+ var out = {};
220
+ if (!Array.isArray(flagKeys)) return out;
221
+ for (var i = 0; i < flagKeys.length; i += 1) {
222
+ var k = flagKeys[i];
223
+ if (typeof k !== "string") continue;
224
+ var r = _evaluate(k, ctx);
225
+ out[k] = r.value;
226
+ }
227
+ return out;
228
+ },
229
+ getDetailsAll: function (flagKeys, ctx) {
230
+ var out = {};
231
+ if (!Array.isArray(flagKeys)) return out;
232
+ for (var i = 0; i < flagKeys.length; i += 1) {
233
+ var k = flagKeys[i];
234
+ if (typeof k !== "string") continue;
235
+ out[k] = _evaluate(k, ctx);
236
+ }
237
+ return out;
238
+ },
239
+ addProvider: function (next) {
240
+ if (!next || typeof next.evaluate !== "function") {
241
+ throw new FlagError("flag/bad-provider",
242
+ "addProvider: provider must implement .evaluate()");
243
+ }
244
+ providers.push(next);
245
+ return providers.length;
246
+ },
247
+ removeProvider: function (target) {
248
+ var before = providers.length;
249
+ for (var i = providers.length - 1; i >= 0; i -= 1) {
250
+ if (providers[i] === target) providers.splice(i, 1);
251
+ }
252
+ return before - providers.length;
253
+ },
254
+ middleware: function (mwOpts) {
255
+ mwOpts = mwOpts || {};
256
+ validateOpts(mwOpts, ["userKey"], "flag.middleware");
257
+ var self = this;
258
+ return function flagMiddleware(req, res, next) {
259
+ var reqCtx = contextMod.fromRequest(req, {
260
+ userKey: mwOpts.userKey,
261
+ });
262
+ req.flag = {
263
+ getBoolean: function (k, def) { return self.getBoolean(k, reqCtx, def); },
264
+ getString: function (k, def) { return self.getString (k, reqCtx, def); },
265
+ getNumber: function (k, def) { return self.getNumber (k, reqCtx, def); },
266
+ getObject: function (k, def) { return self.getObject (k, reqCtx, def); },
267
+ getValue: function (k, def) { return self.getValue (k, reqCtx, def); },
268
+ getDetails: function (k) { return self.getDetails(k, reqCtx); },
269
+ ctx: reqCtx,
270
+ };
271
+ return next();
272
+ };
273
+ },
274
+ };
275
+ }
276
+
277
+ module.exports = {
278
+ create: create,
279
+ providers: providersMod,
280
+ context: contextMod,
281
+ targeting: targeting,
282
+ cache: cacheMod.cache,
283
+ FlagError: FlagError,
284
+ };