@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.
- package/dist/cache/browserStorage.d.ts +3 -0
- package/dist/cache/browserStorage.d.ts.map +1 -0
- package/dist/cache/browserStorage.js +54 -0
- package/dist/cache/browserStorage.js.map +1 -0
- package/dist/cache/memoryStorage.d.ts +3 -0
- package/dist/cache/memoryStorage.d.ts.map +1 -0
- package/dist/cache/memoryStorage.js +30 -0
- package/dist/cache/memoryStorage.js.map +1 -0
- package/dist/cache/storage.d.ts +15 -0
- package/dist/cache/storage.d.ts.map +1 -0
- package/dist/cache/storage.js +43 -0
- package/dist/cache/storage.js.map +1 -0
- package/dist/cache/types.d.ts +3 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +2 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/client/ConfigClient.d.ts +16 -0
- package/dist/client/ConfigClient.d.ts.map +1 -0
- package/dist/client/ConfigClient.js +215 -0
- package/dist/client/ConfigClient.js.map +1 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +80 -0
- package/dist/client.js.map +1 -0
- package/dist/core/resolver.d.ts +8 -0
- package/dist/core/resolver.d.ts.map +1 -0
- package/dist/core/resolver.js +22 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/createConfig.d.ts +6 -0
- package/dist/createConfig.d.ts.map +1 -0
- package/dist/createConfig.js +110 -0
- package/dist/createConfig.js.map +1 -0
- package/dist/errors/index.d.ts +17 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +29 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/events/EventEmitter.d.ts +9 -0
- package/dist/events/EventEmitter.d.ts.map +1 -0
- package/dist/events/EventEmitter.js +30 -0
- package/dist/events/EventEmitter.js.map +1 -0
- package/dist/example.d.ts +2 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +23 -0
- package/dist/example.js.map +1 -0
- package/dist/fetch/batchFetcher.d.ts +3 -0
- package/dist/fetch/batchFetcher.d.ts.map +1 -0
- package/dist/fetch/batchFetcher.js +12 -0
- package/dist/fetch/batchFetcher.js.map +1 -0
- package/dist/fetch/projectedFetcher.d.ts +3 -0
- package/dist/fetch/projectedFetcher.d.ts.map +1 -0
- package/dist/fetch/projectedFetcher.js +43 -0
- package/dist/fetch/projectedFetcher.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/loading/deferred.d.ts +3 -0
- package/dist/loading/deferred.d.ts.map +1 -0
- package/dist/loading/deferred.js +5 -0
- package/dist/loading/deferred.js.map +1 -0
- package/dist/loading/optimistic.d.ts +3 -0
- package/dist/loading/optimistic.d.ts.map +1 -0
- package/dist/loading/optimistic.js +35 -0
- package/dist/loading/optimistic.js.map +1 -0
- package/dist/loading/pessimistic.d.ts +3 -0
- package/dist/loading/pessimistic.d.ts.map +1 -0
- package/dist/loading/pessimistic.js +24 -0
- package/dist/loading/pessimistic.js.map +1 -0
- package/dist/management/index.d.ts +3 -0
- package/dist/management/index.d.ts.map +1 -0
- package/dist/management/index.js +2 -0
- package/dist/management/index.js.map +1 -0
- package/dist/management/manager.d.ts +34 -0
- package/dist/management/manager.d.ts.map +1 -0
- package/dist/management/manager.js +21 -0
- package/dist/management/manager.js.map +1 -0
- package/dist/management/memory-backend.d.ts +6 -0
- package/dist/management/memory-backend.d.ts.map +1 -0
- package/dist/management/memory-backend.js +78 -0
- package/dist/management/memory-backend.js.map +1 -0
- package/dist/plugins/evaluatePipeline.d.ts +15 -0
- package/dist/plugins/evaluatePipeline.d.ts.map +1 -0
- package/dist/plugins/evaluatePipeline.js +39 -0
- package/dist/plugins/evaluatePipeline.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +6 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/lifecycle/archivedPlugin.d.ts +14 -0
- package/dist/plugins/lifecycle/archivedPlugin.d.ts.map +1 -0
- package/dist/plugins/lifecycle/archivedPlugin.js +26 -0
- package/dist/plugins/lifecycle/archivedPlugin.js.map +1 -0
- package/dist/plugins/lifecycle/index.d.ts +4 -0
- package/dist/plugins/lifecycle/index.d.ts.map +1 -0
- package/dist/plugins/lifecycle/index.js +6 -0
- package/dist/plugins/lifecycle/index.js.map +1 -0
- package/dist/plugins/lifecycle/stateTransitions.d.ts +27 -0
- package/dist/plugins/lifecycle/stateTransitions.d.ts.map +1 -0
- package/dist/plugins/lifecycle/stateTransitions.js +33 -0
- package/dist/plugins/lifecycle/stateTransitions.js.map +1 -0
- package/dist/plugins/models.d.ts +50 -0
- package/dist/plugins/models.d.ts.map +1 -0
- package/dist/plugins/models.js +5 -0
- package/dist/plugins/models.js.map +1 -0
- package/dist/plugins/overrides/index.d.ts +2 -0
- package/dist/plugins/overrides/index.d.ts.map +1 -0
- package/dist/plugins/overrides/index.js +5 -0
- package/dist/plugins/overrides/index.js.map +1 -0
- package/dist/plugins/overrides/overridesPlugin.d.ts +12 -0
- package/dist/plugins/overrides/overridesPlugin.d.ts.map +1 -0
- package/dist/plugins/overrides/overridesPlugin.js +40 -0
- package/dist/plugins/overrides/overridesPlugin.js.map +1 -0
- package/dist/plugins/prerequisites/index.d.ts +3 -0
- package/dist/plugins/prerequisites/index.d.ts.map +1 -0
- package/dist/plugins/prerequisites/index.js +5 -0
- package/dist/plugins/prerequisites/index.js.map +1 -0
- package/dist/plugins/prerequisites/prerequisitePlugin.d.ts +24 -0
- package/dist/plugins/prerequisites/prerequisitePlugin.d.ts.map +1 -0
- package/dist/plugins/prerequisites/prerequisitePlugin.js +62 -0
- package/dist/plugins/prerequisites/prerequisitePlugin.js.map +1 -0
- package/dist/plugins/rollout/computeBucket.d.ts +12 -0
- package/dist/plugins/rollout/computeBucket.d.ts.map +1 -0
- package/dist/plugins/rollout/computeBucket.js +20 -0
- package/dist/plugins/rollout/computeBucket.js.map +1 -0
- package/dist/plugins/rollout/index.d.ts +3 -0
- package/dist/plugins/rollout/index.d.ts.map +1 -0
- package/dist/plugins/rollout/index.js +6 -0
- package/dist/plugins/rollout/index.js.map +1 -0
- package/dist/plugins/rollout/murmurhash3.d.ts +6 -0
- package/dist/plugins/rollout/murmurhash3.d.ts.map +1 -0
- package/dist/plugins/rollout/murmurhash3.js +56 -0
- package/dist/plugins/rollout/murmurhash3.js.map +1 -0
- package/dist/plugins/rollout/rolloutPlugin.d.ts +13 -0
- package/dist/plugins/rollout/rolloutPlugin.d.ts.map +1 -0
- package/dist/plugins/rollout/rolloutPlugin.js +44 -0
- package/dist/plugins/rollout/rolloutPlugin.js.map +1 -0
- package/dist/plugins/schedule/index.d.ts +2 -0
- package/dist/plugins/schedule/index.d.ts.map +1 -0
- package/dist/plugins/schedule/index.js +5 -0
- package/dist/plugins/schedule/index.js.map +1 -0
- package/dist/plugins/schedule/schedulePlugin.d.ts +14 -0
- package/dist/plugins/schedule/schedulePlugin.d.ts.map +1 -0
- package/dist/plugins/schedule/schedulePlugin.js +38 -0
- package/dist/plugins/schedule/schedulePlugin.js.map +1 -0
- package/dist/plugins/targeting/index.d.ts +4 -0
- package/dist/plugins/targeting/index.d.ts.map +1 -0
- package/dist/plugins/targeting/index.js +4 -0
- package/dist/plugins/targeting/index.js.map +1 -0
- package/dist/plugins/targeting/predicates.d.ts +23 -0
- package/dist/plugins/targeting/predicates.d.ts.map +1 -0
- package/dist/plugins/targeting/predicates.js +110 -0
- package/dist/plugins/targeting/predicates.js.map +1 -0
- package/dist/plugins/targeting/segmentResolver.d.ts +16 -0
- package/dist/plugins/targeting/segmentResolver.d.ts.map +1 -0
- package/dist/plugins/targeting/segmentResolver.js +27 -0
- package/dist/plugins/targeting/segmentResolver.js.map +1 -0
- package/dist/plugins/targeting/targetingPlugin.d.ts +19 -0
- package/dist/plugins/targeting/targetingPlugin.d.ts.map +1 -0
- package/dist/plugins/targeting/targetingPlugin.js +80 -0
- package/dist/plugins/targeting/targetingPlugin.js.map +1 -0
- package/dist/plugins/types.d.ts +35 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +13 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/registry.d.ts +9 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +22 -0
- package/dist/registry.js.map +1 -0
- package/dist/remote/firebase-adapter.d.ts +6 -0
- package/dist/remote/firebase-adapter.d.ts.map +1 -0
- package/dist/remote/firebase-adapter.js +12 -0
- package/dist/remote/firebase-adapter.js.map +1 -0
- package/dist/remote/provider.d.ts +6 -0
- package/dist/remote/provider.d.ts.map +1 -0
- package/dist/remote/provider.js +5 -0
- package/dist/remote/provider.js.map +1 -0
- package/dist/retry/RetryEngine.d.ts +5 -0
- package/dist/retry/RetryEngine.d.ts.map +1 -0
- package/dist/retry/RetryEngine.js +36 -0
- package/dist/retry/RetryEngine.js.map +1 -0
- package/dist/transport/HttpTransport.d.ts +7 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -0
- package/dist/transport/HttpTransport.js +34 -0
- package/dist/transport/HttpTransport.js.map +1 -0
- package/dist/types.d.ts +217 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/plugins/models.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,qCAAqC;AACrC,kEAAkE"}
|
|
@@ -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 @@
|
|
|
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
|