@supashiphq/javascript-sdk 0.7.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.
@@ -0,0 +1,261 @@
1
+ interface SupaPluginConfig {
2
+ enabled?: boolean;
3
+ }
4
+ interface Plugin {
5
+ name: string;
6
+ }
7
+ interface SupaPlugin extends Plugin {
8
+ onInit?(params: {
9
+ clientId: string;
10
+ availableFeatures: Record<string, FeatureValue>;
11
+ context?: FeatureContext;
12
+ }): Promise<void> | void;
13
+ beforeGetFeatures?(featureNames: string[], context?: FeatureContext): Promise<void>;
14
+ afterGetFeatures?(results: Record<string, FeatureValue>, context?: FeatureContext): Promise<void>;
15
+ onError?(error: Error, context?: FeatureContext): Promise<void>;
16
+ beforeRequest?(url: string, body: unknown, headers: Record<string, string>): Promise<void>;
17
+ afterResponse?(response: Response, timing: {
18
+ duration: number;
19
+ }): Promise<void>;
20
+ onContextUpdate?(oldContext: FeatureContext | undefined, newContext: FeatureContext, source: 'updateContext' | 'request'): Promise<void>;
21
+ onRetryAttempt?(attempt: number, error: Error, willRetry: boolean): Promise<void>;
22
+ onFallbackUsed?(featureName: string, fallbackValue: FeatureValue, reason: Error): Promise<void>;
23
+ }
24
+
25
+ interface SupaToolbarPosition {
26
+ placement?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
27
+ offset?: {
28
+ x: string;
29
+ y: string;
30
+ };
31
+ }
32
+ type SupaToolbarOverrideChange = {
33
+ feature: string;
34
+ value: FeatureValue;
35
+ };
36
+ type SupaToolbarOverrideChangeCallback = (featureOverride: SupaToolbarOverrideChange, allOverrides: Record<string, FeatureValue>) => void;
37
+ interface SupaToolbarPluginConfig extends Omit<SupaPluginConfig, 'enabled'> {
38
+ enabled?: boolean | 'auto';
39
+ position?: SupaToolbarPosition;
40
+ onOverrideChange?: SupaToolbarOverrideChangeCallback;
41
+ }
42
+ /**
43
+ * Toolbar plugin for local feature flag testing
44
+ * Provides a visual interface to override feature flags during development
45
+ */
46
+ declare class SupaToolbarPlugin implements SupaPlugin {
47
+ name: string;
48
+ private config;
49
+ private state;
50
+ private clientId?;
51
+ private storageKey;
52
+ constructor(config?: SupaToolbarPluginConfig);
53
+ cleanup(): void;
54
+ private shouldShowToolbar;
55
+ onInit(params: {
56
+ availableFeatures: Record<string, FeatureValue>;
57
+ context?: FeatureContext;
58
+ clientId: string;
59
+ }): void;
60
+ beforeGetFeatures(_featureNames: string[], context?: FeatureContext): Promise<void>;
61
+ afterGetFeatures(results: Record<string, FeatureValue>, context?: FeatureContext): Promise<void>;
62
+ private loadOverrides;
63
+ private saveOverrides;
64
+ setOverride(featureName: string, value: FeatureValue): void;
65
+ removeOverride(featureName: string): void;
66
+ clearAllOverrides(): void;
67
+ getOverrides(): Record<string, FeatureValue>;
68
+ private injectToolbar;
69
+ private removeToolbar;
70
+ private getToolbarHTML;
71
+ private injectStyles;
72
+ private attachEventListeners;
73
+ private updateToolbarUI;
74
+ private escapeHtml;
75
+ }
76
+
77
+ interface SupaClientConfig {
78
+ /**
79
+ * API key used to authenticate requests to Supaship services.
80
+ * Typically created in your project settings.
81
+ */
82
+ apiKey: string;
83
+ /**
84
+ * Environment identifier used for feature flag evaluation (e.g. "production", "staging").
85
+ */
86
+ environment: string;
87
+ /**
88
+ * Feature definitions with their fallback values.
89
+ * Use `satisfies FeaturesWithFallbacks` for type safety.
90
+ * Defines all feature flags used in the application.
91
+ */
92
+ features: FeaturesWithFallbacks;
93
+ /**
94
+ * Default context included with every feature evaluation request.
95
+ * Can be merged/overridden per-call via options.context.
96
+ */
97
+ context: FeatureContext;
98
+ /**
99
+ * Optional network configuration allowing you to override API endpoints.
100
+ * If omitted, defaults are used.
101
+ */
102
+ networkConfig?: NetworkConfig;
103
+ /**
104
+ * Optional plugins to observe or augment client behavior.
105
+ */
106
+ plugins?: SupaPlugin[];
107
+ /**
108
+ * Toolbar plugin configuration (browser only).
109
+ * - `false`: Disable toolbar (opt-out)
110
+ * - `undefined`: Enable with defaults (enabled: 'auto')
111
+ * - `object`: Custom configuration
112
+ *
113
+ * Default: Enabled in browser with 'auto' mode (shows only on localhost)
114
+ */
115
+ toolbar?: false | SupaToolbarPluginConfig;
116
+ }
117
+ interface FeatureContext {
118
+ [key: string]: string | number | boolean | null | undefined;
119
+ }
120
+ interface NetworkConfig {
121
+ /**
122
+ * Fully-qualified URL to the features evaluation endpoint.
123
+ * Example: "https://edge.supaship.com/v1/features"
124
+ */
125
+ featuresAPIUrl?: string;
126
+ /**
127
+ * Fully-qualified URL to the events/analytics endpoint.
128
+ * Example: "https://edge.supaship.com/v1/events"
129
+ */
130
+ eventsAPIUrl?: string;
131
+ /**
132
+ * Retry behavior for network requests (exponential backoff).
133
+ */
134
+ retry?: RetryConfig;
135
+ /**
136
+ * Request timeout in milliseconds. If provided, requests will be aborted after this duration.
137
+ */
138
+ requestTimeoutMs?: number;
139
+ /**
140
+ * Optional fetch implementation to use (e.g., node-fetch for Node < 18).
141
+ */
142
+ fetchFn?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
143
+ }
144
+ interface RetryConfig {
145
+ enabled?: boolean;
146
+ maxAttempts?: number;
147
+ backoff?: number;
148
+ }
149
+ /**
150
+ * Supported feature flag value types.
151
+ * - boolean: true/false flags
152
+ * - object: structured configuration data
153
+ * - array: lists of items
154
+ * - null: disabled/empty state
155
+ */
156
+ type FeatureValue = boolean | null | Record<string, unknown> | unknown[];
157
+ /**
158
+ * Widens boolean literals to boolean type while preserving other types.
159
+ * This allows `false` and `true` to be inferred as `boolean` for better ergonomics.
160
+ * @internal
161
+ */
162
+ type WidenFeatureValue<T> = T extends boolean ? boolean : T extends readonly unknown[] ? T extends readonly (infer U)[] ? U[] : T : T;
163
+ /**
164
+ * Widens all feature values in a features object.
165
+ * @internal
166
+ */
167
+ type WidenFeatures<T extends Record<string, FeatureValue>> = {
168
+ [K in keyof T]: WidenFeatureValue<T[K]>;
169
+ };
170
+ /**
171
+ * ⚠️ IMPORTANT: Use with `satisfies` operator, NOT type annotation
172
+ *
173
+ * Type representing feature flag definitions with their fallback values.
174
+ * Used to configure the SupaClient with feature flags.
175
+ *
176
+ * **Why `satisfies` over type annotation:**
177
+ * - ✅ `satisfies` preserves exact types ('feature-flag' stays 'feature-flag')
178
+ * - ❌ Type annotation widens types ('feature-flag' becomes string)
179
+ *
180
+ * Supported feature value types:
181
+ * - boolean: simple on/off flags
182
+ * - object: structured configuration data
183
+ * - array: lists of values
184
+ * - null: disabled state
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * import { FeaturesWithFallbacks } from '@supashiphq/javascript-sdk'
189
+ *
190
+ * // ✅ RECOMMENDED: satisfies ✅
191
+ * const features = {
192
+ * 'dark-mode': false,
193
+ * 'ui-config': {
194
+ * theme: 'light' as const,
195
+ * showWelcome: true,
196
+ * },
197
+ * } satisfies FeaturesWithFallbacks
198
+ *
199
+ * // ❌ AVOID: Type annotation ❌
200
+ * const features: FeaturesWithFallbacks = {
201
+ * 'dark-mode': false,
202
+ * 'ui-config': {
203
+ * theme: 'light',
204
+ * showWelcome: true,
205
+ * },
206
+ * }
207
+ * ```
208
+ */
209
+ type FeaturesWithFallbacks = Record<string, FeatureValue>;
210
+ /**
211
+ * Type alias for widened feature definitions.
212
+ * This is the type that gets stored and used internally.
213
+ */
214
+ type Features<T extends FeaturesWithFallbacks> = WidenFeatures<T>;
215
+
216
+ declare class SupaClient<TFeatures extends FeaturesWithFallbacks> {
217
+ private apiKey;
218
+ private environment;
219
+ private defaultContext?;
220
+ private plugins;
221
+ private featureDefinitions;
222
+ private clientId;
223
+ private fetchImpl;
224
+ private networkConfig;
225
+ constructor(config: SupaClientConfig & {
226
+ features: TFeatures;
227
+ });
228
+ /**
229
+ * Generate a unique client ID
230
+ */
231
+ private generateClientId;
232
+ /**
233
+ * Initialize plugins with automatic toolbar plugin in browser environments
234
+ */
235
+ private initializePlugins;
236
+ /**
237
+ * Updates the default context for the client
238
+ * @param context - New context to merge with or replace the existing context
239
+ * @param mergeWithExisting - Whether to merge with existing context (default: true)
240
+ */
241
+ updateContext(context: FeatureContext, mergeWithExisting?: boolean): void;
242
+ /**
243
+ * Gets the current default context
244
+ */
245
+ getContext(): FeatureContext | undefined;
246
+ /**
247
+ * Gets the fallback value for a feature from its definition
248
+ */
249
+ getFeatureFallback<TKey extends keyof TFeatures>(featureName: TKey): Features<TFeatures>[TKey];
250
+ private getVariationValue;
251
+ getFeature<TKey extends keyof TFeatures>(featureName: TKey, options?: {
252
+ context?: FeatureContext;
253
+ }): Promise<Features<TFeatures>[TKey]>;
254
+ getFeatures<TKeys extends readonly (keyof TFeatures)[]>(featureNames: TKeys, options?: {
255
+ context?: FeatureContext;
256
+ }): Promise<{
257
+ [K in TKeys[number]]: Features<TFeatures>[K];
258
+ }>;
259
+ }
260
+
261
+ export { type FeatureContext, type FeatureValue, type Features, type FeaturesWithFallbacks, type NetworkConfig, type RetryConfig, SupaClient, type SupaClientConfig, type SupaPlugin, type SupaPluginConfig, type SupaToolbarOverrideChange, type SupaToolbarOverrideChangeCallback, type SupaToolbarPluginConfig, type SupaToolbarPosition, SupaToolbarPlugin as ToolbarPlugin, type WidenFeatureValue, type WidenFeatures };
@@ -0,0 +1,261 @@
1
+ interface SupaPluginConfig {
2
+ enabled?: boolean;
3
+ }
4
+ interface Plugin {
5
+ name: string;
6
+ }
7
+ interface SupaPlugin extends Plugin {
8
+ onInit?(params: {
9
+ clientId: string;
10
+ availableFeatures: Record<string, FeatureValue>;
11
+ context?: FeatureContext;
12
+ }): Promise<void> | void;
13
+ beforeGetFeatures?(featureNames: string[], context?: FeatureContext): Promise<void>;
14
+ afterGetFeatures?(results: Record<string, FeatureValue>, context?: FeatureContext): Promise<void>;
15
+ onError?(error: Error, context?: FeatureContext): Promise<void>;
16
+ beforeRequest?(url: string, body: unknown, headers: Record<string, string>): Promise<void>;
17
+ afterResponse?(response: Response, timing: {
18
+ duration: number;
19
+ }): Promise<void>;
20
+ onContextUpdate?(oldContext: FeatureContext | undefined, newContext: FeatureContext, source: 'updateContext' | 'request'): Promise<void>;
21
+ onRetryAttempt?(attempt: number, error: Error, willRetry: boolean): Promise<void>;
22
+ onFallbackUsed?(featureName: string, fallbackValue: FeatureValue, reason: Error): Promise<void>;
23
+ }
24
+
25
+ interface SupaToolbarPosition {
26
+ placement?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
27
+ offset?: {
28
+ x: string;
29
+ y: string;
30
+ };
31
+ }
32
+ type SupaToolbarOverrideChange = {
33
+ feature: string;
34
+ value: FeatureValue;
35
+ };
36
+ type SupaToolbarOverrideChangeCallback = (featureOverride: SupaToolbarOverrideChange, allOverrides: Record<string, FeatureValue>) => void;
37
+ interface SupaToolbarPluginConfig extends Omit<SupaPluginConfig, 'enabled'> {
38
+ enabled?: boolean | 'auto';
39
+ position?: SupaToolbarPosition;
40
+ onOverrideChange?: SupaToolbarOverrideChangeCallback;
41
+ }
42
+ /**
43
+ * Toolbar plugin for local feature flag testing
44
+ * Provides a visual interface to override feature flags during development
45
+ */
46
+ declare class SupaToolbarPlugin implements SupaPlugin {
47
+ name: string;
48
+ private config;
49
+ private state;
50
+ private clientId?;
51
+ private storageKey;
52
+ constructor(config?: SupaToolbarPluginConfig);
53
+ cleanup(): void;
54
+ private shouldShowToolbar;
55
+ onInit(params: {
56
+ availableFeatures: Record<string, FeatureValue>;
57
+ context?: FeatureContext;
58
+ clientId: string;
59
+ }): void;
60
+ beforeGetFeatures(_featureNames: string[], context?: FeatureContext): Promise<void>;
61
+ afterGetFeatures(results: Record<string, FeatureValue>, context?: FeatureContext): Promise<void>;
62
+ private loadOverrides;
63
+ private saveOverrides;
64
+ setOverride(featureName: string, value: FeatureValue): void;
65
+ removeOverride(featureName: string): void;
66
+ clearAllOverrides(): void;
67
+ getOverrides(): Record<string, FeatureValue>;
68
+ private injectToolbar;
69
+ private removeToolbar;
70
+ private getToolbarHTML;
71
+ private injectStyles;
72
+ private attachEventListeners;
73
+ private updateToolbarUI;
74
+ private escapeHtml;
75
+ }
76
+
77
+ interface SupaClientConfig {
78
+ /**
79
+ * API key used to authenticate requests to Supaship services.
80
+ * Typically created in your project settings.
81
+ */
82
+ apiKey: string;
83
+ /**
84
+ * Environment identifier used for feature flag evaluation (e.g. "production", "staging").
85
+ */
86
+ environment: string;
87
+ /**
88
+ * Feature definitions with their fallback values.
89
+ * Use `satisfies FeaturesWithFallbacks` for type safety.
90
+ * Defines all feature flags used in the application.
91
+ */
92
+ features: FeaturesWithFallbacks;
93
+ /**
94
+ * Default context included with every feature evaluation request.
95
+ * Can be merged/overridden per-call via options.context.
96
+ */
97
+ context: FeatureContext;
98
+ /**
99
+ * Optional network configuration allowing you to override API endpoints.
100
+ * If omitted, defaults are used.
101
+ */
102
+ networkConfig?: NetworkConfig;
103
+ /**
104
+ * Optional plugins to observe or augment client behavior.
105
+ */
106
+ plugins?: SupaPlugin[];
107
+ /**
108
+ * Toolbar plugin configuration (browser only).
109
+ * - `false`: Disable toolbar (opt-out)
110
+ * - `undefined`: Enable with defaults (enabled: 'auto')
111
+ * - `object`: Custom configuration
112
+ *
113
+ * Default: Enabled in browser with 'auto' mode (shows only on localhost)
114
+ */
115
+ toolbar?: false | SupaToolbarPluginConfig;
116
+ }
117
+ interface FeatureContext {
118
+ [key: string]: string | number | boolean | null | undefined;
119
+ }
120
+ interface NetworkConfig {
121
+ /**
122
+ * Fully-qualified URL to the features evaluation endpoint.
123
+ * Example: "https://edge.supaship.com/v1/features"
124
+ */
125
+ featuresAPIUrl?: string;
126
+ /**
127
+ * Fully-qualified URL to the events/analytics endpoint.
128
+ * Example: "https://edge.supaship.com/v1/events"
129
+ */
130
+ eventsAPIUrl?: string;
131
+ /**
132
+ * Retry behavior for network requests (exponential backoff).
133
+ */
134
+ retry?: RetryConfig;
135
+ /**
136
+ * Request timeout in milliseconds. If provided, requests will be aborted after this duration.
137
+ */
138
+ requestTimeoutMs?: number;
139
+ /**
140
+ * Optional fetch implementation to use (e.g., node-fetch for Node < 18).
141
+ */
142
+ fetchFn?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
143
+ }
144
+ interface RetryConfig {
145
+ enabled?: boolean;
146
+ maxAttempts?: number;
147
+ backoff?: number;
148
+ }
149
+ /**
150
+ * Supported feature flag value types.
151
+ * - boolean: true/false flags
152
+ * - object: structured configuration data
153
+ * - array: lists of items
154
+ * - null: disabled/empty state
155
+ */
156
+ type FeatureValue = boolean | null | Record<string, unknown> | unknown[];
157
+ /**
158
+ * Widens boolean literals to boolean type while preserving other types.
159
+ * This allows `false` and `true` to be inferred as `boolean` for better ergonomics.
160
+ * @internal
161
+ */
162
+ type WidenFeatureValue<T> = T extends boolean ? boolean : T extends readonly unknown[] ? T extends readonly (infer U)[] ? U[] : T : T;
163
+ /**
164
+ * Widens all feature values in a features object.
165
+ * @internal
166
+ */
167
+ type WidenFeatures<T extends Record<string, FeatureValue>> = {
168
+ [K in keyof T]: WidenFeatureValue<T[K]>;
169
+ };
170
+ /**
171
+ * ⚠️ IMPORTANT: Use with `satisfies` operator, NOT type annotation
172
+ *
173
+ * Type representing feature flag definitions with their fallback values.
174
+ * Used to configure the SupaClient with feature flags.
175
+ *
176
+ * **Why `satisfies` over type annotation:**
177
+ * - ✅ `satisfies` preserves exact types ('feature-flag' stays 'feature-flag')
178
+ * - ❌ Type annotation widens types ('feature-flag' becomes string)
179
+ *
180
+ * Supported feature value types:
181
+ * - boolean: simple on/off flags
182
+ * - object: structured configuration data
183
+ * - array: lists of values
184
+ * - null: disabled state
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * import { FeaturesWithFallbacks } from '@supashiphq/javascript-sdk'
189
+ *
190
+ * // ✅ RECOMMENDED: satisfies ✅
191
+ * const features = {
192
+ * 'dark-mode': false,
193
+ * 'ui-config': {
194
+ * theme: 'light' as const,
195
+ * showWelcome: true,
196
+ * },
197
+ * } satisfies FeaturesWithFallbacks
198
+ *
199
+ * // ❌ AVOID: Type annotation ❌
200
+ * const features: FeaturesWithFallbacks = {
201
+ * 'dark-mode': false,
202
+ * 'ui-config': {
203
+ * theme: 'light',
204
+ * showWelcome: true,
205
+ * },
206
+ * }
207
+ * ```
208
+ */
209
+ type FeaturesWithFallbacks = Record<string, FeatureValue>;
210
+ /**
211
+ * Type alias for widened feature definitions.
212
+ * This is the type that gets stored and used internally.
213
+ */
214
+ type Features<T extends FeaturesWithFallbacks> = WidenFeatures<T>;
215
+
216
+ declare class SupaClient<TFeatures extends FeaturesWithFallbacks> {
217
+ private apiKey;
218
+ private environment;
219
+ private defaultContext?;
220
+ private plugins;
221
+ private featureDefinitions;
222
+ private clientId;
223
+ private fetchImpl;
224
+ private networkConfig;
225
+ constructor(config: SupaClientConfig & {
226
+ features: TFeatures;
227
+ });
228
+ /**
229
+ * Generate a unique client ID
230
+ */
231
+ private generateClientId;
232
+ /**
233
+ * Initialize plugins with automatic toolbar plugin in browser environments
234
+ */
235
+ private initializePlugins;
236
+ /**
237
+ * Updates the default context for the client
238
+ * @param context - New context to merge with or replace the existing context
239
+ * @param mergeWithExisting - Whether to merge with existing context (default: true)
240
+ */
241
+ updateContext(context: FeatureContext, mergeWithExisting?: boolean): void;
242
+ /**
243
+ * Gets the current default context
244
+ */
245
+ getContext(): FeatureContext | undefined;
246
+ /**
247
+ * Gets the fallback value for a feature from its definition
248
+ */
249
+ getFeatureFallback<TKey extends keyof TFeatures>(featureName: TKey): Features<TFeatures>[TKey];
250
+ private getVariationValue;
251
+ getFeature<TKey extends keyof TFeatures>(featureName: TKey, options?: {
252
+ context?: FeatureContext;
253
+ }): Promise<Features<TFeatures>[TKey]>;
254
+ getFeatures<TKeys extends readonly (keyof TFeatures)[]>(featureNames: TKeys, options?: {
255
+ context?: FeatureContext;
256
+ }): Promise<{
257
+ [K in TKeys[number]]: Features<TFeatures>[K];
258
+ }>;
259
+ }
260
+
261
+ export { type FeatureContext, type FeatureValue, type Features, type FeaturesWithFallbacks, type NetworkConfig, type RetryConfig, SupaClient, type SupaClientConfig, type SupaPlugin, type SupaPluginConfig, type SupaToolbarOverrideChange, type SupaToolbarOverrideChangeCallback, type SupaToolbarPluginConfig, type SupaToolbarPosition, SupaToolbarPlugin as ToolbarPlugin, type WidenFeatureValue, type WidenFeatures };