@savvagent/solid 1.0.0 → 1.0.1

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/index.d.mts CHANGED
@@ -1,10 +1,39 @@
1
1
  import * as solid_js from 'solid-js';
2
2
  import { ParentProps, Accessor } from 'solid-js';
3
3
  import { FlagClientConfig, FlagClient, FlagContext, FlagEvaluationResult } from '@savvagent/sdk';
4
- export { ApiTypes, ErrorEvent, EvaluationEvent, FlagClient, FlagClientConfig, FlagContext, FlagEvaluationResult, FlagUpdateEvent, components } from '@savvagent/sdk';
4
+ export { ApiTypes, ErrorEvent, EvaluationEvent, FlagClient, FlagClientConfig, FlagContext, FlagDefinition, FlagEvaluationResult, FlagUpdateEvent, components } from '@savvagent/sdk';
5
5
 
6
+ /**
7
+ * Default context values that apply to all flag evaluations
8
+ * Per SDK Developer Guide: https://docs.savvagent.com/sdk-developer-guide
9
+ */
10
+ interface DefaultFlagContext {
11
+ /** Application ID for application-scoped flags */
12
+ applicationId?: string;
13
+ /** Environment (development, staging, production) */
14
+ environment?: string;
15
+ /** Organization ID for multi-tenant apps */
16
+ organizationId?: string;
17
+ /** Default user ID (required for percentage rollouts) */
18
+ userId?: string;
19
+ /** Default anonymous ID (alternative to userId for anonymous users) */
20
+ anonymousId?: string;
21
+ /** Session ID as fallback identifier */
22
+ sessionId?: string;
23
+ /** User's language code (e.g., "en", "es") */
24
+ language?: string;
25
+ /** Default attributes for targeting */
26
+ attributes?: Record<string, any>;
27
+ }
28
+ interface SavvagentContextValue {
29
+ client: FlagClient;
30
+ isReady: Accessor<boolean>;
31
+ defaultContext: Accessor<FlagContext>;
32
+ }
6
33
  interface SavvagentProviderProps extends ParentProps {
7
34
  config: FlagClientConfig;
35
+ /** Default context values applied to all flag evaluations */
36
+ defaultContext?: DefaultFlagContext;
8
37
  }
9
38
  /**
10
39
  * Provider component that initializes and provides the Savvagent client.
@@ -15,7 +44,15 @@ interface SavvagentProviderProps extends ParentProps {
15
44
  *
16
45
  * function App() {
17
46
  * return (
18
- * <SavvagentProvider config={{ apiKey: 'sdk_...' }}>
47
+ * <SavvagentProvider
48
+ * config={{ apiKey: 'sdk_...' }}
49
+ * defaultContext={{
50
+ * applicationId: 'my-app-id',
51
+ * environment: 'development',
52
+ * userId: 'user-123',
53
+ * attributes: { plan: 'pro' }
54
+ * }}
55
+ * >
19
56
  * <MyApp />
20
57
  * </SavvagentProvider>
21
58
  * );
@@ -24,10 +61,10 @@ interface SavvagentProviderProps extends ParentProps {
24
61
  */
25
62
  declare function SavvagentProvider(props: SavvagentProviderProps): solid_js.JSX.Element;
26
63
  /**
27
- * Get the Savvagent client instance.
64
+ * Get the Savvagent context including client, ready state, and default context.
28
65
  * Must be used within a SavvagentProvider.
29
66
  *
30
- * @returns The FlagClient instance
67
+ * @returns The FlagClient instance, ready state accessor, and default context accessor
31
68
  * @throws Error if used outside of SavvagentProvider
32
69
  *
33
70
  * @example
@@ -35,13 +72,17 @@ declare function SavvagentProvider(props: SavvagentProviderProps): solid_js.JSX.
35
72
  * import { useSavvagent } from '@savvagent/solid';
36
73
  *
37
74
  * function MyComponent() {
38
- * const client = useSavvagent();
39
- * const enabled = await client.isEnabled('my-feature');
40
- * return <div>Enabled: {enabled}</div>;
75
+ * const { client, isReady, defaultContext } = useSavvagent();
76
+ *
77
+ * return (
78
+ * <Show when={isReady()}>
79
+ * <div>Client ready!</div>
80
+ * </Show>
81
+ * );
41
82
  * }
42
83
  * ```
43
84
  */
