@savvagent/solid 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +232 -16
- package/dist/index.d.ts +232 -16
- package/dist/index.js +294 -19
- package/dist/index.mjs +290 -27
- package/package.json +16 -7
package/dist/index.js
CHANGED
|
@@ -22,33 +22,93 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
FlagClient: () => import_sdk2.FlagClient,
|
|
24
24
|
SavvagentProvider: () => SavvagentProvider,
|
|
25
|
+
createEnvironment: () => createEnvironment,
|
|
25
26
|
createFlag: () => createFlag,
|
|
26
27
|
createFlagValue: () => createFlagValue,
|
|
28
|
+
createFlags: () => createFlags,
|
|
29
|
+
createTrackError: () => createTrackError,
|
|
30
|
+
createUser: () => createUser,
|
|
27
31
|
createUserSignals: () => createUserSignals,
|
|
32
|
+
createWithFlag: () => createWithFlag,
|
|
28
33
|
trackError: () => trackError,
|
|
29
34
|
useSavvagent: () => useSavvagent
|
|
30
35
|
});
|
|
31
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
var import_web = require("solid-js/web");
|
|
32
38
|
var import_solid_js = require("solid-js");
|
|
33
39
|
var import_sdk = require("@savvagent/sdk");
|
|
34
40
|
var import_sdk2 = require("@savvagent/sdk");
|
|
35
41
|
var SavvagentContext = (0, import_solid_js.createContext)();
|
|
36
42
|
function SavvagentProvider(props) {
|
|
37
|
-
const
|
|
43
|
+
const [isReady, setIsReady] = (0, import_solid_js.createSignal)(false);
|
|
44
|
+
let client;
|
|
45
|
+
try {
|
|
46
|
+
client = new import_sdk.FlagClient(props.config);
|
|
47
|
+
setIsReady(true);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("[Savvagent] Failed to initialize client:", error);
|
|
50
|
+
props.config.onError?.(error);
|
|
51
|
+
client = new import_sdk.FlagClient({
|
|
52
|
+
...props.config,
|
|
53
|
+
apiKey: ""
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const normalizedDefaultContext = (0, import_solid_js.createMemo)(() => ({
|
|
57
|
+
application_id: props.defaultContext?.applicationId,
|
|
58
|
+
environment: props.defaultContext?.environment,
|
|
59
|
+
organization_id: props.defaultContext?.organizationId,
|
|
60
|
+
user_id: props.defaultContext?.userId,
|
|
61
|
+
anonymous_id: props.defaultContext?.anonymousId,
|
|
62
|
+
session_id: props.defaultContext?.sessionId,
|
|
63
|
+
language: props.defaultContext?.language,
|
|
64
|
+
attributes: props.defaultContext?.attributes
|
|
65
|
+
}));
|
|
66
|
+
if (props.defaultContext?.userId) {
|
|
67
|
+
client.setUserId(props.defaultContext.userId);
|
|
68
|
+
}
|
|
38
69
|
(0, import_solid_js.onCleanup)(() => {
|
|
39
70
|
client.close();
|
|
40
71
|
});
|
|
41
|
-
|
|
72
|
+
const contextValue = {
|
|
73
|
+
client,
|
|
74
|
+
isReady,
|
|
75
|
+
defaultContext: normalizedDefaultContext
|
|
76
|
+
};
|
|
77
|
+
return (0, import_web.createComponent)(SavvagentContext.Provider, {
|
|
78
|
+
value: contextValue,
|
|
79
|
+
get children() {
|
|
80
|
+
return props.children;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
42
83
|
}
|
|
43
84
|
function useSavvagent() {
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
85
|
+
const context = (0, import_solid_js.useContext)(SavvagentContext);
|
|
86
|
+
if (!context) {
|
|
46
87
|
throw new Error("useSavvagent must be used within a SavvagentProvider");
|
|
47
88
|
}
|
|
48
|
-
return
|
|
89
|
+
return context;
|
|
90
|
+
}
|
|
91
|
+
function deepEqual(a, b) {
|
|
92
|
+
if (a === b) return true;
|
|
93
|
+
if (a === null || b === null) return a === b;
|
|
94
|
+
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
95
|
+
const keysA = Object.keys(a);
|
|
96
|
+
const keysB = Object.keys(b);
|
|
97
|
+
if (keysA.length !== keysB.length) return false;
|
|
98
|
+
for (const key of keysA) {
|
|
99
|
+
if (!keysB.includes(key)) return false;
|
|
100
|
+
if (!deepEqual(a[key], b[key])) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
49
105
|
}
|
|
50
106
|
function createFlag(flagKey, options = {}) {
|
|
51
|
-
const
|
|
107
|
+
const {
|
|
108
|
+
client,
|
|
109
|
+
isReady,
|
|
110
|
+
defaultContext
|
|
111
|
+
} = useSavvagent();
|
|
52
112
|
const {
|
|
53
113
|
context,
|
|
54
114
|
defaultValue = false,
|
|
@@ -56,23 +116,39 @@ function createFlag(flagKey, options = {}) {
|
|
|
56
116
|
onError
|
|
57
117
|
} = options;
|
|
58
118
|
const [trigger, setTrigger] = (0, import_solid_js.createSignal)(0);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
throw error2;
|
|
119
|
+
const mergedContext = (0, import_solid_js.createMemo)(() => {
|
|
120
|
+
const def = defaultContext();
|
|
121
|
+
return {
|
|
122
|
+
...def,
|
|
123
|
+
...context,
|
|
124
|
+
attributes: {
|
|
125
|
+
...def?.attributes,
|
|
126
|
+
...context?.attributes
|
|
68
127
|
}
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
let prevContext;
|
|
131
|
+
const [result] = (0, import_solid_js.createResource)(() => ({
|
|
132
|
+
trigger: trigger(),
|
|
133
|
+
context: mergedContext(),
|
|
134
|
+
ready: isReady()
|
|
135
|
+
}), async (source) => {
|
|
136
|
+
if (!source.ready) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
return await client.evaluate(flagKey, source.context);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
const error2 = err;
|
|
143
|
+
onError?.(error2);
|
|
144
|
+
throw error2;
|
|
69
145
|
}
|
|
70
|
-
);
|
|
146
|
+
});
|
|
71
147
|
const value = () => result()?.value ?? defaultValue;
|
|
72
148
|
const loading = () => result.loading;
|
|
73
149
|
const error = () => result.error ?? null;
|
|
74
150
|
(0, import_solid_js.createEffect)(() => {
|
|
75
|
-
if (!realtime) return;
|
|
151
|
+
if (!realtime || !isReady()) return;
|
|
76
152
|
const unsubscribe = client.subscribe(flagKey, () => {
|
|
77
153
|
setTrigger((t) => t + 1);
|
|
78
154
|
});
|
|
@@ -80,6 +156,22 @@ function createFlag(flagKey, options = {}) {
|
|
|
80
156
|
unsubscribe();
|
|
81
157
|
});
|
|
82
158
|
});
|
|
159
|
+
(0, import_solid_js.createEffect)(() => {
|
|
160
|
+
if (!isReady()) return;
|
|
161
|
+
const unsubscribe = client.onOverrideChange(() => {
|
|
162
|
+
setTrigger((t) => t + 1);
|
|
163
|
+
});
|
|
164
|
+
(0, import_solid_js.onCleanup)(() => {
|
|
165
|
+
unsubscribe();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
(0, import_solid_js.createEffect)(() => {
|
|
169
|
+
const currentContext = mergedContext();
|
|
170
|
+
if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
|
|
171
|
+
setTrigger((t) => t + 1);
|
|
172
|
+
}
|
|
173
|
+
prevContext = currentContext;
|
|
174
|
+
});
|
|
83
175
|
return {
|
|
84
176
|
value,
|
|
85
177
|
loading,
|
|
@@ -92,8 +184,176 @@ function createFlagValue(flagKey, options = {}) {
|
|
|
92
184
|
const flag = createFlag(flagKey, options);
|
|
93
185
|
return flag.value;
|
|
94
186
|
}
|
|
187
|
+
function createFlags(flagKeys, options = {}) {
|
|
188
|
+
const {
|
|
189
|
+
client,
|
|
190
|
+
isReady,
|
|
191
|
+
defaultContext
|
|
192
|
+
} = useSavvagent();
|
|
193
|
+
const {
|
|
194
|
+
context,
|
|
195
|
+
defaultValues = {},
|
|
196
|
+
realtime = true,
|
|
197
|
+
onError
|
|
198
|
+
} = options;
|
|
199
|
+
const [trigger, setTrigger] = (0, import_solid_js.createSignal)(0);
|
|
200
|
+
const mergedContext = (0, import_solid_js.createMemo)(() => {
|
|
201
|
+
const def = defaultContext();
|
|
202
|
+
return {
|
|
203
|
+
...def,
|
|
204
|
+
...context,
|
|
205
|
+
attributes: {
|
|
206
|
+
...def?.attributes,
|
|
207
|
+
...context?.attributes
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
});
|
|
211
|
+
const initialValues = {};
|
|
212
|
+
const initialErrors = {};
|
|
213
|
+
const initialResults = {};
|
|
214
|
+
for (const key of flagKeys) {
|
|
215
|
+
initialValues[key] = defaultValues[key] ?? false;
|
|
216
|
+
initialErrors[key] = null;
|
|
217
|
+
initialResults[key] = null;
|
|
218
|
+
}
|
|
219
|
+
const [values, setValues] = (0, import_solid_js.createSignal)(initialValues);
|
|
220
|
+
const [errors, setErrors] = (0, import_solid_js.createSignal)(initialErrors);
|
|
221
|
+
const [results, setResults] = (0, import_solid_js.createSignal)(initialResults);
|
|
222
|
+
const [loading, setLoading] = (0, import_solid_js.createSignal)(true);
|
|
223
|
+
let prevContext;
|
|
224
|
+
const evaluateFlags = async () => {
|
|
225
|
+
if (!isReady()) return;
|
|
226
|
+
setLoading(true);
|
|
227
|
+
const newValues = {};
|
|
228
|
+
const newErrors = {};
|
|
229
|
+
const newResults = {};
|
|
230
|
+
const ctx = mergedContext();
|
|
231
|
+
await Promise.all(flagKeys.map(async (flagKey) => {
|
|
232
|
+
try {
|
|
233
|
+
const evalResult = await client.evaluate(flagKey, ctx);
|
|
234
|
+
newValues[flagKey] = evalResult.value;
|
|
235
|
+
newErrors[flagKey] = null;
|
|
236
|
+
newResults[flagKey] = evalResult;
|
|
237
|
+
} catch (err) {
|
|
238
|
+
const error = err;
|
|
239
|
+
newValues[flagKey] = defaultValues[flagKey] ?? false;
|
|
240
|
+
newErrors[flagKey] = error;
|
|
241
|
+
newResults[flagKey] = null;
|
|
242
|
+
onError?.(error, flagKey);
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
245
|
+
setValues(newValues);
|
|
246
|
+
setErrors(newErrors);
|
|
247
|
+
setResults(newResults);
|
|
248
|
+
setLoading(false);
|
|
249
|
+
};
|
|
250
|
+
(0, import_solid_js.createEffect)(() => {
|
|
251
|
+
trigger();
|
|
252
|
+
if (isReady()) {
|
|
253
|
+
evaluateFlags();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
(0, import_solid_js.createEffect)(() => {
|
|
257
|
+
if (!realtime || !isReady()) return;
|
|
258
|
+
const unsubscribes = flagKeys.map((flagKey) => client.subscribe(flagKey, () => {
|
|
259
|
+
setTrigger((t) => t + 1);
|
|
260
|
+
}));
|
|
261
|
+
(0, import_solid_js.onCleanup)(() => {
|
|
262
|
+
unsubscribes.forEach((unsubscribe) => unsubscribe());
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
(0, import_solid_js.createEffect)(() => {
|
|
266
|
+
if (!isReady()) return;
|
|
267
|
+
const unsubscribe = client.onOverrideChange(() => {
|
|
268
|
+
setTrigger((t) => t + 1);
|
|
269
|
+
});
|
|
270
|
+
(0, import_solid_js.onCleanup)(() => {
|
|
271
|
+
unsubscribe();
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
(0, import_solid_js.createEffect)(() => {
|
|
275
|
+
const currentContext = mergedContext();
|
|
276
|
+
if (prevContext !== void 0 && !deepEqual(prevContext, currentContext)) {
|
|
277
|
+
setTrigger((t) => t + 1);
|
|
278
|
+
}
|
|
279
|
+
prevContext = currentContext;
|
|
280
|
+
});
|
|
281
|
+
return {
|
|
282
|
+
values,
|
|
283
|
+
loading,
|
|
284
|
+
errors,
|
|
285
|
+
results,
|
|
286
|
+
refetch: () => setTrigger((t) => t + 1)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function createWithFlag(flagKey, callback, options = {}) {
|
|
290
|
+
const {
|
|
291
|
+
client,
|
|
292
|
+
isReady
|
|
293
|
+
} = useSavvagent();
|
|
294
|
+
const {
|
|
295
|
+
context,
|
|
296
|
+
onError
|
|
297
|
+
} = options;
|
|
298
|
+
(0, import_solid_js.createEffect)(() => {
|
|
299
|
+
if (!isReady()) return;
|
|
300
|
+
client.withFlag(flagKey, callback, context).catch((error) => {
|
|
301
|
+
console.error(`[Savvagent] Error in withFlag callback for ${flagKey}:`, error);
|
|
302
|
+
onError?.(error);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function createUser() {
|
|
307
|
+
const {
|
|
308
|
+
client
|
|
309
|
+
} = useSavvagent();
|
|
310
|
+
const [userId, setUserIdSignal] = (0, import_solid_js.createSignal)(client.getUserId());
|
|
311
|
+
const [anonymousId, setAnonymousIdSignal] = (0, import_solid_js.createSignal)(client.getAnonymousId());
|
|
312
|
+
const setUserId = (id) => {
|
|
313
|
+
client.setUserId(id);
|
|
314
|
+
setUserIdSignal(id);
|
|
315
|
+
};
|
|
316
|
+
const getUserId = () => {
|
|
317
|
+
return client.getUserId();
|
|
318
|
+
};
|
|
319
|
+
const setAnonymousId = (id) => {
|
|
320
|
+
client.setAnonymousId(id);
|
|
321
|
+
setAnonymousIdSignal(id);
|
|
322
|
+
};
|
|
323
|
+
const getAnonymousId = () => {
|
|
324
|
+
return client.getAnonymousId();
|
|
325
|
+
};
|
|
326
|
+
return {
|
|
327
|
+
userId,
|
|
328
|
+
setUserId,
|
|
329
|
+
getUserId,
|
|
330
|
+
anonymousId,
|
|
331
|
+
setAnonymousId,
|
|
332
|
+
getAnonymousId
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function createEnvironment() {
|
|
336
|
+
const {
|
|
337
|
+
client
|
|
338
|
+
} = useSavvagent();
|
|
339
|
+
const [environment, setEnvironmentSignal] = (0, import_solid_js.createSignal)(client.getEnvironment());
|
|
340
|
+
const setEnvironment = (env) => {
|
|
341
|
+
client.setEnvironment(env);
|
|
342
|
+
setEnvironmentSignal(env);
|
|
343
|
+
};
|
|
344
|
+
const getEnvironment = () => {
|
|
345
|
+
return client.getEnvironment();
|
|
346
|
+
};
|
|
347
|
+
return {
|
|
348
|
+
environment,
|
|
349
|
+
setEnvironment,
|
|
350
|
+
getEnvironment
|
|
351
|
+
};
|
|
352
|
+
}
|
|
95
353
|
function createUserSignals() {
|
|
96
|
-
const
|
|
354
|
+
const {
|
|
355
|
+
client
|
|
356
|
+
} = useSavvagent();
|
|
97
357
|
const [userId, setUserIdSignal] = (0, import_solid_js.createSignal)(client.getUserId());
|
|
98
358
|
const setUserId = (id) => {
|
|
99
359
|
client.setUserId(id);
|
|
@@ -101,17 +361,32 @@ function createUserSignals() {
|
|
|
101
361
|
};
|
|
102
362
|
return [userId, setUserId];
|
|
103
363
|
}
|
|
364
|
+
function createTrackError(flagKey, context) {
|
|
365
|
+
const {
|
|
366
|
+
client
|
|
367
|
+
} = useSavvagent();
|
|
368
|
+
return (error) => {
|
|
369
|
+
client.trackError(flagKey, error, context);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
104
372
|
function trackError(flagKey, error, context) {
|
|
105
|
-
const
|
|
373
|
+
const {
|
|
374
|
+
client
|
|
375
|
+
} = useSavvagent();
|
|
106
376
|
client.trackError(flagKey, error, context);
|
|
107
377
|
}
|
|
108
378
|
// Annotate the CommonJS export names for ESM import in node:
|
|
109
379
|
0 && (module.exports = {
|
|
110
380
|
FlagClient,
|
|
111
381
|
SavvagentProvider,
|
|
382
|
+
createEnvironment,
|
|
112
383
|
createFlag,
|
|
113
384
|
createFlagValue,
|
|
385
|
+
createFlags,
|
|
386
|
+
createTrackError,
|
|
387
|
+
createUser,
|
|
114
388
|
createUserSignals,
|
|
389
|
+
createWithFlag,
|
|
115
390
|
trackError,
|
|
116
391
|
useSavvagent
|
|
117
392
|
});
|