@jewel998/config 0.1.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 (189) hide show
  1. package/dist/cache/browserStorage.d.ts +3 -0
  2. package/dist/cache/browserStorage.d.ts.map +1 -0
  3. package/dist/cache/browserStorage.js +54 -0
  4. package/dist/cache/browserStorage.js.map +1 -0
  5. package/dist/cache/memoryStorage.d.ts +3 -0
  6. package/dist/cache/memoryStorage.d.ts.map +1 -0
  7. package/dist/cache/memoryStorage.js +30 -0
  8. package/dist/cache/memoryStorage.js.map +1 -0
  9. package/dist/cache/storage.d.ts +15 -0
  10. package/dist/cache/storage.d.ts.map +1 -0
  11. package/dist/cache/storage.js +43 -0
  12. package/dist/cache/storage.js.map +1 -0
  13. package/dist/cache/types.d.ts +3 -0
  14. package/dist/cache/types.d.ts.map +1 -0
  15. package/dist/cache/types.js +2 -0
  16. package/dist/cache/types.js.map +1 -0
  17. package/dist/client/ConfigClient.d.ts +16 -0
  18. package/dist/client/ConfigClient.d.ts.map +1 -0
  19. package/dist/client/ConfigClient.js +215 -0
  20. package/dist/client/ConfigClient.js.map +1 -0
  21. package/dist/client.d.ts +15 -0
  22. package/dist/client.d.ts.map +1 -0
  23. package/dist/client.js +80 -0
  24. package/dist/client.js.map +1 -0
  25. package/dist/core/resolver.d.ts +8 -0
  26. package/dist/core/resolver.d.ts.map +1 -0
  27. package/dist/core/resolver.js +22 -0
  28. package/dist/core/resolver.js.map +1 -0
  29. package/dist/createConfig.d.ts +6 -0
  30. package/dist/createConfig.d.ts.map +1 -0
  31. package/dist/createConfig.js +110 -0
  32. package/dist/createConfig.js.map +1 -0
  33. package/dist/errors/index.d.ts +17 -0
  34. package/dist/errors/index.d.ts.map +1 -0
  35. package/dist/errors/index.js +29 -0
  36. package/dist/errors/index.js.map +1 -0
  37. package/dist/events/EventEmitter.d.ts +9 -0
  38. package/dist/events/EventEmitter.d.ts.map +1 -0
  39. package/dist/events/EventEmitter.js +30 -0
  40. package/dist/events/EventEmitter.js.map +1 -0
  41. package/dist/example.d.ts +2 -0
  42. package/dist/example.d.ts.map +1 -0
  43. package/dist/example.js +23 -0
  44. package/dist/example.js.map +1 -0
  45. package/dist/fetch/batchFetcher.d.ts +3 -0
  46. package/dist/fetch/batchFetcher.d.ts.map +1 -0
  47. package/dist/fetch/batchFetcher.js +12 -0
  48. package/dist/fetch/batchFetcher.js.map +1 -0
  49. package/dist/fetch/projectedFetcher.d.ts +3 -0
  50. package/dist/fetch/projectedFetcher.d.ts.map +1 -0
  51. package/dist/fetch/projectedFetcher.js +43 -0
  52. package/dist/fetch/projectedFetcher.js.map +1 -0
  53. package/dist/index.d.ts +23 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +19 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/loading/deferred.d.ts +3 -0
  58. package/dist/loading/deferred.d.ts.map +1 -0
  59. package/dist/loading/deferred.js +5 -0
  60. package/dist/loading/deferred.js.map +1 -0
  61. package/dist/loading/optimistic.d.ts +3 -0
  62. package/dist/loading/optimistic.d.ts.map +1 -0
  63. package/dist/loading/optimistic.js +35 -0
  64. package/dist/loading/optimistic.js.map +1 -0
  65. package/dist/loading/pessimistic.d.ts +3 -0
  66. package/dist/loading/pessimistic.d.ts.map +1 -0
  67. package/dist/loading/pessimistic.js +24 -0
  68. package/dist/loading/pessimistic.js.map +1 -0
  69. package/dist/management/index.d.ts +3 -0
  70. package/dist/management/index.d.ts.map +1 -0
  71. package/dist/management/index.js +2 -0
  72. package/dist/management/index.js.map +1 -0
  73. package/dist/management/manager.d.ts +34 -0
  74. package/dist/management/manager.d.ts.map +1 -0
  75. package/dist/management/manager.js +21 -0
  76. package/dist/management/manager.js.map +1 -0
  77. package/dist/management/memory-backend.d.ts +6 -0
  78. package/dist/management/memory-backend.d.ts.map +1 -0
  79. package/dist/management/memory-backend.js +78 -0
  80. package/dist/management/memory-backend.js.map +1 -0
  81. package/dist/plugins/evaluatePipeline.d.ts +15 -0
  82. package/dist/plugins/evaluatePipeline.d.ts.map +1 -0
  83. package/dist/plugins/evaluatePipeline.js +39 -0
  84. package/dist/plugins/evaluatePipeline.js.map +1 -0
  85. package/dist/plugins/index.d.ts +5 -0
  86. package/dist/plugins/index.d.ts.map +1 -0
  87. package/dist/plugins/index.js +6 -0
  88. package/dist/plugins/index.js.map +1 -0
  89. package/dist/plugins/lifecycle/archivedPlugin.d.ts +14 -0
  90. package/dist/plugins/lifecycle/archivedPlugin.d.ts.map +1 -0
  91. package/dist/plugins/lifecycle/archivedPlugin.js +26 -0
  92. package/dist/plugins/lifecycle/archivedPlugin.js.map +1 -0
  93. package/dist/plugins/lifecycle/index.d.ts +4 -0
  94. package/dist/plugins/lifecycle/index.d.ts.map +1 -0
  95. package/dist/plugins/lifecycle/index.js +6 -0
  96. package/dist/plugins/lifecycle/index.js.map +1 -0
  97. package/dist/plugins/lifecycle/stateTransitions.d.ts +27 -0
  98. package/dist/plugins/lifecycle/stateTransitions.d.ts.map +1 -0
  99. package/dist/plugins/lifecycle/stateTransitions.js +33 -0
  100. package/dist/plugins/lifecycle/stateTransitions.js.map +1 -0
  101. package/dist/plugins/models.d.ts +50 -0
  102. package/dist/plugins/models.d.ts.map +1 -0
  103. package/dist/plugins/models.js +5 -0
  104. package/dist/plugins/models.js.map +1 -0
  105. package/dist/plugins/overrides/index.d.ts +2 -0
  106. package/dist/plugins/overrides/index.d.ts.map +1 -0
  107. package/dist/plugins/overrides/index.js +5 -0
  108. package/dist/plugins/overrides/index.js.map +1 -0
  109. package/dist/plugins/overrides/overridesPlugin.d.ts +12 -0
  110. package/dist/plugins/overrides/overridesPlugin.d.ts.map +1 -0
  111. package/dist/plugins/overrides/overridesPlugin.js +40 -0
  112. package/dist/plugins/overrides/overridesPlugin.js.map +1 -0
  113. package/dist/plugins/prerequisites/index.d.ts +3 -0
  114. package/dist/plugins/prerequisites/index.d.ts.map +1 -0
  115. package/dist/plugins/prerequisites/index.js +5 -0
  116. package/dist/plugins/prerequisites/index.js.map +1 -0
  117. package/dist/plugins/prerequisites/prerequisitePlugin.d.ts +24 -0
  118. package/dist/plugins/prerequisites/prerequisitePlugin.d.ts.map +1 -0
  119. package/dist/plugins/prerequisites/prerequisitePlugin.js +62 -0
  120. package/dist/plugins/prerequisites/prerequisitePlugin.js.map +1 -0
  121. package/dist/plugins/rollout/computeBucket.d.ts +12 -0
  122. package/dist/plugins/rollout/computeBucket.d.ts.map +1 -0
  123. package/dist/plugins/rollout/computeBucket.js +20 -0
  124. package/dist/plugins/rollout/computeBucket.js.map +1 -0
  125. package/dist/plugins/rollout/index.d.ts +3 -0
  126. package/dist/plugins/rollout/index.d.ts.map +1 -0
  127. package/dist/plugins/rollout/index.js +6 -0
  128. package/dist/plugins/rollout/index.js.map +1 -0
  129. package/dist/plugins/rollout/murmurhash3.d.ts +6 -0
  130. package/dist/plugins/rollout/murmurhash3.d.ts.map +1 -0
  131. package/dist/plugins/rollout/murmurhash3.js +56 -0
  132. package/dist/plugins/rollout/murmurhash3.js.map +1 -0
  133. package/dist/plugins/rollout/rolloutPlugin.d.ts +13 -0
  134. package/dist/plugins/rollout/rolloutPlugin.d.ts.map +1 -0
  135. package/dist/plugins/rollout/rolloutPlugin.js +44 -0
  136. package/dist/plugins/rollout/rolloutPlugin.js.map +1 -0
  137. package/dist/plugins/schedule/index.d.ts +2 -0
  138. package/dist/plugins/schedule/index.d.ts.map +1 -0
  139. package/dist/plugins/schedule/index.js +5 -0
  140. package/dist/plugins/schedule/index.js.map +1 -0
  141. package/dist/plugins/schedule/schedulePlugin.d.ts +14 -0
  142. package/dist/plugins/schedule/schedulePlugin.d.ts.map +1 -0
  143. package/dist/plugins/schedule/schedulePlugin.js +38 -0
  144. package/dist/plugins/schedule/schedulePlugin.js.map +1 -0
  145. package/dist/plugins/targeting/index.d.ts +4 -0
  146. package/dist/plugins/targeting/index.d.ts.map +1 -0
  147. package/dist/plugins/targeting/index.js +4 -0
  148. package/dist/plugins/targeting/index.js.map +1 -0
  149. package/dist/plugins/targeting/predicates.d.ts +23 -0
  150. package/dist/plugins/targeting/predicates.d.ts.map +1 -0
  151. package/dist/plugins/targeting/predicates.js +110 -0
  152. package/dist/plugins/targeting/predicates.js.map +1 -0
  153. package/dist/plugins/targeting/segmentResolver.d.ts +16 -0
  154. package/dist/plugins/targeting/segmentResolver.d.ts.map +1 -0
  155. package/dist/plugins/targeting/segmentResolver.js +27 -0
  156. package/dist/plugins/targeting/segmentResolver.js.map +1 -0
  157. package/dist/plugins/targeting/targetingPlugin.d.ts +19 -0
  158. package/dist/plugins/targeting/targetingPlugin.d.ts.map +1 -0
  159. package/dist/plugins/targeting/targetingPlugin.js +80 -0
  160. package/dist/plugins/targeting/targetingPlugin.js.map +1 -0
  161. package/dist/plugins/types.d.ts +35 -0
  162. package/dist/plugins/types.d.ts.map +1 -0
  163. package/dist/plugins/types.js +13 -0
  164. package/dist/plugins/types.js.map +1 -0
  165. package/dist/registry.d.ts +9 -0
  166. package/dist/registry.d.ts.map +1 -0
  167. package/dist/registry.js +22 -0
  168. package/dist/registry.js.map +1 -0
  169. package/dist/remote/firebase-adapter.d.ts +6 -0
  170. package/dist/remote/firebase-adapter.d.ts.map +1 -0
  171. package/dist/remote/firebase-adapter.js +12 -0
  172. package/dist/remote/firebase-adapter.js.map +1 -0
  173. package/dist/remote/provider.d.ts +6 -0
  174. package/dist/remote/provider.d.ts.map +1 -0
  175. package/dist/remote/provider.js +5 -0
  176. package/dist/remote/provider.js.map +1 -0
  177. package/dist/retry/RetryEngine.d.ts +5 -0
  178. package/dist/retry/RetryEngine.d.ts.map +1 -0
  179. package/dist/retry/RetryEngine.js +36 -0
  180. package/dist/retry/RetryEngine.js.map +1 -0
  181. package/dist/transport/HttpTransport.d.ts +7 -0
  182. package/dist/transport/HttpTransport.d.ts.map +1 -0
  183. package/dist/transport/HttpTransport.js +34 -0
  184. package/dist/transport/HttpTransport.js.map +1 -0
  185. package/dist/types.d.ts +217 -0
  186. package/dist/types.d.ts.map +1 -0
  187. package/dist/types.js +14 -0
  188. package/dist/types.js.map +1 -0
  189. package/package.json +72 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * In-memory backend for testing and local development.