44
- declare function useSavvagent(): FlagClient;
85
+ declare function useSavvagent(): SavvagentContextValue;
45
86
  interface CreateFlagOptions {
46
87
  /** Context for flag evaluation */
47
88
  context?: FlagContext;
@@ -118,34 +159,178 @@ declare function createFlag(flagKey: string, options?: CreateFlagOptions): Creat
118
159
  * ```
119
160
  */
120
161
  declare function createFlagValue(flagKey: string, options?: CreateFlagOptions): Accessor<boolean>;
162
+ interface CreateFlagsOptions {
163
+ /** Context for flag evaluation */
164
+ context?: FlagContext;
165
+ /** Default values for flags (keyed by flag key) */
166
+ defaultValues?: Record<string, boolean>;
167
+ /** Enable real-time updates */
168
+ realtime?: boolean;
169
+ /** Custom error handler */
170
+ onError?: (error: Error, flagKey: string) => void;
171
+ }
172
+ interface CreateFlagsReturn {
173
+ /** Map of flag keys to their current values */
174
+ values: Accessor<Record<string, boolean>>;
175
+ /** Whether any flag is currently being evaluated */
176
+ loading: Accessor<boolean>;
177
+ /** Map of flag keys to their errors (if any) */
178
+ errors: Accessor<Record<string, Error | null>>;
179
+ /** Map of flag keys to their detailed evaluation results */
180
+ results: Accessor<Record<string, FlagEvaluationResult | null>>;
181
+ /** Force re-evaluation of all flags */
182
+ refetch: () => void;
183
+ }
121
184
  /**
122
- * Create signals for user identification.
185
+ * Create reactive flags for multiple flag keys with a single state update.
186
+ * This is more efficient than using multiple createFlag calls when you need
187
+ * several flags in the same component.
123
188
  *
124
- * @returns User ID management functions
189
+ * @param flagKeys - Array of feature flag keys to evaluate
190
+ * @param options - Configuration options
191
+ * @returns Reactive flag state for all flags
125
192
  *
126
193
  * @example
127
194
  * ```tsx
128
- * import { createUserSignals } from '@savvagent/solid';
195
+ * import { createFlags } from '@savvagent/solid';
196
+ * import { Show, For } from 'solid-js';
197
+ *
198
+ * function MyComponent() {
199
+ * const flags = createFlags(
200
+ * ['feature-a', 'feature-b', 'feature-c'],
201
+ * {
202
+ * context: { user_id: 'user-123' },
203
+ * defaultValues: { 'feature-a': false, 'feature-b': true },
204
+ * realtime: true
205
+ * }
206
+ * );
207
+ *
208
+ * return (
209
+ * <Show when={!flags.loading()} fallback={<Spinner />}>
210
+ * <div>
211
+ * <Show when={flags.values()['feature-a']}>
212
+ * <FeatureA />
213
+ * </Show>
214
+ * <Show when={flags.values()['feature-b']}>
215
+ * <FeatureB />
216
+ * </Show>
217
+ * </div>
218
+ * </Show>
219
+ * );
220
+ * }
221
+ * ```
222
+ */
223
+ declare function createFlags(flagKeys: string[], options?: CreateFlagsOptions): CreateFlagsReturn;
224
+ /**
225
+ * Execute a callback conditionally based on a flag value.
226
+ *
227
+ * @param flagKey - The feature flag key to check
228
+ * @param callback - Function to execute if flag is enabled
229
+ * @param options - Configuration options
230
+ *
231
+ * @example
232
+ * ```tsx
233
+ * import { createWithFlag } from '@savvagent/solid';
234
+ *
235
+ * function MyComponent() {
236
+ * createWithFlag('analytics-enabled', async () => {
237
+ * await trackEvent('page_view');
238
+ * });
239
+ *
240
+ * return <div>Content</div>;
241
+ * }
242
+ * ```
243
+ */
244
+ declare function createWithFlag(flagKey: string, callback: () => void | Promise<void>, options?: CreateFlagOptions): void;
245
+ interface CreateUserReturn {
246
+ /** Current user ID */
247
+ userId: Accessor<string | null>;
248
+ /** Set user ID */
249
+ setUserId: (id: string | null) => void;
250
+ /** Get current user ID from client */
251
+ getUserId: () => string | null;
252
+ /** Current anonymous ID */
253
+ anonymousId: Accessor<string | null>;
254
+ /** Set anonymous ID */
255
+ setAnonymousId: (id: string) => void;
256
+ /** Get current anonymous ID from client */
257
+ getAnonymousId: () => string | null;
258
+ }
259
+ /**
260
+ * Create signals for user identification management.
261
+ *
262
+ * @returns User ID management functions and reactive signals
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * import { createUser } from '@savvagent/solid';
129
267
  * import { createEffect } from 'solid-js';
130
268
  *
131
269
  * function AuthHandler() {
132
- * const [userId, setUserId] = createUserSignals();
270
+ * const user = createUser();
133
271
  *
134
272
  * createEffect(() => {
135
273
  * if (currentUser()) {
136
- * setUserId(currentUser().id);
274
+ * user.setUserId(currentUser().id);
137
275
  * } else {
138
- * setUserId(null);
276
+ * user.setUserId(null);
139
277
  * }
140
278
  * });
141
279
  *
142
- * return null;
280
+ * return <div>User ID: {user.userId()}</div>;
281
+ * }
282
+ * ```
283
+ */
284
+ declare function createUser(): CreateUserReturn;
285
+ /**
286
+ * Legacy function - use createUser() instead.
287
+ * Create signals for user identification.
288
+ *
289
+ * @returns User ID signal tuple [userId, setUserId]
290
+ * @deprecated Use createUser() for full user management
291
+ *
292
+ * @example
293
+ * ```tsx
294
+ * import { createUserSignals } from '@savvagent/solid';
295
+ *
296
+ * function AuthHandler() {
297
+ * const [userId, setUserId] = createUserSignals();
298
+ *
299
+ * return <div>User ID: {userId()}</div>;
143
300
  * }
144
301
  * ```
145
302
  */
146
303
  declare function createUserSignals(): readonly [Accessor<string | null>, (id: string | null) => void];
304
+ /**
305
+ * Create an error tracking function for a specific flag.
306
+ *
307
+ * @param flagKey - The flag key associated with errors
308
+ * @param context - Optional context
309
+ * @returns Error tracking function
310
+ *
311
+ * @example
312
+ * ```tsx
313
+ * import { createTrackError } from '@savvagent/solid';
314
+ *
315
+ * function FeatureComponent() {
316
+ * const trackError = createTrackError('new-feature');
317
+ *
318
+ * const handleAction = async () => {
319
+ * try {
320
+ * await doSomething();
321
+ * } catch (error) {
322
+ * trackError(error as Error);
323
+ * }
324
+ * };
325
+ *
326
+ * return <button onClick={handleAction}>Try Feature</button>;
327
+ * }
328
+ * ```
329
+ */
330
+ declare function createTrackError(flagKey: string, context?: FlagContext): (error: Error) => void;
147
331
  /**
148
332
  * Track an error with flag context.
333
+ * Direct function call (not reactive).
149
334
  *
150
335
  * @param flagKey - The flag key associated with the error
151
336
  * @param error - The error that occurred
@@ -170,4 +355,4 @@ declare function createUserSignals(): readonly [Accessor<string | null>, (id: st
170
355
  */
171
356
  declare function trackError(flagKey: string, error: Error, context?: FlagContext): void;
172
357
 
173
- export { type CreateFlagOptions, type CreateFlagReturn, SavvagentProvider, type SavvagentProviderProps, createFlag, createFlagValue, createUserSignals, trackError, useSavvagent };
358
+ export { type CreateFlagOptions, type CreateFlagReturn, type CreateFlagsOptions, type CreateFlagsReturn, type CreateUserReturn, type DefaultFlagContext, SavvagentProvider, type SavvagentProviderProps, createFlag, createFlagValue, createFlags, createTrackError, createUser, createUserSignals, createWithFlag, trackError, useSavvagent };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,39 @@
1
1
  import * as solid_js from 'solid-js';
2
2
  import { ParentProps, Accessor } from 'solid-js';
3
3
  import { FlagClientConfig, FlagClient, FlagContext, FlagEvaluationResult } from '@savvagent/sdk';
4
- export { ApiTypes, ErrorEvent, EvaluationEvent, FlagClient, FlagClientConfig, FlagContext, FlagEvaluationResult, FlagUpdateEvent, components } from '@savvagent/sdk';
4
+ export { ApiTypes, ErrorEvent, EvaluationEvent, FlagClient, FlagClientConfig, FlagContext, FlagDefinition, FlagEvaluationResult, FlagUpdateEvent, components } from '@savvagent/sdk';
5
5
 
6
+ /**
7
+ * Default context values that apply to all flag evaluations
8
+ * Per SDK Developer Guide: https://docs.savvagent.com/sdk-developer-guide
9
+ */
10
+ interface DefaultFlagContext {
11
+ /** Application ID for application-scoped flags */
12
+ applicationId?: string;
13
+ /** Environment (development, staging, production) */
14
+ environment?: string;
15
+ /** Organization ID for multi-tenant apps */
16
+ organizationId?: string;
17
+ /** Default user ID (required for percentage rollouts) */
18
+ userId?: string;
19
+ /** Default anonymous ID (alternative to userId for anonymous users) */
20
+ anonymousId?: string;
21
+ /** Session ID as fallback identifier */
22
+ sessionId?: string;
23
+ /** User's language code (e.g., "en", "es") */
24
+ language?: string;
25
+ /** Default attributes for targeting */
26
+ attributes?: Record<string, any>;
27
+ }
28
+ interface SavvagentContextValue {
29
+ client: FlagClient;
30
+ isReady: Accessor<boolean>;
31
+ defaultContext: Accessor<FlagContext>;
32
+ }
6
33
  interface SavvagentProviderProps extends ParentProps {
7
34
  config: FlagClientConfig;
35
+ /** Default context values applied to all flag evaluations */
36
+ defaultContext?: DefaultFlagContext;
8
37
  }
9
38
  /**
10
39
  * Provider component that initializes and provides the Savvagent client.
@@ -15,7 +44,15 @@ interface SavvagentProviderProps extends ParentProps {
15
44
  *
16
45
  * function App() {
17
46
  * return (
18
- * <SavvagentProvider config={{ apiKey: 'sdk_...' }}>
47
+ * <SavvagentProvider
48
+ * config={{ apiKey: 'sdk_...' }}
49
+ * defaultContext={{
50
+ * applicationId: 'my-app-id',
51
+ * environment: 'development',
52
+ * userId: 'user-123',
53
+ * attributes: { plan: 'pro' }
54
+ * }}
55
+ * >
19
56
  * <MyApp />
20
57
  * </SavvagentProvider>
21
58
  * );
@@ -24,10 +61,10 @@ interface SavvagentProviderProps extends ParentProps {
24
61
  */
25
62
  declare function SavvagentProvider(props: SavvagentProviderProps): solid_js.JSX.Element;
26
63
  /**
27
- * Get the Savvagent client instance.
64
+ * Get the Savvagent context including client, ready state, and default context.
28
65
  * Must be used within a SavvagentProvider.
29
66
  *
30
- * @returns The FlagClient instance
67
+ * @returns The FlagClient instance, ready state accessor, and default context accessor
31
68
  * @throws Error if used outside of SavvagentProvider
32
69
  *
33
70
  * @example
@@ -35,13 +72,17 @@ declare function SavvagentProvider(props: SavvagentProviderProps): solid_js.JSX.
35
72
  * import { useSavvagent } from '@savvagent/solid';
36
73
  *
37
74
  * function MyComponent() {
38
- * const client = useSavvagent();
39
- * const enabled = await client.isEnabled('my-feature');
40
- * return <div>Enabled: {enabled}</div>;
75
+ * const { client, isReady, defaultContext } = useSavvagent();
76
+ *
77
+ * return (
78
+ * <Show when={isReady()}>
79
+ * <div>Client ready!</div>
80
+ * </Show>
81
+ * );
41
82
  * }
42
83
  * ```
43
84
  */
44
- declare function useSavvagent(): FlagClient;
85
+ declare function useSavvagent(): SavvagentContextValue;
45
86
  interface CreateFlagOptions {
46
87
  /** Context for flag evaluation */
47
88
  context?: FlagContext;
@@ -118,34 +159,178 @@ declare function createFlag(flagKey: string, options?: CreateFlagOptions): Creat
118
159
  * ```
119
160
  */
120
161
  declare function createFlagValue(flagKey: string, options?: CreateFlagOptions): Accessor<boolean>;
162
+ interface CreateFlagsOptions {
163
+ /** Context for flag evaluation */
164
+ context?: FlagContext;
165
+ /** Default values for flags (keyed by flag key) */
166
+ defaultValues?: Record<string, boolean>;
167
+ /** Enable real-time updates */
168
+ realtime?: boolean;
169
+ /** Custom error handler */
170
+ onError?: (error: Error, flagKey: string) => void;
171
+ }
172
+ interface CreateFlagsReturn {
173
+ /** Map of flag keys to their current values */
174
+ values: Accessor<Record<string, boolean>>;
175
+ /** Whether any flag is currently being evaluated */
176
+ loading: Accessor<boolean>;
177
+ /** Map of flag keys to their errors (if any) */
178
+ errors: Accessor<Record<string, Error | null>>;
179
+ /** Map of flag keys to their detailed evaluation results */
180
+ results: Accessor<Record<string, FlagEvaluationResult | null>>;
181
+ /** Force re-evaluation of all flags */
182
+ refetch: () => void;
183
+ }
121
184
  /**
122
- * Create signals for user identification.
185
+ * Create reactive flags for multiple flag keys with a single state update.
186
+ * This is more efficient than using multiple createFlag calls when you need
187
+ * several flags in the same component.
123
188
  *
124
- * @returns User ID management functions
189
+ * @param flagKeys - Array of feature flag keys to evaluate
190
+ * @param options - Configuration options
191
+ * @returns Reactive flag state for all flags
125
192
  *
126
193
  * @example
127
194
  * ```tsx
128
- * import { createUserSignals } from '@savvagent/solid';
195
+ * import { createFlags } from '@savvagent/solid';
196
+ * import { Show, For } from 'solid-js';
197
+ *
198
+ * function MyComponent() {
199
+ * const flags = createFlags(
200
+ * ['feature-a', 'feature-b', 'feature-c'],
201
+ * {
202
+ * context: { user_id: 'user-123' },
203
+ * defaultValues: { 'feature-a': false, 'feature-b': true },
204
+ * realtime: true
205
+ * }
206
+ * );
207
+ *
208
+ * return (
209
+ * <Show when={!flags.loading()} fallback={<Spinner />}>
210
+ * <div>
211
+ * <Show when={flags.values()['feature-a']}>
212
+ * <FeatureA />
213
+ * </Show>
214
+ * <Show when={flags.values()['feature-b']}>
215
+ * <FeatureB />
216
+ * </Show>
217
+ * </div>
218
+ * </Show>
219
+ * );
220
+ * }
221
+ * ```
222
+ */
223
+ declare function createFlags(flagKeys: string[], options?: CreateFlagsOptions): CreateFlagsReturn;
224
+ /**
225
+ * Execute a callback conditionally based on a flag value.
226
+ *
227
+ * @param flagKey - The feature flag key to check
228
+ * @param callback - Function to execute if flag is enabled
229
+ * @param options - Configuration options
230
+ *
231
+ * @example
232
+ * ```tsx
233
+ * import { createWithFlag } from '@savvagent/solid';
234
+ *
235
+ * function MyComponent() {
236
+ * createWithFlag('analytics-enabled', async () => {
237
+ * await trackEvent('page_view');
238
+ * });
239
+ *
240
+ * return <div>Content</div>;
241
+ * }
242
+ * ```
243
+ */
244
+ declare function createWithFlag(flagKey: string, callback: () => void | Promise<void>, options?: CreateFlagOptions): void;
245
+ interface CreateUserReturn {
246
+ /** Current user ID */
247
+ userId: Accessor<string | null>;
248
+ /** Set user ID */
249
+ setUserId: (id: string | null) => void;
250
+ /** Get current user ID from client */
251
+ getUserId: () => string | null;
252
+ /** Current anonymous ID */
253
+ anonymousId: Accessor<string | null>;
254
+ /** Set anonymous ID */
255
+ setAnonymousId: (id: string) => void;
256
+ /** Get current anonymous ID from client */
257
+ getAnonymousId: () => string | null;
258
+ }
259
+ /**
260
+ * Create signals for user identification management.
261
+ *
262
+ * @returns User ID management functions and reactive signals
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * import { createUser } from '@savvagent/solid';
129
267
  * import { createEffect } from 'solid-js';
130
268
  *
131
269
  * function AuthHandler() {
132
- * const [userId, setUserId] = createUserSignals();
270
+ * const user = createUser();
133
271
  *
134
272
  * createEffect(() => {
135
273
  * if (currentUser()) {
136
- * setUserId(currentUser().id);
274
+ * user.setUserId(currentUser().id);
137
275
  * } else {
138
- * setUserId(null);
276
+ * user.setUserId(null);
139
277
  * }
140
278
  * });
141
279
  *
142
- * return null;
280
+ * return <div>User ID: {user.userId()}</div>;
281
+ * }
282
+ * ```
283
+ */
284
+ declare function createUser(): CreateUserReturn;
285
+ /**
286
+ * Legacy function - use createUser() instead.
287
+ * Create signals for user identification.
288
+ *
289
+ * @returns User ID signal tuple [userId, setUserId]
290
+ * @deprecated Use createUser() for full user management
291
+ *
292
+ * @example
293
+ * ```tsx
294
+ * import { createUserSignals } from '@savvagent/solid';
295
+ *
296
+ * function AuthHandler() {
297
+ * const [userId, setUserId] = createUserSignals();
298
+ *
299
+ * return <div>User ID: {userId()}</div>;
143
300
  * }
144
301
  * ```
145
302
  */
146
303
  declare function createUserSignals(): readonly [Accessor<string | null>, (id: string | null) => void];
304
+ /**
305
+ * Create an error tracking function for a specific flag.
306
+ *
307
+ * @param flagKey - The flag key associated with errors
308
+ * @param context - Optional context
309
+ * @returns Error tracking function
310
+ *
311
+ * @example
312
+ * ```tsx
313
+ * import { createTrackError } from '@savvagent/solid';
314
+ *
315
+ * function FeatureComponent() {
316
+ * const trackError = createTrackError('new-feature');
317
+ *
318
+ * const handleAction = async () => {
319
+ * try {
320
+ * await doSomething();
321
+ * } catch (error) {
322
+ * trackError(error as Error);
323
+ * }
324
+ * };
325
+ *
326
+ * return <button onClick={handleAction}>Try Feature</button>;
327
+ * }
328
+ * ```
329
+ */
330
+ declare function createTrackError(flagKey: string, context?: FlagContext): (error: Error) => void;
147
331
  /**
148
332
  * Track an error with flag context.
333
+ * Direct function call (not reactive).
149
334
  *
150
335
  * @param flagKey - The flag key associated with the error
151
336
  * @param error - The error that occurred
@@ -170,4 +355,4 @@ declare function createUserSignals(): readonly [Accessor<string | null>, (id: st
170
355
  */
171
356
  declare function trackError(flagKey: string, error: Error, context?: FlagContext): void;
172
357
 
173
- export { type CreateFlagOptions, type CreateFlagReturn, SavvagentProvider, type SavvagentProviderProps, createFlag, createFlagValue, createUserSignals, trackError, useSavvagent };
358
+ export { type CreateFlagOptions, type CreateFlagReturn, type CreateFlagsOptions, type CreateFlagsReturn, type CreateUserReturn, type DefaultFlagContext, SavvagentProvider, type SavvagentProviderProps, createFlag, createFlagValue, createFlags, createTrackError, createUser, createUserSignals, createWithFlag, trackError, useSavvagent };
package/dist/index.js CHANGED
@@ -24,31 +24,87 @@ __export(index_exports, {
24
24
  SavvagentProvider: () => SavvagentProvider,
25
25
  createFlag: () => createFlag,
26
26
  createFlagValue: () => createFlagValue,
27
+ createFlags: () => createFlags,
28
+ createTrackError: () => createTrackError,
29
+ createUser: () => createUser,
27
30
  createUserSignals: () => createUserSignals,
31
+ createWithFlag: () => createWithFlag,
28
32
  trackError: () => trackError,
29
33
  useSavvagent: () => useSavvagent
30
34
  });
31
35
  module.exports = __toCommonJS(index_exports);
36
+ var import_web = require("solid-js/web");
32
37
  var import_solid_js = require("solid-js");
33
38
  var import_sdk = require("@savvagent/sdk");
34
39
  var import_sdk2 = require("@savvagent/sdk");
35
40
  var SavvagentContext = (0, import_solid_js.createContext)();
36
41
  function SavvagentProvider(props) {
37
- const client = new import_sdk.FlagClient(props.config);
42
+ const [isReady, setIsReady] = (0, import_solid_js.createSignal)(false);
43
+ let client;
44
+ try {
45
+ client = new import_sdk.FlagClient(props.config);
46
+ setIsReady(true);
47
+ } catch (error) {
48
+ console.error("[Savvagent] Failed to initialize client:", error);
49
+ props.config.onError?.(error);
50
+ client = new import_sdk.FlagClient({
51
+ ...props.config,
52
+ apiKey: ""
53
+ });
54
+ }
55
+ const normalizedDefaultContext = (0, import_solid_js.createMemo)(() => ({
56
+ application_id: props.defaultContext?.applicationId,
57
+ environment: props.defaultContext?.environment,
58
+ organization_id: props.defaultContext?.organizationId,
59
+ user_id: props.defaultContext?.userId,
60
+ anonymous_id: props.defaultContext?.anonymousId,
61
+ session_id: props.defaultContext?.sessionId,
62
+ language: props.defaultContext?.language,
63
+ attributes: props.defaultContext?.attributes
64
+ }));
38
65
  (0, import_solid_js.onCleanup)(() => {
39
66
  client.close();
40
67
  });
41
- return /* @__PURE__ */ React.createElement(SavvagentContext.Provider, { value: client }, props.children);
68
+ const contextValue = {
69
+ client,
70
+ isReady,
71
+ defaultContext: normalizedDefaultContext
72
+ };
73
+ return (0, import_web.createComponent)(SavvagentContext.Provider, {
74
+ value: contextValue,
75
+ get children() {
76
+ return props.children;
77
+ }
78
+ });
42
79
  }
43
80
  function useSavvagent() {
44
- const client = (0, import_solid_js.useContext)(SavvagentContext);
45
- if (!client) {
81
+ const context = (0, import_solid_js.useContext)(SavvagentContext);
82
+ if (!context) {
46
83
  throw new Error("useSavvagent must be used within a SavvagentProvider");
47
84
  }
48
- return client;
85
+ return context;
86
+ }
87
+ function deepEqual(a, b) {
88
+ if (a === b) return true;
89
+ if (a === null || b === null) return a === b;
90
+ if (typeof a !== "object" || typeof b !== "object") return false;
91
+ const keysA = Object.keys(a);
92
+ const keysB = Object.keys(b);
93
+ if (keysA.length !== keysB.length) return false;
94
+ for (const key of keysA) {
95
+ if (!keysB.includes(key)) return false;
96
+ if (!deepEqual(a[key], b[key])) {
97
+ return false;
98
+ }
99
+ }
100
+ return true;
49
101
  }
50
102
  function createFlag(flagKey, options = {}) {
51
- const client = useSavvagent();
103
+ const {
104
+ client,
105
+ isReady,
106
+ defaultContext
107
+ } = useSavvagent();
52
108
  const {
53
109
  context,
54
110
  defaultValue = false,
@@ -56,23 +112,39 @@ function createFlag(flagKey, options = {}) {
56
112
  onError
57
113
  } = options;
58
114
  const [trigger, setTrigger] = (0, import_solid_js.createSignal)(0);
59
- const [result] = (0, import_solid_js.createResource)(
60
- trigger,
61
- async () => {
62
- try {
63
- return await client.evaluate(flagKey, context);
64
- } catch (err) {
65
- const error2 = err;
66
- onError?.(error2);
67
- throw error2;
115
+ const mergedContext = (0, import_solid_js.createMemo)(() => {
116
+ const def = defaultContext();
117
+ return {
118
+ ...def,
119
+ ...context,
120
+ attributes: {
121
+ ...def?.attributes,
122
+ ...context?.attributes
68
123
  }
124
+ };
125
+ });
126
+ let prevContext;
127
+ const [result] = (0, import_solid_js.createResource)(() => ({
128
+ trigger: trigger(),
129
+ context: mergedContext(),
130
+ ready: isReady()
131
+ }), async (source) => {
132
+ if (!source.ready) {
133
+ return null;
69
134
  }
70
- );
135
+ try {
136
+ return await client.evaluate(flagKey, source.context);
137
+ } catch (err) {
138
+ const error2 = err;
139
+ onError?.(error2);
140
+ throw error2;
141
+ }
142
+ });
71
143
  const value = () => result()?.value ?? defaultValue;
72
144
  const loading = () => result.loading;
73
145
  const error = () => result.error ?? null;
74
146
  (0, import_solid_js.createEffect)(() => {
75
- if (!realtime) return;
147
+ if (!realtime || !isReady()) return;
76
148
  const unsubscribe = client.subscribe(flagKey, () => {
77
149
  setTrigger((t) => t + 1);
78
150
  });
@@ -80,6 +152,22 @@ function createFlag(flagKey, options = {}) {
80
152
  unsubscribe();
81
153
  });
82
154
  });
155
+ (0, import_solid_js.createEffect)(() => {
156
+ if (!isReady()) return;
157
+ const unsubscribe = client.onOverrideChange(() => {
158
+ setTrigger((t) => t + 1);
159
+ });
160
+ (0, import_solid_js.onCleanup)(() => {
161
+ unsubscribe();
162
+ });
163
+ });
164
+ (0, import_solid_js.createEffect)(() => {
165
+ const currentContext = mergedContext();
166
+ if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
167
+ setTrigger((t) => t + 1);
168
+ }
169
+ prevContext = currentContext;
170
+ });
83
171
  return {
84
172
  value,
85
173
  loading,
@@ -92,8 +180,158 @@ function createFlagValue(flagKey, options = {}) {
92
180
  const flag = createFlag(flagKey, options);
93
181
  return flag.value;
94
182
  }
183
+ function createFlags(flagKeys, options = {}) {
184
+ const {
185
+ client,
186
+ isReady,
187
+ defaultContext
188
+ } = useSavvagent();
189
+ const {
190
+ context,
191
+ defaultValues = {},
192
+ realtime = true,
193
+ onError
194
+ } = options;
195
+ const [trigger, setTrigger] = (0, import_solid_js.createSignal)(0);
196
+ const mergedContext = (0, import_solid_js.createMemo)(() => {
197
+ const def = defaultContext();
198
+ return {
199
+ ...def,
200
+ ...context,
201
+ attributes: {
202
+ ...def?.attributes,
203
+ ...context?.attributes
204
+ }
205
+ };
206
+ });
207
+ const initialValues = {};
208
+ const initialErrors = {};
209
+ const initialResults = {};
210
+ for (const key of flagKeys) {
211
+ initialValues[key] = defaultValues[key] ?? false;
212
+ initialErrors[key] = null;
213
+ initialResults[key] = null;
214
+ }
215
+ const [values, setValues] = (0, import_solid_js.createSignal)(initialValues);
216
+ const [errors, setErrors] = (0, import_solid_js.createSignal)(initialErrors);
217
+ const [results, setResults] = (0, import_solid_js.createSignal)(initialResults);
218
+ const [loading, setLoading] = (0, import_solid_js.createSignal)(true);
219
+ let prevContext;
220
+ const evaluateFlags = async () => {
221
+ if (!isReady()) return;
222
+ setLoading(true);
223
+ const newValues = {};
224
+ const newErrors = {};
225
+ const newResults = {};
226
+ const ctx = mergedContext();
227
+ await Promise.all(flagKeys.map(async (flagKey) => {
228
+ try {
229
+ const evalResult = await client.evaluate(flagKey, ctx);
230
+ newValues[flagKey] = evalResult.value;
231
+ newErrors[flagKey] = null;
232
+ newResults[flagKey] = evalResult;
233
+ } catch (err) {
234
+ const error = err;
235
+ newValues[flagKey] = defaultValues[flagKey] ?? false;
236
+ newErrors[flagKey] = error;
237
+ newResults[flagKey] = null;
238
+ onError?.(error, flagKey);
239
+ }
240
+ }));
241
+ setValues(newValues);
242
+ setErrors(newErrors);
243
+ setResults(newResults);
244
+ setLoading(false);
245
+ };
246
+ (0, import_solid_js.createEffect)(() => {
247
+ trigger();
248
+ if (isReady()) {
249
+ evaluateFlags();
250
+ }
251
+ });
252
+ (0, import_solid_js.createEffect)(() => {
253
+ if (!realtime || !isReady()) return;
254
+ const unsubscribes = flagKeys.map((flagKey) => client.subscribe(flagKey, () => {
255
+ setTrigger((t) => t + 1);
256
+ }));
257
+ (0, import_solid_js.onCleanup)(() => {
258
+ unsubscribes.forEach((unsubscribe) => unsubscribe());
259
+ });
260
+ });
261
+ (0, import_solid_js.createEffect)(() => {
262
+ if (!isReady()) return;
263
+ const unsubscribe = client.onOverrideChange(() => {
264
+ setTrigger((t) => t + 1);
265
+ });
266
+ (0, import_solid_js.onCleanup)(() => {
267
+ unsubscribe();
268
+ });
269
+ });
270
+ (0, import_solid_js.createEffect)(() => {
271
+ const currentContext = mergedContext();
272
+ if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
273
+ setTrigger((t) => t + 1);
274
+ }
275
+ prevContext = currentContext;
276
+ });
277
+ return {
278
+ values,
279
+ loading,
280
+ errors,
281
+ results,
282
+ refetch: () => setTrigger((t) => t + 1)
283
+ };
284
+ }
285
+ function createWithFlag(flagKey, callback, options = {}) {
286
+ const {
287
+ client,
288
+ isReady
289
+ } = useSavvagent();
290
+ const {
291
+ context,
292
+ onError
293
+ } = options;
294
+ (0, import_solid_js.createEffect)(() => {
295
+ if (!isReady()) return;
296
+ client.withFlag(flagKey, callback, context).catch((error) => {
297
+ console.error(`[Savvagent] Error in withFlag callback for ${flagKey}:`, error);
298
+ onError?.(error);
299
+ });
300
+ });
301
+ }
302
+ function createUser() {
303
+ const {
304
+ client
305
+ } = useSavvagent();
306
+ const [userId, setUserIdSignal] = (0, import_solid_js.createSignal)(client.getUserId());
307
+ const [anonymousId, setAnonymousIdSignal] = (0, import_solid_js.createSignal)(client.getAnonymousId());
308
+ const setUserId = (id) => {
309
+ client.setUserId(id);
310
+ setUserIdSignal(id);
311
+ };
312
+ const getUserId = () => {
313
+ return client.getUserId();
314
+ };
315
+ const setAnonymousId = (id) => {
316
+ client.setAnonymousId(id);
317
+ setAnonymousIdSignal(id);
318
+ };
319
+ const getAnonymousId = () => {
320
+ return client.getAnonymousId();
321
+ };
322
+ return {
323
+ userId,
324
+ setUserId,
325
+ getUserId,
326
+ anonymousId,
327
+ setAnonymousId,
328
+ getAnonymousId
329
+ };
330
+ }
95
331
  function createUserSignals() {
96
- const client = useSavvagent();
332
+ const {
333
+ client
334
+ } = useSavvagent();
97
335
  const [userId, setUserIdSignal] = (0, import_solid_js.createSignal)(client.getUserId());
98
336
  const setUserId = (id) => {
99
337
  client.setUserId(id);
@@ -101,8 +339,18 @@ function createUserSignals() {
101
339
  };
102
340
  return [userId, setUserId];
103
341
  }
342
+ function createTrackError(flagKey, context) {
343
+ const {
344
+ client
345
+ } = useSavvagent();
346
+ return (error) => {
347
+ client.trackError(flagKey, error, context);
348
+ };
349
+ }
104
350
  function trackError(flagKey, error, context) {
105
- const client = useSavvagent();
351
+ const {
352
+ client
353
+ } = useSavvagent();
106
354
  client.trackError(flagKey, error, context);
107
355
  }
108
356
  // Annotate the CommonJS export names for ESM import in node:
@@ -111,7 +359,11 @@ function trackError(flagKey, error, context) {
111
359
  SavvagentProvider,
112
360
  createFlag,
113
361
  createFlagValue,
362
+ createFlags,
363
+ createTrackError,
364
+ createUser,
114
365
  createUserSignals,
366
+ createWithFlag,
115
367
  trackError,
116
368
  useSavvagent
117
369
  });
package/dist/index.mjs CHANGED
@@ -1,31 +1,76 @@
1
1
  // src/index.tsx
2
- import {
3
- createContext,
4
- useContext,
5
- createSignal,
6
- createResource,
7
- createEffect,
8
- onCleanup
9
- } from "solid-js";
2
+ import { createComponent as _$createComponent } from "solid-js/web";
3
+ import { createContext, useContext, createSignal, createResource, createEffect, createMemo, onCleanup } from "solid-js";
10
4
  import { FlagClient } from "@savvagent/sdk";
11
5
  import { FlagClient as FlagClient2 } from "@savvagent/sdk";
12
6
  var SavvagentContext = createContext();
13
7
  function SavvagentProvider(props) {
14
- const client = new FlagClient(props.config);
8
+ const [isReady, setIsReady] = createSignal(false);
9
+ let client;
10
+ try {
11
+ client = new FlagClient(props.config);
12
+ setIsReady(true);
13
+ } catch (error) {
14
+ console.error("[Savvagent] Failed to initialize client:", error);
15
+ props.config.onError?.(error);
16
+ client = new FlagClient({
17
+ ...props.config,
18
+ apiKey: ""
19
+ });
20
+ }
21
+ const normalizedDefaultContext = createMemo(() => ({
22
+ application_id: props.defaultContext?.applicationId,
23
+ environment: props.defaultContext?.environment,
24
+ organization_id: props.defaultContext?.organizationId,
25
+ user_id: props.defaultContext?.userId,
26
+ anonymous_id: props.defaultContext?.anonymousId,
27
+ session_id: props.defaultContext?.sessionId,
28
+ language: props.defaultContext?.language,
29
+ attributes: props.defaultContext?.attributes
30
+ }));
15
31
  onCleanup(() => {
16
32
  client.close();
17
33
  });
18
- return /* @__PURE__ */ React.createElement(SavvagentContext.Provider, { value: client }, props.children);
34
+ const contextValue = {
35
+ client,
36
+ isReady,
37
+ defaultContext: normalizedDefaultContext
38
+ };
39
+ return _$createComponent(SavvagentContext.Provider, {
40
+ value: contextValue,
41
+ get children() {
42
+ return props.children;
43
+ }
44
+ });
19
45
  }
20
46
  function useSavvagent() {
21
- const client = useContext(SavvagentContext);
22
- if (!client) {
47
+ const context = useContext(SavvagentContext);
48
+ if (!context) {
23
49
  throw new Error("useSavvagent must be used within a SavvagentProvider");
24
50
  }
25
- return client;
51
+ return context;
52
+ }
53
+ function deepEqual(a, b) {
54
+ if (a === b) return true;
55
+ if (a === null || b === null) return a === b;
56
+ if (typeof a !== "object" || typeof b !== "object") return false;
57
+ const keysA = Object.keys(a);
58
+ const keysB = Object.keys(b);
59
+ if (keysA.length !== keysB.length) return false;
60
+ for (const key of keysA) {
61
+ if (!keysB.includes(key)) return false;
62
+ if (!deepEqual(a[key], b[key])) {
63
+ return false;
64
+ }
65
+ }
66
+ return true;
26
67
  }
27
68
  function createFlag(flagKey, options = {}) {
28
- const client = useSavvagent();
69
+ const {
70
+ client,
71
+ isReady,
72
+ defaultContext
73
+ } = useSavvagent();
29
74
  const {
30
75
  context,
31
76
  defaultValue = false,
@@ -33,23 +78,39 @@ function createFlag(flagKey, options = {}) {
33
78
  onError
34
79
  } = options;
35
80
  const [trigger, setTrigger] = createSignal(0);
36
- const [result] = createResource(
37
- trigger,
38
- async () => {
39
- try {
40
- return await client.evaluate(flagKey, context);
41
- } catch (err) {
42
- const error2 = err;
43
- onError?.(error2);
44
- throw error2;
81
+ const mergedContext = createMemo(() => {
82
+ const def = defaultContext();
83
+ return {
84
+ ...def,
85
+ ...context,
86
+ attributes: {
87
+ ...def?.attributes,
88
+ ...context?.attributes
45
89
  }
90
+ };
91
+ });
92
+ let prevContext;
93
+ const [result] = createResource(() => ({
94
+ trigger: trigger(),
95
+ context: mergedContext(),
96
+ ready: isReady()
97
+ }), async (source) => {
98
+ if (!source.ready) {
99
+ return null;
46
100
  }
47
- );
101
+ try {
102
+ return await client.evaluate(flagKey, source.context);
103
+ } catch (err) {
104
+ const error2 = err;
105
+ onError?.(error2);
106
+ throw error2;
107
+ }
108
+ });
48
109
  const value = () => result()?.value ?? defaultValue;
49
110
  const loading = () => result.loading;
50
111
  const error = () => result.error ?? null;
51
112
  createEffect(() => {
52
- if (!realtime) return;
113
+ if (!realtime || !isReady()) return;
53
114
  const unsubscribe = client.subscribe(flagKey, () => {
54
115
  setTrigger((t) => t + 1);
55
116
  });
@@ -57,6 +118,22 @@ function createFlag(flagKey, options = {}) {
57
118
  unsubscribe();
58
119
  });
59
120
  });
121
+ createEffect(() => {
122
+ if (!isReady()) return;
123
+ const unsubscribe = client.onOverrideChange(() => {
124
+ setTrigger((t) => t + 1);
125
+ });
126
+ onCleanup(() => {
127
+ unsubscribe();
128
+ });
129
+ });
130
+ createEffect(() => {
131
+ const currentContext = mergedContext();
132
+ if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
133
+ setTrigger((t) => t + 1);
134
+ }
135
+ prevContext = currentContext;
136
+ });
60
137
  return {
61
138
  value,
62
139
  loading,
@@ -69,8 +146,158 @@ function createFlagValue(flagKey, options = {}) {
69
146
  const flag = createFlag(flagKey, options);
70
147
  return flag.value;
71
148
  }
149
+ function createFlags(flagKeys, options = {}) {
150
+ const {
151
+ client,
152
+ isReady,
153
+ defaultContext
154
+ } = useSavvagent();
155
+ const {
156
+ context,
157
+ defaultValues = {},
158
+ realtime = true,
159
+ onError
160
+ } = options;
161
+ const [trigger, setTrigger] = createSignal(0);
162
+ const mergedContext = createMemo(() => {
163
+ const def = defaultContext();
164
+ return {
165
+ ...def,
166
+ ...context,
167
+ attributes: {
168
+ ...def?.attributes,
169
+ ...context?.attributes
170
+ }
171
+ };
172
+ });
173
+ const initialValues = {};
174
+ const initialErrors = {};
175
+ const initialResults = {};
176
+ for (const key of flagKeys) {
177
+ initialValues[key] = defaultValues[key] ?? false;
178
+ initialErrors[key] = null;
179
+ initialResults[key] = null;
180
+ }
181
+ const [values, setValues] = createSignal(initialValues);
182
+ const [errors, setErrors] = createSignal(initialErrors);
183
+ const [results, setResults] = createSignal(initialResults);
184
+ const [loading, setLoading] = createSignal(true);
185
+ let prevContext;
186
+ const evaluateFlags = async () => {
187
+ if (!isReady()) return;
188
+ setLoading(true);
189
+ const newValues = {};
190
+ const newErrors = {};
191
+ const newResults = {};
192
+ const ctx = mergedContext();
193
+ await Promise.all(flagKeys.map(async (flagKey) => {
194
+ try {
195
+ const evalResult = await client.evaluate(flagKey, ctx);
196
+ newValues[flagKey] = evalResult.value;
197
+ newErrors[flagKey] = null;
198
+ newResults[flagKey] = evalResult;
199
+ } catch (err) {
200
+ const error = err;
201
+ newValues[flagKey] = defaultValues[flagKey] ?? false;
202
+ newErrors[flagKey] = error;
203
+ newResults[flagKey] = null;
204
+ onError?.(error, flagKey);
205
+ }
206
+ }));
207
+ setValues(newValues);
208
+ setErrors(newErrors);
209
+ setResults(newResults);
210
+ setLoading(false);
211
+ };
212
+ createEffect(() => {
213
+ trigger();
214
+ if (isReady()) {
215
+ evaluateFlags();
216
+ }
217
+ });
218
+ createEffect(() => {
219
+ if (!realtime || !isReady()) return;
220
+ const unsubscribes = flagKeys.map((flagKey) => client.subscribe(flagKey, () => {
221
+ setTrigger((t) => t + 1);
222
+ }));
223
+ onCleanup(() => {
224
+ unsubscribes.forEach((unsubscribe) => unsubscribe());
225
+ });
226
+ });
227
+ createEffect(() => {
228
+ if (!isReady()) return;
229
+ const unsubscribe = client.onOverrideChange(() => {
230
+ setTrigger((t) => t + 1);
231
+ });
232
+ onCleanup(() => {
233
+ unsubscribe();
234
+ });
235
+ });
236
+ createEffect(() => {
237
+ const currentContext = mergedContext();
238
+ if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
239
+ setTrigger((t) => t + 1);
240
+ }
241
+ prevContext = currentContext;
242
+ });
243
+ return {
244
+ values,
245
+ loading,
246
+ errors,
247
+ results,
248
+ refetch: () => setTrigger((t) => t + 1)
249
+ };
250
+ }
251
+ function createWithFlag(flagKey, callback, options = {}) {
252
+ const {
253
+ client,
254
+ isReady
255
+ } = useSavvagent();
256
+ const {
257
+ context,
258
+ onError
259
+ } = options;
260
+ createEffect(() => {
261
+ if (!isReady()) return;
262
+ client.withFlag(flagKey, callback, context).catch((error) => {
263
+ console.error(`[Savvagent] Error in withFlag callback for ${flagKey}:`, error);
264
+ onError?.(error);
265
+ });
266
+ });
267
+ }
268
+ function createUser() {
269
+ const {
270
+ client
271
+ } = useSavvagent();
272
+ const [userId, setUserIdSignal] = createSignal(client.getUserId());
273
+ const [anonymousId, setAnonymousIdSignal] = createSignal(client.getAnonymousId());
274
+ const setUserId = (id) => {
275
+ client.setUserId(id);
276
+ setUserIdSignal(id);
277
+ };
278
+ const getUserId = () => {
279
+ return client.getUserId();
280
+ };
281
+ const setAnonymousId = (id) => {
282
+ client.setAnonymousId(id);
283
+ setAnonymousIdSignal(id);
284
+ };
285
+ const getAnonymousId = () => {
286
+ return client.getAnonymousId();
287
+ };
288
+ return {
289
+ userId,
290
+ setUserId,
291
+ getUserId,
292
+ anonymousId,
293
+ setAnonymousId,
294
+ getAnonymousId
295
+ };
296
+ }
72
297
  function createUserSignals() {
73
- const client = useSavvagent();
298
+ const {
299
+ client
300
+ } = useSavvagent();
74
301
  const [userId, setUserIdSignal] = createSignal(client.getUserId());
75
302
  const setUserId = (id) => {
76
303
  client.setUserId(id);
@@ -78,8 +305,18 @@ function createUserSignals() {
78
305
  };
79
306
  return [userId, setUserId];
80
307
  }
308
+ function createTrackError(flagKey, context) {
309
+ const {
310
+ client
311
+ } = useSavvagent();
312
+ return (error) => {
313
+ client.trackError(flagKey, error, context);
314
+ };
315
+ }
81
316
  function trackError(flagKey, error, context) {
82
- const client = useSavvagent();
317
+ const {
318
+ client
319
+ } = useSavvagent();
83
320
  client.trackError(flagKey, error, context);
84
321
  }
85
322
  export {
@@ -87,7 +324,11 @@ export {
87
324
  SavvagentProvider,
88
325
  createFlag,
89
326
  createFlagValue,
327
+ createFlags,
328
+ createTrackError,
329
+ createUser,
90
330
  createUserSignals,
331
+ createWithFlag,
91
332
  trackError,
92
333
  useSavvagent
93
334
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvagent/solid",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "SolidJS SDK for Savvagent feature flags with reactive primitives",
5
5
  "author": "Savvagent",
6
6
  "license": "MIT",
@@ -21,12 +21,18 @@
21
21
  "solid-js": ">=1.0.0"
22
22
  },
23
23
  "dependencies": {
24
- "@savvagent/sdk": "1.0.0"
24
+ "@savvagent/sdk": "1.0.1"
25
25
  },
26
26
  "devDependencies": {
27
- "solid-js": "^1.8.0",
28
- "tsup": "^8.0.0",
29
- "typescript": "^5.4.0"
27
+ "@solidjs/testing-library": "0.8.10",
28
+ "@testing-library/jest-dom": "6.9.1",
29
+ "esbuild-plugin-solid": "0.6.0",
30
+ "jsdom": "27.2.0",
31
+ "solid-js": "^1.9.10",
32
+ "tsup": "^8.5.1",
33
+ "typescript": "^5.9.3",
34
+ "vite-plugin-solid": "^2.11.10",
35
+ "vitest": "4.0.14"
30
36
  },
31
37
  "keywords": [
32
38
  "savvagent",
@@ -50,8 +56,8 @@
50
56
  "access": "public"
51
57
  },
52
58
  "scripts": {
53
- "build": "tsup src/index.tsx --format cjs,esm --dts --external solid-js",
54
- "dev": "tsup src/index.tsx --format cjs,esm --dts --external solid-js --watch",
59
+ "build": "tsup",
60
+ "dev": "tsup --watch",
55
61
  "test": "vitest",
56
62
  "lint": "eslint src --ext .ts,.tsx",
57
63
  "format": "prettier --write \"src/**/*.{ts,tsx}\""