@jewel998/config 0.1.5 → 0.1.7
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 +0 -1
- package/dist/cache/memoryStorage.d.ts +0 -1
- package/dist/cache/storage.d.ts +14 -0
- package/dist/cache/storage.js +43 -0
- package/dist/cache/types.d.ts +0 -1
- package/dist/client/ConfigClient.d.ts +0 -1
- package/dist/context/autoContext.d.ts +0 -1
- package/dist/createConfig.d.ts +0 -1
- package/dist/errors/index.d.ts +16 -0
- package/dist/errors/index.js +29 -0
- package/dist/events/EventEmitter.d.ts +0 -1
- package/dist/fetch/batchFetcher.d.ts +0 -1
- package/dist/fetch/projectedFetcher.d.ts +0 -1
- package/dist/index.d.ts +13 -0
- package/dist/initConfig.d.ts +0 -1
- package/dist/loading/deferred.d.ts +2 -0
- package/dist/loading/deferred.js +5 -0
- package/dist/loading/optimistic.d.ts +2 -0
- package/dist/loading/pessimistic.d.ts +2 -0
- package/dist/plugins/evaluatePipeline.d.ts +0 -1
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/lifecycle/archivedPlugin.d.ts +0 -1
- package/dist/plugins/lifecycle/index.d.ts +3 -0
- package/dist/plugins/lifecycle/stateTransitions.d.ts +0 -1
- package/dist/plugins/models.d.ts +50 -0
- package/dist/plugins/models.js +5 -0
- package/dist/plugins/overrides/index.d.ts +1 -0
- package/dist/plugins/overrides/overridesPlugin.d.ts +0 -1
- package/dist/plugins/prerequisites/index.d.ts +2 -0
- package/dist/plugins/prerequisites/prerequisitePlugin.d.ts +0 -1
- package/dist/plugins/rollout/computeBucket.d.ts +0 -1
- package/dist/plugins/rollout/index.d.ts +2 -0
- package/dist/plugins/rollout/murmurhash3.d.ts +5 -0
- package/dist/plugins/rollout/murmurhash3.js +56 -0
- package/dist/plugins/rollout/rolloutPlugin.d.ts +0 -1
- package/dist/plugins/schedule/index.d.ts +1 -0
- package/dist/plugins/schedule/schedulePlugin.d.ts +0 -1
- package/dist/plugins/targeting/index.d.ts +3 -0
- package/dist/plugins/targeting/predicates.d.ts +22 -0
- package/dist/plugins/targeting/predicates.js +110 -0
- package/dist/plugins/targeting/segmentResolver.d.ts +0 -1
- package/dist/plugins/targeting/targetingPlugin.d.ts +0 -1
- package/dist/plugins/types.d.ts +34 -0
- package/dist/plugins/types.js +13 -0
- package/dist/retry/RetryEngine.d.ts +0 -1
- package/dist/transport/HttpTransport.d.ts +0 -1
- package/dist/types.d.ts +203 -0
- package/dist/types.js +14 -0
- package/dist/webhook-formats.d.ts +91 -0
- package/dist/webhook-formats.js +141 -0
- package/package.json +3 -2
- package/dist/cache/browserStorage.d.ts.map +0 -1
- package/dist/cache/browserStorage.js.map +0 -1
- package/dist/cache/memoryStorage.d.ts.map +0 -1
- package/dist/cache/memoryStorage.js.map +0 -1
- package/dist/cache/types.d.ts.map +0 -1
- package/dist/cache/types.js.map +0 -1
- package/dist/client/ConfigClient.d.ts.map +0 -1
- package/dist/client/ConfigClient.js.map +0 -1
- package/dist/context/autoContext.d.ts.map +0 -1
- package/dist/context/autoContext.js.map +0 -1
- package/dist/createConfig.d.ts.map +0 -1
- package/dist/createConfig.js.map +0 -1
- package/dist/events/EventEmitter.d.ts.map +0 -1
- package/dist/events/EventEmitter.js.map +0 -1
- package/dist/fetch/batchFetcher.d.ts.map +0 -1
- package/dist/fetch/batchFetcher.js.map +0 -1
- package/dist/fetch/projectedFetcher.d.ts.map +0 -1
- package/dist/fetch/projectedFetcher.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/initConfig.d.ts.map +0 -1
- package/dist/initConfig.js.map +0 -1
- package/dist/loading/optimistic.d.ts.map +0 -1
- package/dist/loading/optimistic.js.map +0 -1
- package/dist/loading/pessimistic.d.ts.map +0 -1
- package/dist/loading/pessimistic.js.map +0 -1
- package/dist/plugins/evaluatePipeline.d.ts.map +0 -1
- package/dist/plugins/evaluatePipeline.js.map +0 -1
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/lifecycle/archivedPlugin.d.ts.map +0 -1
- package/dist/plugins/lifecycle/archivedPlugin.js.map +0 -1
- package/dist/plugins/lifecycle/index.d.ts.map +0 -1
- package/dist/plugins/lifecycle/index.js.map +0 -1
- package/dist/plugins/lifecycle/stateTransitions.d.ts.map +0 -1
- package/dist/plugins/lifecycle/stateTransitions.js.map +0 -1
- package/dist/plugins/overrides/index.d.ts.map +0 -1
- package/dist/plugins/overrides/index.js.map +0 -1
- package/dist/plugins/overrides/overridesPlugin.d.ts.map +0 -1
- package/dist/plugins/overrides/overridesPlugin.js.map +0 -1
- package/dist/plugins/prerequisites/index.d.ts.map +0 -1
- package/dist/plugins/prerequisites/index.js.map +0 -1
- package/dist/plugins/prerequisites/prerequisitePlugin.d.ts.map +0 -1
- package/dist/plugins/prerequisites/prerequisitePlugin.js.map +0 -1
- package/dist/plugins/rollout/computeBucket.d.ts.map +0 -1
- package/dist/plugins/rollout/computeBucket.js.map +0 -1
- package/dist/plugins/rollout/index.d.ts.map +0 -1
- package/dist/plugins/rollout/index.js.map +0 -1
- package/dist/plugins/rollout/rolloutPlugin.d.ts.map +0 -1
- package/dist/plugins/rollout/rolloutPlugin.js.map +0 -1
- package/dist/plugins/schedule/index.d.ts.map +0 -1
- package/dist/plugins/schedule/index.js.map +0 -1
- package/dist/plugins/schedule/schedulePlugin.d.ts.map +0 -1
- package/dist/plugins/schedule/schedulePlugin.js.map +0 -1
- package/dist/plugins/targeting/index.d.ts.map +0 -1
- package/dist/plugins/targeting/index.js.map +0 -1
- package/dist/plugins/targeting/segmentResolver.d.ts.map +0 -1
- package/dist/plugins/targeting/segmentResolver.js.map +0 -1
- package/dist/plugins/targeting/targetingPlugin.d.ts.map +0 -1
- package/dist/plugins/targeting/targetingPlugin.js.map +0 -1
- package/dist/retry/RetryEngine.d.ts.map +0 -1
- package/dist/retry/RetryEngine.js.map +0 -1
- package/dist/transport/HttpTransport.d.ts.map +0 -1
- package/dist/transport/HttpTransport.js.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CacheStorage {
|
|
2
|
+
get<T>(key: string): Promise<T | undefined> | T | undefined;
|
|
3
|
+
set<T>(key: string, value: T): Promise<void> | void;
|
|
4
|
+
delete(key: string): Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
export interface CacheDriver {
|
|
7
|
+
name: string;
|
|
8
|
+
getItem<T>(key: string): Promise<T | undefined>;
|
|
9
|
+
setItem<T>(key: string, value: T): Promise<void>;
|
|
10
|
+
removeItem(key: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare const memoryStorage: () => CacheStorage;
|
|
13
|
+
export declare const createDriverStorage: (driver: CacheDriver, storageKey?: string) => CacheStorage;
|
|
14
|
+
export declare const browserStorage: (storageKey?: string) => CacheStorage;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
export const memoryStorage = () => {
|
|
3
|
+
const store = new Map();
|
|
4
|
+
return {
|
|
5
|
+
get: (key) => store.get(key),
|
|
6
|
+
set: (key, value) => {
|
|
7
|
+
store.set(key, value);
|
|
8
|
+
},
|
|
9
|
+
delete: (key) => {
|
|
10
|
+
store.delete(key);
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export const createDriverStorage = (driver, storageKey = "@jewel998/config") => ({
|
|
15
|
+
get: async (key) => driver.getItem(`${storageKey}:${key}`),
|
|
16
|
+
set: async (key, value) => {
|
|
17
|
+
await driver.setItem(`${storageKey}:${key}`, value);
|
|
18
|
+
},
|
|
19
|
+
delete: async (key) => {
|
|
20
|
+
await driver.removeItem(`${storageKey}:${key}`);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
export const browserStorage = (storageKey = "@jewel998/config") => {
|
|
24
|
+
const isBrowser = typeof window !== "undefined" && typeof window.localStorage !== "undefined";
|
|
25
|
+
if (!isBrowser) {
|
|
26
|
+
return memoryStorage();
|
|
27
|
+
}
|
|
28
|
+
const driver = {
|
|
29
|
+
name: "localStorage",
|
|
30
|
+
getItem: async (key) => {
|
|
31
|
+
const serialized = window.localStorage.getItem(key);
|
|
32
|
+
return serialized ? JSON.parse(serialized) : undefined;
|
|
33
|
+
},
|
|
34
|
+
setItem: async (key, value) => {
|
|
35
|
+
window.localStorage.setItem(key, JSON.stringify(value));
|
|
36
|
+
},
|
|
37
|
+
removeItem: async (key) => {
|
|
38
|
+
window.localStorage.removeItem(key);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
return createDriverStorage(driver, storageKey);
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=storage.js.map
|
package/dist/cache/types.d.ts
CHANGED
|
@@ -25,4 +25,3 @@ export declare function autoContext(user?: {
|
|
|
25
25
|
* Deep-merge two evaluation contexts. User-provided values take precedence.
|
|
26
26
|
*/
|
|
27
27
|
export declare function mergeContext(auto: EvaluationContext, user: EvaluationContext): EvaluationContext;
|
|
28
|
-
//# sourceMappingURL=autoContext.d.ts.map
|
package/dist/createConfig.d.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ConfigErrorCode = "MISSING_CLIENT_ID" | "AUTHENTICATION_FAILED" | "INITIALIZATION_FAILED" | "TIMEOUT" | "RATE_LIMITED" | "REVOKED" | "NETWORK_ERROR";
|
|
2
|
+
export declare class ConfigError extends Error {
|
|
3
|
+
readonly code: ConfigErrorCode;
|
|
4
|
+
name: string;
|
|
5
|
+
constructor(message: string, code: ConfigErrorCode);
|
|
6
|
+
}
|
|
7
|
+
export declare class InitializationError extends ConfigError {
|
|
8
|
+
readonly cause?: Error | undefined;
|
|
9
|
+
constructor(message: string, cause?: Error | undefined);
|
|
10
|
+
}
|
|
11
|
+
export declare class TimeoutError extends ConfigError {
|
|
12
|
+
constructor(timeoutMs: number);
|
|
13
|
+
}
|
|
14
|
+
export declare class AuthenticationError extends ConfigError {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class ConfigError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
name = "ConfigError";
|
|
4
|
+
constructor(message, code) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class InitializationError extends ConfigError {
|
|
10
|
+
cause;
|
|
11
|
+
constructor(message, cause) {
|
|
12
|
+
super(message, "INITIALIZATION_FAILED");
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
this.name = "InitializationError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class TimeoutError extends ConfigError {
|
|
18
|
+
constructor(timeoutMs) {
|
|
19
|
+
super(`Config initialization timed out after ${timeoutMs}ms`, "TIMEOUT");
|
|
20
|
+
this.name = "TimeoutError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class AuthenticationError extends ConfigError {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message, "AUTHENTICATION_FAILED");
|
|
26
|
+
this.name = "AuthenticationError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { initConfig } from "./initConfig.js";
|
|
2
|
+
export type { InitConfigOptions, Flags } from "./initConfig.js";
|
|
3
|
+
export { createConfig } from "./createConfig.js";
|
|
4
|
+
export type { CacheStorage, ClientIdRecord, ConfigClient, ConfigEventCallback, ConfigEventPayloads, ConfigEventType, ConfigRecord, CreateConfigOptions, EnvironmentRecord, EvaluationWarning, FetchGranularity, LoadingStrategy, ProjectRecord, RetryConfig, } from "./types.js";
|
|
5
|
+
export type { EvaluationContext, EvaluationPlugin, PipelineStepId, PipelineStepResult, PipelineHelpers, } from "./plugins/types.js";
|
|
6
|
+
export { PIPELINE_ORDER } from "./plugins/types.js";
|
|
7
|
+
export { autoContext, mergeContext } from "./context/autoContext.js";
|
|
8
|
+
export { WEBHOOK_FORMATS, WEBHOOK_FORMAT_INFO, TEMPLATE_VARIABLES, WEBHOOK_EVENT_TYPES, WEBHOOK_RESOURCE_CATEGORIES, SAMPLE_WEBHOOK_EVENT, } from "./webhook-formats.js";
|
|
9
|
+
export type { WebhookFormat, WebhookEventType, WebhookResourceCategory, } from "./webhook-formats.js";
|
|
10
|
+
export { memoryStorage } from "./cache/memoryStorage.js";
|
|
11
|
+
export { browserStorage } from "./cache/browserStorage.js";
|
|
12
|
+
export { AuthenticationError, ConfigError, InitializationError, TimeoutError, } from "./errors/index.js";
|
|
13
|
+
export type { ConfigErrorCode } from "./errors/index.js";
|
package/dist/initConfig.d.ts
CHANGED
|
@@ -12,4 +12,3 @@ import type { EvaluationContext, EvaluationPlugin, PipelineHelpers } from "./typ
|
|
|
12
12
|
* Steps with no registered plugin are transparently skipped.
|
|
13
13
|
*/
|
|
14
14
|
export declare function evaluatePipeline(plugins: EvaluationPlugin[], flag: ConfigFlagData, context: EvaluationContext, helpers: PipelineHelpers): unknown;
|
|
15
|
-
//# sourceMappingURL=evaluatePipeline.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
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";
|
|
@@ -24,4 +24,3 @@ export declare const VALID_TRANSITIONS: Record<LifecycleState, LifecycleState[]>
|
|
|
24
24
|
* @returns `true` if the transition is valid, `false` otherwise
|
|
25
25
|
*/
|
|
26
26
|
export declare function validateStateTransition(current: LifecycleState, target: LifecycleState): boolean;
|
|
27
|
-
//# sourceMappingURL=stateTransitions.d.ts.map
|
|
@@ -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
|
+
operator?: "equals" | "not_equals" | "greater_than" | "less_than" | "contains";
|
|
19
|
+
requiredValue: unknown;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/** A single targeting rule */
|
|
23
|
+
export interface TargetingRule {
|
|
24
|
+
id: string;
|
|
25
|
+
priority: number;
|
|
26
|
+
value: unknown;
|
|
27
|
+
conditions: PredicateGroup[];
|
|
28
|
+
}
|
|
29
|
+
/** A group of predicates combined with AND logic */
|
|
30
|
+
export interface PredicateGroup {
|
|
31
|
+
predicates: Predicate[];
|
|
32
|
+
}
|
|
33
|
+
/** A single predicate */
|
|
34
|
+
export interface Predicate {
|
|
35
|
+
attribute: string;
|
|
36
|
+
operator: PredicateOperator;
|
|
37
|
+
value: string | number | boolean | string[];
|
|
38
|
+
}
|
|
39
|
+
/** Supported predicate operators */
|
|
40
|
+
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";
|
|
41
|
+
/** A reusable audience segment */
|
|
42
|
+
export interface Segment {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
conditions: PredicateGroup[];
|
|
47
|
+
createdAt: string;
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
createdBy: string;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { overridesPlugin } from "./overridesPlugin.js";
|
|
@@ -21,4 +21,3 @@ export interface PrerequisitePluginOptions {
|
|
|
21
21
|
* that tracks which flags are currently being evaluated for prerequisites.
|
|
22
22
|
*/
|
|
23
23
|
export declare function prerequisitePlugin(options?: PrerequisitePluginOptions): EvaluationPlugin;
|
|
24
|
-
//# sourceMappingURL=prerequisitePlugin.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// MurmurHash3_x86_32
|
|
3
|
+
// Public domain — Austin Appleby
|
|
4
|
+
// Adapted for TypeScript (operates on UTF-8 encoded string bytes)
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════
|
|
6
|
+
/**
|
|
7
|
+
* MurmurHash3_x86_32 — deterministic 32-bit hash.
|
|
8
|
+
* Used for percentage rollout bucketing (same algorithm as flagd/OpenFeature).
|
|
9
|
+
*/
|
|
10
|
+
export function murmurhash3_32(key, seed = 0) {
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
const bytes = encoder.encode(key);
|
|
13
|
+
const len = bytes.length;
|
|
14
|
+
let h1 = seed >>> 0;
|
|
15
|
+
const c1 = 0xcc9e2d51;
|
|
16
|
+
const c2 = 0x1b873593;
|
|
17
|
+
let i = 0;
|
|
18
|
+
while (i + 4 <= len) {
|
|
19
|
+
let k1 = (bytes[i] |
|
|
20
|
+
(bytes[i + 1] << 8) |
|
|
21
|
+
(bytes[i + 2] << 16) |
|
|
22
|
+
(bytes[i + 3] << 24)) >>>
|
|
23
|
+
0;
|
|
24
|
+
k1 = Math.imul(k1, c1) >>> 0;
|
|
25
|
+
k1 = ((k1 << 15) | (k1 >>> 17)) >>> 0;
|
|
26
|
+
k1 = Math.imul(k1, c2) >>> 0;
|
|
27
|
+
h1 ^= k1;
|
|
28
|
+
h1 = ((h1 << 13) | (h1 >>> 19)) >>> 0;
|
|
29
|
+
h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;
|
|
30
|
+
i += 4;
|
|
31
|
+
}
|
|
32
|
+
let k1 = 0;
|
|
33
|
+
const remainder = len & 3;
|
|
34
|
+
if (remainder >= 3) {
|
|
35
|
+
k1 ^= bytes[i + 2] << 16;
|
|
36
|
+
}
|
|
37
|
+
if (remainder >= 2) {
|
|
38
|
+
k1 ^= bytes[i + 1] << 8;
|
|
39
|
+
}
|
|
40
|
+
if (remainder >= 1) {
|
|
41
|
+
k1 ^= bytes[i];
|
|
42
|
+
k1 = Math.imul(k1, c1) >>> 0;
|
|
43
|
+
k1 = ((k1 << 15) | (k1 >>> 17)) >>> 0;
|
|
44
|
+
k1 = Math.imul(k1, c2) >>> 0;
|
|
45
|
+
h1 ^= k1;
|
|
46
|
+
}
|
|
47
|
+
h1 ^= len;
|
|
48
|
+
// fmix32
|
|
49
|
+
h1 ^= h1 >>> 16;
|
|
50
|
+
h1 = Math.imul(h1, 0x85ebca6b) >>> 0;
|
|
51
|
+
h1 ^= h1 >>> 13;
|
|
52
|
+
h1 = Math.imul(h1, 0xc2b2ae35) >>> 0;
|
|
53
|
+
h1 ^= h1 >>> 16;
|
|
54
|
+
return h1 >>> 0;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=murmurhash3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { schedulePlugin } from "./schedulePlugin.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Predicate, PredicateGroup } from "../models.js";
|
|
2
|
+
type AttributeValue = string | number | boolean | string[];
|
|
3
|
+
/**
|
|
4
|
+
* Evaluate a single predicate against the provided attributes.
|
|
5
|
+
*
|
|
6
|
+
* Returns false for:
|
|
7
|
+
* - Missing attributes in context
|
|
8
|
+
* - Type mismatches (e.g., greater_than on a non-numeric value)
|
|
9
|
+
* - Invalid regex patterns (also calls emitError)
|
|
10
|
+
* - in_segment / not_in_segment (handled externally by segment resolver)
|
|
11
|
+
*/
|
|
12
|
+
export declare function evaluatePredicate(predicate: Predicate, attributes: Record<string, AttributeValue>, emitError?: (message: string) => void): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Evaluate predicate groups in Disjunctive Normal Form (DNF).
|
|
15
|
+
*
|
|
16
|
+
* Groups are OR'd — any group matching means the whole expression matches.
|
|
17
|
+
* Within each group, predicates are AND'd — all must match.
|
|
18
|
+
*
|
|
19
|
+
* Returns false if groups array is empty.
|
|
20
|
+
*/
|
|
21
|
+
export declare function evaluatePredicateGroups(groups: PredicateGroup[], attributes: Record<string, AttributeValue>, emitError?: (message: string) => void): boolean;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// Predicate Evaluator — DNF logic for targeting rules
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
/**
|
|
5
|
+
* Evaluate a single predicate against the provided attributes.
|
|
6
|
+
*
|
|
7
|
+
* Returns false for:
|
|
8
|
+
* - Missing attributes in context
|
|
9
|
+
* - Type mismatches (e.g., greater_than on a non-numeric value)
|
|
10
|
+
* - Invalid regex patterns (also calls emitError)
|
|
11
|
+
* - in_segment / not_in_segment (handled externally by segment resolver)
|
|
12
|
+
*/
|
|
13
|
+
export function evaluatePredicate(predicate, attributes, emitError) {
|
|
14
|
+
const { attribute, operator, value } = predicate;
|
|
15
|
+
// in_segment / not_in_segment are resolved externally by the segment resolver
|
|
16
|
+
if (operator === "in_segment" || operator === "not_in_segment") {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// Missing attribute → predicate is non-matching (Property 4)
|
|
20
|
+
if (!(attribute in attributes)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const attrValue = attributes[attribute];
|
|
24
|
+
// Attribute value is undefined/null → non-matching
|
|
25
|
+
if (attrValue === undefined || attrValue === null) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
switch (operator) {
|
|
29
|
+
case "equals":
|
|
30
|
+
return attrValue === value;
|
|
31
|
+
case "not_equals":
|
|
32
|
+
return attrValue !== value;
|
|
33
|
+
case "contains": {
|
|
34
|
+
if (typeof attrValue !== "string" || typeof value !== "string") {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return attrValue.includes(value);
|
|
38
|
+
}
|
|
39
|
+
case "starts_with": {
|
|
40
|
+
if (typeof attrValue !== "string" || typeof value !== "string") {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return attrValue.startsWith(value);
|
|
44
|
+
}
|
|
45
|
+
case "ends_with": {
|
|
46
|
+
if (typeof attrValue !== "string" || typeof value !== "string") {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return attrValue.endsWith(value);
|
|
50
|
+
}
|
|
51
|
+
case "in_list": {
|
|
52
|
+
if (!Array.isArray(value)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return value.includes(attrValue);
|
|
56
|
+
}
|
|
57
|
+
case "not_in_list": {
|
|
58
|
+
if (!Array.isArray(value)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return !value.includes(attrValue);
|
|
62
|
+
}
|
|
63
|
+
case "greater_than": {
|
|
64
|
+
if (typeof attrValue !== "number" || typeof value !== "number") {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return attrValue > value;
|
|
68
|
+
}
|
|
69
|
+
case "less_than": {
|
|
70
|
+
if (typeof attrValue !== "number" || typeof value !== "number") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return attrValue < value;
|
|
74
|
+
}
|
|
75
|
+
case "regex_match": {
|
|
76
|
+
if (typeof attrValue !== "string" || typeof value !== "string") {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const regex = new RegExp(value);
|
|
81
|
+
return regex.test(attrValue);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
emitError?.(`Invalid regex pattern: ${value}`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
default:
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Evaluate predicate groups in Disjunctive Normal Form (DNF).
|
|
94
|
+
*
|
|
95
|
+
* Groups are OR'd — any group matching means the whole expression matches.
|
|
96
|
+
* Within each group, predicates are AND'd — all must match.
|
|
97
|
+
*
|
|
98
|
+
* Returns false if groups array is empty.
|
|
99
|
+
*/
|
|
100
|
+
export function evaluatePredicateGroups(groups, attributes, emitError) {
|
|
101
|
+
if (groups.length === 0) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
// OR across groups: at least one group must fully match
|
|
105
|
+
return groups.some((group) => {
|
|
106
|
+
// AND within each group: all predicates must match
|
|
107
|
+
return group.predicates.every((predicate) => evaluatePredicate(predicate, attributes, emitError));
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=predicates.js.map
|
|
@@ -13,4 +13,3 @@ type AttributeValue = string | number | boolean | string[];
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function resolveSegment(segmentId: string, segments: Record<string, Segment>, attributes: Record<string, AttributeValue>, emitError?: (message: string) => void): boolean;
|
|
15
15
|
export {};
|
|
16
|
-
//# sourceMappingURL=segmentResolver.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ConfigFlagData } from "./models.js";
|
|
2
|
+
/** Pipeline step identifier — determines execution order */
|
|
3
|
+
export type PipelineStepId = "archived" | "prerequisites" | "overrides" | "schedule" | "targeting" | "rollout";
|
|
4
|
+
/** The fixed execution order (per Requirement 11) */
|
|
5
|
+
export declare const PIPELINE_ORDER: PipelineStepId[];
|
|
6
|
+
/** Evaluation context provided by the consumer */
|
|
7
|
+
export interface EvaluationContext {
|
|
8
|
+
userId?: string;
|
|
9
|
+
attributes?: Record<string, string | number | boolean | string[]>;
|
|
10
|
+
consentGranted?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Result from a pipeline step */
|
|
13
|
+
export type PipelineStepResult = {
|
|
14
|
+
resolved: true;
|
|
15
|
+
value: unknown;
|
|
16
|
+
} | {
|
|
17
|
+
resolved: false;
|
|
18
|
+
};
|
|
19
|
+
/** A registered evaluation plugin */
|
|
20
|
+
export interface EvaluationPlugin {
|
|
21
|
+
/** Which pipeline step this plugin handles */
|
|
22
|
+
stepId: PipelineStepId;
|
|
23
|
+
/** Evaluate a config flag at this pipeline step */
|
|
24
|
+
evaluate(flag: ConfigFlagData, context: EvaluationContext, helpers: PipelineHelpers): PipelineStepResult;
|
|
25
|
+
}
|
|
26
|
+
/** Helpers provided to plugins for cross-cutting concerns */
|
|
27
|
+
export interface PipelineHelpers {
|
|
28
|
+
/** Evaluate another flag (for prerequisites) */
|
|
29
|
+
evaluateFlag(key: string, context: EvaluationContext): unknown;
|
|
30
|
+
/** Emit an error */
|
|
31
|
+
emitError(message: string): void;
|
|
32
|
+
/** Current timestamp (injectable for testing) */
|
|
33
|
+
now(): number;
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// Plugin System Types and Pipeline Interfaces
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
/** The fixed execution order (per Requirement 11) */
|
|
5
|
+
export const PIPELINE_ORDER = [
|
|
6
|
+
"archived",
|
|
7
|
+
"prerequisites",
|
|
8
|
+
"overrides",
|
|
9
|
+
"schedule",
|
|
10
|
+
"targeting",
|
|
11
|
+
"rollout",
|
|
12
|
+
];
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -2,4 +2,3 @@ import type { RetryConfig } from "../types.js";
|
|
|
2
2
|
export declare const sleep: (ms: number) => Promise<void>;
|
|
3
3
|
export declare const isNonRetryableError: (error: unknown) => boolean;
|
|
4
4
|
export declare const withRetry: <T>(fn: () => Promise<T>, options?: RetryConfig, onRetry?: (attempt: number, error: Error, nextDelay: number) => void) => Promise<T>;
|
|
5
|
-
//# sourceMappingURL=RetryEngine.d.ts.map
|