3
+ */
4
+ export const createMemoryBackend = () => {
5
+ const projects = [];
6
+ const environments = [];
7
+ const versions = [];
8
+ let idCounter = 0;
9
+ const nextId = () => {
10
+ idCounter++;
11
+ return `mem-${idCounter.toString().padStart(4, "0")}`;
12
+ };
13
+ return {
14
+ createProject: async (name, ownerId) => {
15
+ const project = {
16
+ id: nextId(),
17
+ name,
18
+ ownerId,
19
+ authorizedUsers: [ownerId],
20
+ createdAt: new Date().toISOString(),
21
+ updatedAt: new Date().toISOString(),
22
+ };
23
+ projects.push(project);
24
+ return project;
25
+ },
26
+ deleteProject: async (projectId) => {
27
+ const index = projects.findIndex((p) => p.id === projectId);
28
+ if (index >= 0) {
29
+ projects.splice(index, 1);
30
+ }
31
+ },
32
+ listProjects: async (ownerId) => projects.filter((p) => p.ownerId === ownerId || p.authorizedUsers.includes(ownerId)),
33
+ createEnvironment: async (projectId, name) => {
34
+ const environment = {
35
+ id: nextId(),
36
+ projectId,
37
+ name,
38
+ allowedDomains: [],
39
+ createdAt: new Date().toISOString(),
40
+ updatedAt: new Date().toISOString(),
41
+ };
42
+ environments.push(environment);
43
+ return environment;
44
+ },
45
+ deleteEnvironment: async (_projectId, environmentId) => {
46
+ const index = environments.findIndex((e) => e.id === environmentId);
47
+ if (index >= 0) {
48
+ environments.splice(index, 1);
49
+ }
50
+ },
51
+ listEnvironments: async (projectId) => environments.filter((e) => e.projectId === projectId),
52
+ createVersion: async (projectId, version, payload, environmentId) => {
53
+ const record = {
54
+ id: nextId(),
55
+ projectId,
56
+ environmentId,
57
+ version,
58
+ payload,
59
+ publishedAt: undefined,
60
+ };
61
+ versions.push(record);
62
+ return record;
63
+ },
64
+ publishVersion: async (_projectId, versionId) => {
65
+ const record = versions.find((v) => v.id === versionId);
66
+ if (!record) {
67
+ throw new Error(`Version ${versionId} not found.`);
68
+ }
69
+ if (record.publishedAt) {
70
+ throw new Error(`Version ${versionId} is already published.`);
71
+ }
72
+ record.publishedAt = new Date().toISOString();
73
+ return record;
74
+ },
75
+ listVersions: async (projectId) => versions.filter((v) => v.projectId === projectId),
76
+ };
77
+ };
78
+ //# sourceMappingURL=memory-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-backend.js","sourceRoot":"","sources":["../../src/management/memory-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ConfigFlagData } from "./models.js";
2
+ import type { EvaluationContext, EvaluationPlugin, PipelineHelpers } from "./types.js";
3
+ /**
4
+ * Evaluate a config flag through the plugin pipeline.
5
+ *
6
+ * 1. Builds a lookup map of stepId → plugin from the registered plugins.
7
+ * 2. Iterates through PIPELINE_ORDER (fixed order regardless of registration order).
8
+ * 3. For each step, if a plugin is registered, calls plugin.evaluate().
9
+ * 4. If a plugin returns { resolved: true, value }, returns that value immediately (short-circuit).
10
+ * 5. If no plugin resolves, returns the flag's default value (flag.value).
11
+ *
12
+ * Steps with no registered plugin are transparently skipped.
13
+ */
14
+ export declare function evaluatePipeline(plugins: EvaluationPlugin[], flag: ConfigFlagData, context: EvaluationContext, helpers: PipelineHelpers): unknown;
15
+ //# sourceMappingURL=evaluatePipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluatePipeline.d.ts","sourceRoot":"","sources":["../../src/plugins/evaluatePipeline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAGpB;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EAAE,EAC3B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,eAAe,GACvB,OAAO,CA0BT"}
@@ -0,0 +1,39 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Pipeline Executor — Sorts plugins into fixed order, iterates,
3
+ // short-circuits on first resolved result.
4
+ // ═══════════════════════════════════════════════════════════════
5
+ import { PIPELINE_ORDER } from "./types.js";
6
+ /**
7
+ * Evaluate a config flag through the plugin pipeline.
8
+ *
9
+ * 1. Builds a lookup map of stepId → plugin from the registered plugins.
10
+ * 2. Iterates through PIPELINE_ORDER (fixed order regardless of registration order).
11
+ * 3. For each step, if a plugin is registered, calls plugin.evaluate().
12
+ * 4. If a plugin returns { resolved: true, value }, returns that value immediately (short-circuit).
13
+ * 5. If no plugin resolves, returns the flag's default value (flag.value).
14
+ *
15
+ * Steps with no registered plugin are transparently skipped.
16
+ */
17
+ export function evaluatePipeline(plugins, flag, context, helpers) {
18
+ // Build a map from stepId → plugin (last registration wins if duplicates)
19
+ const pluginMap = new Map();
20
+ for (const plugin of plugins) {
21
+ pluginMap.set(plugin.stepId, plugin);
22
+ }
23
+ // Iterate through the fixed pipeline order
24
+ for (const stepId of PIPELINE_ORDER) {
25
+ const plugin = pluginMap.get(stepId);
26
+ // Skip steps with no registered plugin (Property 21)
27
+ if (!plugin) {
28
+ continue;
29
+ }
30
+ const result = plugin.evaluate(flag, context, helpers);
31
+ // Short-circuit on first resolved result (Requirement 11.2)
32
+ if (result.resolved) {
33
+ return result.value;
34
+ }
35
+ }
36
+ // No step resolved — return the flag's default value
37
+ return flag.value;
38
+ }
39
+ //# sourceMappingURL=evaluatePipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluatePipeline.js","sourceRoot":"","sources":["../../src/plugins/evaluatePipeline.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,gEAAgE;AAChE,2CAA2C;AAC3C,kEAAkE;AASlE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAA2B,EAC3B,IAAoB,EACpB,OAA0B,EAC1B,OAAwB;IAExB,0EAA0E;IAC1E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC9D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,2CAA2C;IAC3C,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAErC,qDAAqD;QACrD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAEvD,4DAA4D;QAC5D,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export type { PipelineStepId, EvaluationContext, PipelineStepResult, EvaluationPlugin, PipelineHelpers, } from "./types.js";
2
+ export { PIPELINE_ORDER } from "./types.js";
3
+ export type { ConfigFlagData, TargetingRule, PredicateGroup, Predicate, PredicateOperator, Segment, } from "./models.js";
4
+ export { evaluatePipeline } from "./evaluatePipeline.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,YAAY,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,OAAO,GACR,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Plugin System — Barrel Export
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export { PIPELINE_ORDER } from "./types.js";
5
+ export { evaluatePipeline } from "./evaluatePipeline.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,gCAAgC;AAChC,kEAAkE;AAUlE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAW5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { EvaluationPlugin } from "../types.js";
2
+ /**
3
+ * Factory function that creates the archived state evaluation plugin.
4
+ *
5
+ * Evaluation logic:
6
+ * - If `flag.lifecycleState === "archived"` → return `{ resolved: true, value: undefined }`
7
+ * (archived flags always return undefined, regardless of other configuration)
8
+ * - Otherwise → return `{ resolved: false }` (let pipeline continue)
9
+ *
10
+ * This is the first step in the evaluation pipeline, ensuring archived flags
11
+ * short-circuit before any other evaluation logic runs.
12
+ */
13
+ export declare function archivedPlugin(): EvaluationPlugin;
14
+ //# sourceMappingURL=archivedPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archivedPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/lifecycle/archivedPlugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,gBAAgB,CAgBjD"}
@@ -0,0 +1,26 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Archived State Evaluation Plugin
3
+ // ═══════════════════════════════════════════════════════════════
4
+ /**
5
+ * Factory function that creates the archived state evaluation plugin.
6
+ *
7
+ * Evaluation logic:
8
+ * - If `flag.lifecycleState === "archived"` → return `{ resolved: true, value: undefined }`
9
+ * (archived flags always return undefined, regardless of other configuration)
10
+ * - Otherwise → return `{ resolved: false }` (let pipeline continue)
11
+ *
12
+ * This is the first step in the evaluation pipeline, ensuring archived flags
13
+ * short-circuit before any other evaluation logic runs.
14
+ */
15
+ export function archivedPlugin() {
16
+ return {
17
+ stepId: "archived",
18
+ evaluate(flag, _context, _helpers) {
19
+ if (flag.lifecycleState === "archived") {
20
+ return { resolved: true, value: undefined };
21
+ }
22
+ return { resolved: false };
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=archivedPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archivedPlugin.js","sourceRoot":"","sources":["../../../src/plugins/lifecycle/archivedPlugin.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,mCAAmC;AACnC,kEAAkE;AAUlE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,MAAM,EAAE,UAAU;QAElB,QAAQ,CACN,IAAoB,EACpB,QAA2B,EAC3B,QAAyB;YAEzB,IAAI,IAAI,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;gBACvC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YAC9C,CAAC;YAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { archivedPlugin } from "./archivedPlugin.js";
2
+ export { validateStateTransition, VALID_TRANSITIONS, } from "./stateTransitions.js";
3
+ export type { LifecycleState } from "./stateTransitions.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/lifecycle/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Lifecycle Plugin — Public Barrel Export
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export { archivedPlugin } from "./archivedPlugin.js";
5
+ export { validateStateTransition, VALID_TRANSITIONS, } from "./stateTransitions.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/lifecycle/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,0CAA0C;AAC1C,kEAAkE;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Valid lifecycle states for a config flag.
3
+ */
4
+ export type LifecycleState = "draft" | "active" | "stale" | "archived";
5
+ /**
6
+ * Map of valid state transitions.
7
+ *
8
+ * Allowed transitions:
9
+ * - draft → active
10
+ * - active → stale
11
+ * - stale → archived
12
+ * - stale → active (reactivation)
13
+ * - archived → active (unarchive)
14
+ *
15
+ * All other transitions are rejected.
16
+ */
17
+ export declare const VALID_TRANSITIONS: Record<LifecycleState, LifecycleState[]>;
18
+ /**
19
+ * Validates whether a state transition from `current` to `target` is allowed
20
+ * by the lifecycle state machine.
21
+ *
22
+ * @param current - The current lifecycle state of the flag
23
+ * @param target - The desired target lifecycle state
24
+ * @returns `true` if the transition is valid, `false` otherwise
25
+ */
26
+ export declare function validateStateTransition(current: LifecycleState, target: LifecycleState): boolean;
27
+ //# sourceMappingURL=stateTransitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateTransitions.d.ts","sourceRoot":"","sources":["../../../src/plugins/lifecycle/stateTransitions.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAEvE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,CAKtE,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAET"}
@@ -0,0 +1,33 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Lifecycle State Machine Validator
3
+ // ═══════════════════════════════════════════════════════════════
4
+ /**
5
+ * Map of valid state transitions.
6
+ *
7
+ * Allowed transitions:
8
+ * - draft → active
9
+ * - active → stale
10
+ * - stale → archived
11
+ * - stale → active (reactivation)
12
+ * - archived → active (unarchive)
13
+ *
14
+ * All other transitions are rejected.
15
+ */
16
+ export const VALID_TRANSITIONS = {
17
+ draft: ["active"],
18
+ active: ["stale"],
19
+ stale: ["archived", "active"],
20
+ archived: ["active"],
21
+ };
22
+ /**
23
+ * Validates whether a state transition from `current` to `target` is allowed
24
+ * by the lifecycle state machine.
25
+ *
26
+ * @param current - The current lifecycle state of the flag
27
+ * @param target - The desired target lifecycle state
28
+ * @returns `true` if the transition is valid, `false` otherwise
29
+ */
30
+ export function validateStateTransition(current, target) {
31
+ return VALID_TRANSITIONS[current]?.includes(target) ?? false;
32
+ }
33
+ //# sourceMappingURL=stateTransitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateTransitions.js","sourceRoot":"","sources":["../../../src/plugins/lifecycle/stateTransitions.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,oCAAoC;AACpC,kEAAkE;AAOlE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA6C;IACzE,KAAK,EAAE,CAAC,QAAQ,CAAC;IACjB,MAAM,EAAE,CAAC,OAAO,CAAC;IACjB,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC;IAC7B,QAAQ,EAAE,CAAC,QAAQ,CAAC;CACrB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAuB,EACvB,MAAsB;IAEtB,OAAO,iBAAiB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,50 @@
1
+ /** The full config flag document as fetched from Firestore */
2
+ export interface ConfigFlagData {
3
+ key: string;
4
+ value: unknown;
5
+ valueType: "string" | "number" | "boolean" | "json";
6
+ version: string;
7
+ lifecycleState: "draft" | "active" | "stale" | "archived";
8
+ targetingRules?: TargetingRule[];
9
+ rolloutPercentage?: number;
10
+ rolloutValue?: unknown;
11
+ overrides?: Record<string, unknown>;
12
+ schedule?: {
13
+ targetValue: unknown;
14
+ activateAt: string;
15
+ };
16
+ prerequisites?: Array<{
17
+ flagKey: string;
18
+ requiredValue: unknown;
19
+ }>;
20
+ }
21
+ /** A single targeting rule */
22
+ export interface TargetingRule {
23
+ id: string;
24
+ priority: number;
25
+ value: unknown;
26
+ conditions: PredicateGroup[];
27
+ }
28
+ /** A group of predicates combined with AND logic */
29
+ export interface PredicateGroup {
30
+ predicates: Predicate[];
31
+ }
32
+ /** A single predicate */
33
+ export interface Predicate {
34
+ attribute: string;
35
+ operator: PredicateOperator;
36
+ value: string | number | boolean | string[];
37
+ }
38
+ /** Supported predicate operators */
39
+ export type PredicateOperator = "equals" | "not_equals" | "contains" | "starts_with" | "ends_with" | "in_list" | "not_in_list" | "greater_than" | "less_than" | "regex_match" | "in_segment" | "not_in_segment";
40
+ /** A reusable audience segment */
41
+ export interface Segment {
42
+ id: string;
43
+ name: string;
44
+ description: string;
45
+ conditions: PredicateGroup[];
46
+ createdAt: string;
47
+ updatedAt: string;
48
+ createdBy: string;
49
+ }
50
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/plugins/models.ts"],"names":[],"mappings":"AAIA,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IAG1D,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IAGjC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAGpC,QAAQ,CAAC,EAAE;QACT,WAAW,EAAE,OAAO,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAGF,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC,CAAC;CACJ;AAED,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED,yBAAyB;AACzB,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC;CAC7C;AAED,oCAAoC;AACpC,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,YAAY,GACZ,UAAU,GACV,aAAa,GACb,WAAW,GACX,SAAS,GACT,aAAa,GACb,cAAc,GACd,WAAW,GACX,aAAa,GACb,YAAY,GACZ,gBAAgB,CAAC;AAErB,kCAAkC;AAClC,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,5 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Config Flag Data Models (SDK-side)
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export {};
5
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/plugins/models.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,qCAAqC;AACrC,kEAAkE"}
@@ -0,0 +1,2 @@
1
+ export { overridesPlugin } from "./overridesPlugin.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/overrides/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Overrides Plugin — Public Barrel Export
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export { overridesPlugin } from "./overridesPlugin.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/overrides/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,0CAA0C;AAC1C,kEAAkE;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { EvaluationPlugin } from "../types.js";
2
+ /**
3
+ * Factory function that creates the overrides evaluation plugin.
4
+ *
5
+ * Evaluation logic:
6
+ * - If no userId in context → skip (Req 4.5)
7
+ * - If `flag.overrides` is undefined/null → skip
8
+ * - If userId exists in overrides map AND value is not null/undefined → return override value (Req 4.3)
9
+ * - If userId not in overrides or value is null/undefined → skip (Req 4.4, 4.7)
10
+ */
11
+ export declare function overridesPlugin(): EvaluationPlugin;
12
+ //# sourceMappingURL=overridesPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overridesPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/overrides/overridesPlugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,gBAAgB,CAmClD"}
@@ -0,0 +1,40 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Overrides Evaluation Plugin
3
+ // ═══════════════════════════════════════════════════════════════
4
+ /**
5
+ * Factory function that creates the overrides evaluation plugin.
6
+ *
7
+ * Evaluation logic:
8
+ * - If no userId in context → skip (Req 4.5)
9
+ * - If `flag.overrides` is undefined/null → skip
10
+ * - If userId exists in overrides map AND value is not null/undefined → return override value (Req 4.3)
11
+ * - If userId not in overrides or value is null/undefined → skip (Req 4.4, 4.7)
12
+ */
13
+ export function overridesPlugin() {
14
+ return {
15
+ stepId: "overrides",
16
+ evaluate(flag, context, _helpers) {
17
+ // No userId in context — skip override evaluation entirely (Req 4.5)
18
+ if (!context.userId) {
19
+ return { resolved: false };
20
+ }
21
+ // No overrides map configured on this flag — skip
22
+ if (flag.overrides == null) {
23
+ return { resolved: false };
24
+ }
25
+ // Check if userId exists in overrides map
26
+ const userId = context.userId;
27
+ if (!(userId in flag.overrides)) {
28
+ return { resolved: false };
29
+ }
30
+ // userId exists but value is null/undefined — skip (Req 4.7)
31
+ const overrideValue = flag.overrides[userId];
32
+ if (overrideValue == null) {
33
+ return { resolved: false };
34
+ }
35
+ // Override found with a non-null value — return immediately (Req 4.3)
36
+ return { resolved: true, value: overrideValue };
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=overridesPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overridesPlugin.js","sourceRoot":"","sources":["../../../src/plugins/overrides/overridesPlugin.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,8BAA8B;AAC9B,kEAAkE;AAUlE;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,MAAM,EAAE,WAAW;QAEnB,QAAQ,CACN,IAAoB,EACpB,OAA0B,EAC1B,QAAyB;YAEzB,qEAAqE;YACrE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;YAED,kDAAkD;YAClD,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC3B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;YAED,0CAA0C;YAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;YAED,6DAA6D;YAC7D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;gBAC1B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;YAED,sEAAsE;YACtE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAClD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { prerequisitePlugin } from "./prerequisitePlugin.js";
2
+ export type { PrerequisitePluginOptions } from "./prerequisitePlugin.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/prerequisites/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Prerequisites Plugin — Public Barrel Export
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export { prerequisitePlugin } from "./prerequisitePlugin.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/prerequisites/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,8CAA8C;AAC9C,kEAAkE;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { EvaluationPlugin } from "../types.js";
2
+ /** Options for the prerequisite plugin */
3
+ export interface PrerequisitePluginOptions {
4
+ /** Maximum recursion depth for prerequisite evaluation (default: 5) */
5
+ maxDepth?: number;
6
+ }
7
+ /**
8
+ * Factory function that creates the prerequisites evaluation plugin.
9
+ *
10
+ * Evaluation logic:
11
+ * - If `prerequisites` is undefined/empty → skip (resolved: false)
12
+ * - For each prerequisite:
13
+ * - Check for circular dependency (flag already in evaluation stack)
14
+ * - Check for depth exceeded (> maxDepth levels)
15
+ * - Evaluate the prerequisite flag via helpers.evaluateFlag()
16
+ * - If the resolved value !== requiredValue → prerequisite is unmet
17
+ * - If any prerequisite is unmet → return flag's default value
18
+ * - If all met → skip (resolved: false), let pipeline continue
19
+ *
20
+ * Circular dependency detection uses a module-level evaluation stack (Set)
21
+ * that tracks which flags are currently being evaluated for prerequisites.
22
+ */
23
+ export declare function prerequisitePlugin(options?: PrerequisitePluginOptions): EvaluationPlugin;
24
+ //# sourceMappingURL=prerequisitePlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerequisitePlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/prerequisites/prerequisitePlugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,CAAC,EAAE,yBAAyB,GAClC,gBAAgB,CA4DlB"}
@@ -0,0 +1,62 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Prerequisites Evaluation Plugin
3
+ // ═══════════════════════════════════════════════════════════════
4
+ /**
5
+ * Factory function that creates the prerequisites evaluation plugin.
6
+ *
7
+ * Evaluation logic:
8
+ * - If `prerequisites` is undefined/empty → skip (resolved: false)
9
+ * - For each prerequisite:
10
+ * - Check for circular dependency (flag already in evaluation stack)
11
+ * - Check for depth exceeded (> maxDepth levels)
12
+ * - Evaluate the prerequisite flag via helpers.evaluateFlag()
13
+ * - If the resolved value !== requiredValue → prerequisite is unmet
14
+ * - If any prerequisite is unmet → return flag's default value
15
+ * - If all met → skip (resolved: false), let pipeline continue
16
+ *
17
+ * Circular dependency detection uses a module-level evaluation stack (Set)
18
+ * that tracks which flags are currently being evaluated for prerequisites.
19
+ */
20
+ export function prerequisitePlugin(options) {
21
+ const maxDepth = options?.maxDepth ?? 5;
22
+ /** Tracks flags currently being evaluated for prerequisites (cycle detection) */
23
+ const evaluationStack = new Set();
24
+ return {
25
+ stepId: "prerequisites",
26
+ evaluate(flag, context, helpers) {
27
+ // No prerequisites configured — skip
28
+ if (!flag.prerequisites || flag.prerequisites.length === 0) {
29
+ return { resolved: false };
30
+ }
31
+ // Check for circular dependency: this flag is already being evaluated
32
+ if (evaluationStack.has(flag.key)) {
33
+ helpers.emitError(`Circular dependency detected: flag "${flag.key}" is already in the prerequisite evaluation chain`);
34
+ return { resolved: true, value: flag.value };
35
+ }
36
+ // Check depth: if we've exceeded the max depth, stop
37
+ if (evaluationStack.size >= maxDepth) {
38
+ helpers.emitError(`Prerequisite evaluation depth exceeded maximum of ${maxDepth} levels while evaluating flag "${flag.key}"`);
39
+ return { resolved: true, value: flag.value };
40
+ }
41
+ // Add current flag to the evaluation stack
42
+ evaluationStack.add(flag.key);
43
+ try {
44
+ // Evaluate each prerequisite
45
+ for (const prerequisite of flag.prerequisites) {
46
+ const resolvedValue = helpers.evaluateFlag(prerequisite.flagKey, context);
47
+ // Strict equality check — prerequisite is unmet if values don't match
48
+ if (resolvedValue !== prerequisite.requiredValue) {
49
+ return { resolved: true, value: flag.value };
50
+ }
51
+ }
52
+ // All prerequisites met — let pipeline continue
53
+ return { resolved: false };
54
+ }
55
+ finally {
56
+ // Always remove current flag from the stack after evaluation
57
+ evaluationStack.delete(flag.key);
58
+ }
59
+ },
60
+ };
61
+ }
62
+ //# sourceMappingURL=prerequisitePlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerequisitePlugin.js","sourceRoot":"","sources":["../../../src/plugins/prerequisites/prerequisitePlugin.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,kCAAkC;AAClC,kEAAkE;AAgBlE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAmC;IAEnC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC,CAAC;IAExC,iFAAiF;IACjF,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,OAAO;QACL,MAAM,EAAE,eAAe;QAEvB,QAAQ,CACN,IAAoB,EACpB,OAA0B,EAC1B,OAAwB;YAExB,qCAAqC;YACrC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;YAED,sEAAsE;YACtE,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,SAAS,CACf,uCAAuC,IAAI,CAAC,GAAG,mDAAmD,CACnG,CAAC;gBACF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/C,CAAC;YAED,qDAAqD;YACrD,IAAI,eAAe,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBACrC,OAAO,CAAC,SAAS,CACf,qDAAqD,QAAQ,kCAAkC,IAAI,CAAC,GAAG,GAAG,CAC3G,CAAC;gBACF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/C,CAAC;YAED,2CAA2C;YAC3C,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE9B,IAAI,CAAC;gBACH,6BAA6B;gBAC7B,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC9C,MAAM,aAAa,GAAG,OAAO,CAAC,YAAY,CACxC,YAAY,CAAC,OAAO,EACpB,OAAO,CACR,CAAC;oBAEF,sEAAsE;oBACtE,IAAI,aAAa,KAAK,YAAY,CAAC,aAAa,EAAE,CAAC;wBACjD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC/C,CAAC;gBACH,CAAC;gBAED,gDAAgD;gBAChD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7B,CAAC;oBAAS,CAAC;gBACT,6DAA6D;gBAC7D,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Compute the rollout bucket (0–99) for a given configKey and userId.
3
+ *
4
+ * Algorithm:
5
+ * 1. Concatenate: `${configKey}:${userId}`
6
+ * 2. Compute MurmurHash3_x86_32 with seed 0
7
+ * 3. Map to bucket: hash % 100
8
+ *
9
+ * Deterministic — same inputs always produce the same bucket.
10
+ */
11
+ export declare function computeBucket(configKey: string, userId: string): number;
12
+ //# sourceMappingURL=computeBucket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computeBucket.d.ts","sourceRoot":"","sources":["../../../src/plugins/rollout/computeBucket.ts"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIvE"}
@@ -0,0 +1,20 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Rollout Bucket Computation
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { murmurhash3_32 } from "./murmurhash3.js";
5
+ /**
6
+ * Compute the rollout bucket (0–99) for a given configKey and userId.
7
+ *
8
+ * Algorithm:
9
+ * 1. Concatenate: `${configKey}:${userId}`
10
+ * 2. Compute MurmurHash3_x86_32 with seed 0
11
+ * 3. Map to bucket: hash % 100
12
+ *
13
+ * Deterministic — same inputs always produce the same bucket.
14
+ */
15
+ export function computeBucket(configKey, userId) {
16
+ const input = `${configKey}:${userId}`;
17
+ const hash = murmurhash3_32(input, 0);
18
+ return hash % 100;
19
+ }
20
+ //# sourceMappingURL=computeBucket.js.map