@mergedapp/feature-flags 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.
@@ -0,0 +1,175 @@
1
+ import * as _repo_types_v2 from '@repo/types-v2';
2
+ import { EvaluatedFlag, FeatureFlagEvaluationContext } from '@repo/types-v2';
3
+ export { EvaluateResponse, EvaluatedFlag, FeatureFlagDefinition, FeatureFlagEvaluationContext, FeatureFlagType, PublicKeyResponse, SignedEvaluateResponse } from '@repo/types-v2';
4
+
5
+ declare class FeatureFlagError extends Error {
6
+ constructor(message: string, options?: {
7
+ cause?: unknown;
8
+ });
9
+ }
10
+ declare class FeatureFlagNetworkError extends FeatureFlagError {
11
+ constructor(message: string, options?: {
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ declare class FeatureFlagVerificationError extends FeatureFlagError {
16
+ constructor(message: string, options?: {
17
+ cause?: unknown;
18
+ });
19
+ }
20
+
21
+ /** Base type for a flag registry mapping flag names to their value types. */
22
+ type FlagRegistry = object;
23
+ type FeatureFlagRuntimeSource = "network" | "persisted" | "defaults";
24
+ type FeatureFlagRuntimeStatus = {
25
+ source: FeatureFlagRuntimeSource;
26
+ isStale: boolean;
27
+ lastSuccessfulRefreshAt: string | null;
28
+ tokenExpiresAt: string | null;
29
+ lastError: Error | null;
30
+ };
31
+ type PersistedFeatureFlagSnapshot = {
32
+ schemaVersion: number;
33
+ scopeKey: string;
34
+ organizationId: string;
35
+ environmentId: string;
36
+ teamId: string | null;
37
+ clientKeyFingerprint: string;
38
+ contextHash: string;
39
+ token: string;
40
+ publicKeyPem: string;
41
+ fetchedAt: string;
42
+ tokenExpiresAt: string | null;
43
+ };
44
+ type FeatureFlagSnapshotStore = {
45
+ load(key: string): Promise<PersistedFeatureFlagSnapshot | null>;
46
+ save(key: string, snapshot: PersistedFeatureFlagSnapshot): Promise<void>;
47
+ remove(key: string): Promise<void>;
48
+ };
49
+ type FeatureFlagSnapshotPersistenceConfig = {
50
+ store?: FeatureFlagSnapshotStore;
51
+ keyPrefix?: string;
52
+ };
53
+ type FeatureFlagClientConfig<TFlags extends FlagRegistry = FlagRegistry> = {
54
+ /** API key with `lk_pub_*` or `lk_sec_*` prefix */
55
+ clientKey: string;
56
+ /** Base URL for the API (e.g. "https://api.merged.gg") */
57
+ apiUrl: string;
58
+ /** Organization scope for signed flag evaluation */
59
+ organizationId: string;
60
+ /** Environment scope for signed flag evaluation */
61
+ environmentId: string;
62
+ /** Optional team scope for signed flag evaluation */
63
+ teamId?: string;
64
+ /** Code-key-to-ID mapping from generated code. Enables type-safe lookups resolved to stable IDs. */
65
+ flagIds?: {
66
+ readonly [K in string & keyof TFlags]: string;
67
+ };
68
+ /** PEM-format ES256 public key. If omitted, auto-fetched from the public-key endpoint. */
69
+ publicKey?: string;
70
+ /** Polling interval in milliseconds. Default: 60_000 (60s). Set to 0 to disable. */
71
+ refreshInterval?: number;
72
+ /** Optional caller-provided evaluation context sent to the API when resolving flags. */
73
+ evaluationContext?: _repo_types_v2.FeatureFlagEvaluationContext;
74
+ /** Controls automatic persistence of the last successful signed evaluation. */
75
+ snapshotPersistence?: false | FeatureFlagSnapshotPersistenceConfig;
76
+ /** Called when an error occurs during refresh or verification */
77
+ onError?: (error: Error) => void;
78
+ /** Called when flags change after a refresh */
79
+ onFlagsChanged?: (flags: _repo_types_v2.EvaluatedFlag[]) => void;
80
+ };
81
+ type GenerateConfig = {
82
+ /** Base URL for the API */
83
+ apiUrl: string;
84
+ /** API key for fetching definitions */
85
+ clientKey: string;
86
+ /** Output path for the generated TypeScript file */
87
+ outputPath: string;
88
+ /** Optional team scope */
89
+ teamId?: string;
90
+ /** Organization ID required for fetching definitions */
91
+ organizationId: string;
92
+ };
93
+
94
+ type ChangeListener = (flags: EvaluatedFlag[]) => void;
95
+ declare class MergedFeatureFlags<TFlags extends FlagRegistry = FlagRegistry> {
96
+ private flagsById;
97
+ private flagsByName;
98
+ private publicKeyPem;
99
+ private publicKeyCrypto;
100
+ private refreshTimer;
101
+ private backoffMs;
102
+ private consecutiveFailures;
103
+ private listeners;
104
+ private storeListeners;
105
+ private initialized;
106
+ private visibilityHandler;
107
+ private pendingScopeTransition;
108
+ private runtimeStatus;
109
+ private snapshotStorePromise;
110
+ private readonly keyPrefix;
111
+ private contextSignature;
112
+ private readonly flagIds;
113
+ private readonly clientKey;
114
+ private readonly apiUrl;
115
+ private readonly organizationId;
116
+ private readonly environmentId;
117
+ private readonly teamId;
118
+ private readonly refreshInterval;
119
+ private readonly onError;
120
+ private readonly onFlagsChanged;
121
+ private readonly snapshotPersistence;
122
+ private evaluationContext;
123
+ constructor(config: FeatureFlagClientConfig<TFlags>);
124
+ initialize(): Promise<void>;
125
+ /** Returns true if the flag is enabled. Returns false for unknown flags. */
126
+ isEnabled<K extends string & keyof TFlags>(name: K): boolean;
127
+ /** Returns the flag's value with the type inferred from the flag registry. */
128
+ getValue<K extends string & keyof TFlags>(name: K): TFlags[K] | undefined;
129
+ /** Returns the full evaluated flag entry, or undefined if not found. */
130
+ getFlag<K extends string & keyof TFlags>(name: K): EvaluatedFlag | undefined;
131
+ /** Returns all evaluated flags. */
132
+ getAllFlags(): EvaluatedFlag[];
133
+ getStatus(): FeatureFlagRuntimeStatus;
134
+ getStatusSnapshot(): FeatureFlagRuntimeStatus;
135
+ /** Manually trigger a refresh from the server. */
136
+ refresh(): Promise<void>;
137
+ /** Subscribe to flag changes. Returns an unsubscribe function. */
138
+ onChange(listener: ChangeListener): () => void;
139
+ /** Get a snapshot function for useSyncExternalStore. */
140
+ getSnapshot(): EvaluatedFlag[];
141
+ /** Replace the caller-provided evaluation context used on subsequent refreshes. */
142
+ setEvaluationContext(context: FeatureFlagEvaluationContext | null | undefined): void;
143
+ /** Subscribe function for useSyncExternalStore. */
144
+ subscribe(onStoreChange: () => void): () => void;
145
+ /** Clean up timers, listeners, and cached data. */
146
+ destroy(): void;
147
+ private resolveFlag;
148
+ private clearFlags;
149
+ private emitChange;
150
+ private updateFlags;
151
+ private hasFlagsChanged;
152
+ private setRuntimeStatus;
153
+ private fetchSignedFlags;
154
+ private fetchPublicKey;
155
+ private verifyWithRetry;
156
+ private ensureVerificationKey;
157
+ private getTrustedSnapshotVerificationKey;
158
+ private getSnapshotStore;
159
+ private getScopeParts;
160
+ private restorePersistedSnapshot;
161
+ private persistSnapshot;
162
+ private startPolling;
163
+ private scheduleNextPoll;
164
+ private safeRefresh;
165
+ private resetBackoff;
166
+ private incrementBackoff;
167
+ }
168
+
169
+ declare function createDefaultFeatureFlagRuntimeStatus(): FeatureFlagRuntimeStatus;
170
+ declare function createLocalStorageFeatureFlagSnapshotStore(): FeatureFlagSnapshotStore;
171
+ declare function createFileFeatureFlagSnapshotStore(params?: {
172
+ rootDirectory?: string;
173
+ }): FeatureFlagSnapshotStore;
174
+
175
+ export { type FeatureFlagClientConfig, FeatureFlagError, FeatureFlagNetworkError, type FeatureFlagRuntimeSource, type FeatureFlagRuntimeStatus, type FeatureFlagSnapshotPersistenceConfig, type FeatureFlagSnapshotStore, FeatureFlagVerificationError, type FlagRegistry, type GenerateConfig, MergedFeatureFlags, type PersistedFeatureFlagSnapshot, createDefaultFeatureFlagRuntimeStatus, createFileFeatureFlagSnapshotStore, createLocalStorageFeatureFlagSnapshotStore };
@@ -0,0 +1,175 @@
1
+ import * as _repo_types_v2 from '@repo/types-v2';
2
+ import { EvaluatedFlag, FeatureFlagEvaluationContext } from '@repo/types-v2';
3
+ export { EvaluateResponse, EvaluatedFlag, FeatureFlagDefinition, FeatureFlagEvaluationContext, FeatureFlagType, PublicKeyResponse, SignedEvaluateResponse } from '@repo/types-v2';
4
+
5
+ declare class FeatureFlagError extends Error {
6
+ constructor(message: string, options?: {
7
+ cause?: unknown;
8
+ });
9
+ }
10
+ declare class FeatureFlagNetworkError extends FeatureFlagError {
11
+ constructor(message: string, options?: {
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ declare class FeatureFlagVerificationError extends FeatureFlagError {
16
+ constructor(message: string, options?: {
17
+ cause?: unknown;
18
+ });
19
+ }
20
+
21
+ /** Base type for a flag registry mapping flag names to their value types. */
22
+ type FlagRegistry = object;
23
+ type FeatureFlagRuntimeSource = "network" | "persisted" | "defaults";
24
+ type FeatureFlagRuntimeStatus = {
25
+ source: FeatureFlagRuntimeSource;
26
+ isStale: boolean;
27
+ lastSuccessfulRefreshAt: string | null;
28
+ tokenExpiresAt: string | null;
29
+ lastError: Error | null;
30
+ };
31
+ type PersistedFeatureFlagSnapshot = {
32
+ schemaVersion: number;
33
+ scopeKey: string;
34
+ organizationId: string;
35
+ environmentId: string;
36
+ teamId: string | null;
37
+ clientKeyFingerprint: string;
38
+ contextHash: string;
39
+ token: string;
40
+ publicKeyPem: string;
41
+ fetchedAt: string;
42
+ tokenExpiresAt: string | null;
43
+ };
44
+ type FeatureFlagSnapshotStore = {
45
+ load(key: string): Promise<PersistedFeatureFlagSnapshot | null>;
46
+ save(key: string, snapshot: PersistedFeatureFlagSnapshot): Promise<void>;
47
+ remove(key: string): Promise<void>;
48
+ };
49
+ type FeatureFlagSnapshotPersistenceConfig = {
50
+ store?: FeatureFlagSnapshotStore;
51
+ keyPrefix?: string;
52
+ };
53
+ type FeatureFlagClientConfig<TFlags extends FlagRegistry = FlagRegistry> = {
54
+ /** API key with `lk_pub_*` or `lk_sec_*` prefix */
55
+ clientKey: string;
56
+ /** Base URL for the API (e.g. "https://api.merged.gg") */
57
+ apiUrl: string;
58
+ /** Organization scope for signed flag evaluation */
59
+ organizationId: string;
60
+ /** Environment scope for signed flag evaluation */
61
+ environmentId: string;
62
+ /** Optional team scope for signed flag evaluation */
63
+ teamId?: string;
64
+ /** Code-key-to-ID mapping from generated code. Enables type-safe lookups resolved to stable IDs. */
65
+ flagIds?: {
66
+ readonly [K in string & keyof TFlags]: string;
67
+ };
68
+ /** PEM-format ES256 public key. If omitted, auto-fetched from the public-key endpoint. */
69
+ publicKey?: string;
70
+ /** Polling interval in milliseconds. Default: 60_000 (60s). Set to 0 to disable. */
71
+ refreshInterval?: number;
72
+ /** Optional caller-provided evaluation context sent to the API when resolving flags. */
73
+ evaluationContext?: _repo_types_v2.FeatureFlagEvaluationContext;
74
+ /** Controls automatic persistence of the last successful signed evaluation. */
75
+ snapshotPersistence?: false | FeatureFlagSnapshotPersistenceConfig;
76
+ /** Called when an error occurs during refresh or verification */
77
+ onError?: (error: Error) => void;
78
+ /** Called when flags change after a refresh */
79
+ onFlagsChanged?: (flags: _repo_types_v2.EvaluatedFlag[]) => void;
80
+ };
81
+ type GenerateConfig = {
82
+ /** Base URL for the API */
83
+ apiUrl: string;
84
+ /** API key for fetching definitions */
85
+ clientKey: string;
86
+ /** Output path for the generated TypeScript file */
87
+ outputPath: string;
88
+ /** Optional team scope */
89
+ teamId?: string;
90
+ /** Organization ID required for fetching definitions */
91
+ organizationId: string;
92
+ };
93
+
94
+ type ChangeListener = (flags: EvaluatedFlag[]) => void;
95
+ declare class MergedFeatureFlags<TFlags extends FlagRegistry = FlagRegistry> {
96
+ private flagsById;
97
+ private flagsByName;
98
+ private publicKeyPem;
99
+ private publicKeyCrypto;
100
+ private refreshTimer;
101
+ private backoffMs;
102
+ private consecutiveFailures;
103
+ private listeners;
104
+ private storeListeners;
105
+ private initialized;
106
+ private visibilityHandler;
107
+ private pendingScopeTransition;
108
+ private runtimeStatus;
109
+ private snapshotStorePromise;
110
+ private readonly keyPrefix;
111
+ private contextSignature;
112
+ private readonly flagIds;
113
+ private readonly clientKey;
114
+ private readonly apiUrl;
115
+ private readonly organizationId;
116
+ private readonly environmentId;
117
+ private readonly teamId;
118
+ private readonly refreshInterval;
119
+ private readonly onError;
120
+ private readonly onFlagsChanged;
121
+ private readonly snapshotPersistence;
122
+ private evaluationContext;
123
+ constructor(config: FeatureFlagClientConfig<TFlags>);
124
+ initialize(): Promise<void>;
125
+ /** Returns true if the flag is enabled. Returns false for unknown flags. */
126
+ isEnabled<K extends string & keyof TFlags>(name: K): boolean;
127
+ /** Returns the flag's value with the type inferred from the flag registry. */
128
+ getValue<K extends string & keyof TFlags>(name: K): TFlags[K] | undefined;
129
+ /** Returns the full evaluated flag entry, or undefined if not found. */
130
+ getFlag<K extends string & keyof TFlags>(name: K): EvaluatedFlag | undefined;
131
+ /** Returns all evaluated flags. */
132
+ getAllFlags(): EvaluatedFlag[];
133
+ getStatus(): FeatureFlagRuntimeStatus;
134
+ getStatusSnapshot(): FeatureFlagRuntimeStatus;
135
+ /** Manually trigger a refresh from the server. */
136
+ refresh(): Promise<void>;
137
+ /** Subscribe to flag changes. Returns an unsubscribe function. */
138
+ onChange(listener: ChangeListener): () => void;
139
+ /** Get a snapshot function for useSyncExternalStore. */
140
+ getSnapshot(): EvaluatedFlag[];
141
+ /** Replace the caller-provided evaluation context used on subsequent refreshes. */
142
+ setEvaluationContext(context: FeatureFlagEvaluationContext | null | undefined): void;
143
+ /** Subscribe function for useSyncExternalStore. */
144
+ subscribe(onStoreChange: () => void): () => void;
145
+ /** Clean up timers, listeners, and cached data. */
146
+ destroy(): void;
147
+ private resolveFlag;
148
+ private clearFlags;
149
+ private emitChange;
150
+ private updateFlags;
151
+ private hasFlagsChanged;
152
+ private setRuntimeStatus;
153
+ private fetchSignedFlags;
154
+ private fetchPublicKey;
155
+ private verifyWithRetry;
156
+ private ensureVerificationKey;
157
+ private getTrustedSnapshotVerificationKey;
158
+ private getSnapshotStore;
159
+ private getScopeParts;
160
+ private restorePersistedSnapshot;
161
+ private persistSnapshot;
162
+ private startPolling;
163
+ private scheduleNextPoll;
164
+ private safeRefresh;
165
+ private resetBackoff;
166
+ private incrementBackoff;
167
+ }
168
+
169
+ declare function createDefaultFeatureFlagRuntimeStatus(): FeatureFlagRuntimeStatus;
170
+ declare function createLocalStorageFeatureFlagSnapshotStore(): FeatureFlagSnapshotStore;
171
+ declare function createFileFeatureFlagSnapshotStore(params?: {
172
+ rootDirectory?: string;
173
+ }): FeatureFlagSnapshotStore;
174
+
175
+ export { type FeatureFlagClientConfig, FeatureFlagError, FeatureFlagNetworkError, type FeatureFlagRuntimeSource, type FeatureFlagRuntimeStatus, type FeatureFlagSnapshotPersistenceConfig, type FeatureFlagSnapshotStore, FeatureFlagVerificationError, type FlagRegistry, type GenerateConfig, MergedFeatureFlags, type PersistedFeatureFlagSnapshot, createDefaultFeatureFlagRuntimeStatus, createFileFeatureFlagSnapshotStore, createLocalStorageFeatureFlagSnapshotStore };