@simplr-ai/node 1.0.0 → 1.1.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/README.md +132 -2
- package/dist/index.cjs +524 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +401 -2
- package/dist/index.d.ts +401 -2
- package/dist/index.js +519 -2
- package/dist/index.js.map +1 -1
- package/package.json +14 -3
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
Simplr: () => Simplr,
|
|
24
|
+
SimplrAI: () => SimplrAI,
|
|
25
|
+
SimplrAdmin: () => SimplrAdmin,
|
|
24
26
|
SimplrError: () => SimplrError,
|
|
27
|
+
SimplrFlags: () => SimplrFlags,
|
|
28
|
+
SimplrProfiles: () => SimplrProfiles,
|
|
29
|
+
SimplrRUM: () => SimplrRUM,
|
|
25
30
|
WebhookVerificationError: () => WebhookVerificationError,
|
|
26
31
|
constructWebhookEvent: () => constructEvent,
|
|
27
32
|
default: () => src_default,
|
|
@@ -56,7 +61,7 @@ async function apiRequest(cfg, method, path, body) {
|
|
|
56
61
|
method,
|
|
57
62
|
headers: {
|
|
58
63
|
"Content-Type": "application/json",
|
|
59
|
-
|
|
64
|
+
...cfg.authHeaders
|
|
60
65
|
},
|
|
61
66
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
62
67
|
signal: controller.signal
|
|
@@ -137,6 +142,402 @@ var EdgeResource = class {
|
|
|
137
142
|
}
|
|
138
143
|
};
|
|
139
144
|
|
|
145
|
+
// src/flags.ts
|
|
146
|
+
function murmurHash3(input, seed = 0) {
|
|
147
|
+
let h1 = seed;
|
|
148
|
+
const c1 = 3432918353;
|
|
149
|
+
const c2 = 461845907;
|
|
150
|
+
for (let i = 0; i < input.length; i++) {
|
|
151
|
+
let k1 = input.charCodeAt(i);
|
|
152
|
+
k1 = Math.imul(k1, c1);
|
|
153
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
154
|
+
k1 = Math.imul(k1, c2);
|
|
155
|
+
h1 ^= k1;
|
|
156
|
+
h1 = h1 << 13 | h1 >>> 19;
|
|
157
|
+
h1 = Math.imul(h1, 5) + 3864292196;
|
|
158
|
+
}
|
|
159
|
+
h1 ^= input.length;
|
|
160
|
+
h1 ^= h1 >>> 16;
|
|
161
|
+
h1 = Math.imul(h1, 2246822507);
|
|
162
|
+
h1 ^= h1 >>> 13;
|
|
163
|
+
h1 = Math.imul(h1, 3266489909);
|
|
164
|
+
h1 ^= h1 >>> 16;
|
|
165
|
+
return h1 >>> 0;
|
|
166
|
+
}
|
|
167
|
+
function matchRule(rule, attributes) {
|
|
168
|
+
const actual = attributes[rule.attribute];
|
|
169
|
+
switch (rule.op) {
|
|
170
|
+
case "eq":
|
|
171
|
+
return String(actual) === rule.value;
|
|
172
|
+
case "neq":
|
|
173
|
+
return String(actual) !== rule.value;
|
|
174
|
+
case "contains":
|
|
175
|
+
return String(actual ?? "").includes(rule.value);
|
|
176
|
+
default:
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
var SimplrFlags = class {
|
|
181
|
+
cfg;
|
|
182
|
+
environment;
|
|
183
|
+
refreshIntervalMs;
|
|
184
|
+
flags = {};
|
|
185
|
+
defaultUserId;
|
|
186
|
+
timer = null;
|
|
187
|
+
ready = false;
|
|
188
|
+
constructor(options) {
|
|
189
|
+
if (!options?.publicKey) throw new Error("SimplrFlags: `publicKey` is required");
|
|
190
|
+
this.cfg = {
|
|
191
|
+
authHeaders: { "X-API-Key": options.publicKey },
|
|
192
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
193
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
194
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
195
|
+
};
|
|
196
|
+
this.environment = options.environment;
|
|
197
|
+
this.refreshIntervalMs = options.refreshIntervalMs ?? 6e4;
|
|
198
|
+
}
|
|
199
|
+
/** Fetch the flag config once and start the background refresh. */
|
|
200
|
+
async initialize() {
|
|
201
|
+
await this.refresh();
|
|
202
|
+
this.ready = true;
|
|
203
|
+
if (this.refreshIntervalMs > 0) {
|
|
204
|
+
this.timer = setInterval(() => {
|
|
205
|
+
void this.refresh();
|
|
206
|
+
}, this.refreshIntervalMs);
|
|
207
|
+
this.timer?.unref?.();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/** Set the default identifier used for bucketing when none is passed to isEnabled. */
|
|
211
|
+
setUser(userId) {
|
|
212
|
+
this.defaultUserId = userId;
|
|
213
|
+
}
|
|
214
|
+
/** Re-fetch the flag config (counts as one billable request). */
|
|
215
|
+
async refresh() {
|
|
216
|
+
const path = this.environment ? `/v1/flags?environment=${encodeURIComponent(this.environment)}` : "/v1/flags";
|
|
217
|
+
try {
|
|
218
|
+
const content = await apiRequest(this.cfg, "GET", path);
|
|
219
|
+
const list = content?.flags || [];
|
|
220
|
+
const map = {};
|
|
221
|
+
for (const f of list) map[f.key] = f;
|
|
222
|
+
this.flags = map;
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/** Evaluate a flag locally. Deterministic per user; no network call. */
|
|
227
|
+
isEnabled(key, ctx = {}) {
|
|
228
|
+
const f = this.flags[key];
|
|
229
|
+
if (!f || !f.enabled) return false;
|
|
230
|
+
const uid = ctx.userId || this.defaultUserId || "anonymous";
|
|
231
|
+
if (f.target_user_ids?.includes(uid)) return true;
|
|
232
|
+
if (ctx.attributes && f.rules?.length && f.rules.some((r) => matchRule(r, ctx.attributes))) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
if (f.rollout_percentage >= 100) return true;
|
|
236
|
+
if (f.rollout_percentage <= 0) return false;
|
|
237
|
+
return murmurHash3(`${key}:${uid}`) % 100 < f.rollout_percentage;
|
|
238
|
+
}
|
|
239
|
+
getAll() {
|
|
240
|
+
return { ...this.flags };
|
|
241
|
+
}
|
|
242
|
+
isReady() {
|
|
243
|
+
return this.ready;
|
|
244
|
+
}
|
|
245
|
+
/** Stop the background refresh timer. */
|
|
246
|
+
dispose() {
|
|
247
|
+
if (this.timer) clearInterval(this.timer);
|
|
248
|
+
this.timer = null;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/profiles.ts
|
|
253
|
+
var SimplrProfiles = class {
|
|
254
|
+
constructor(cfg) {
|
|
255
|
+
this.cfg = cfg;
|
|
256
|
+
}
|
|
257
|
+
cfg;
|
|
258
|
+
/**
|
|
259
|
+
* Identify a user — creates or updates an anonymous profile and (optionally)
|
|
260
|
+
* links a device fingerprint. POST /v1/profiles.
|
|
261
|
+
*/
|
|
262
|
+
identify(externalId, options) {
|
|
263
|
+
const { profileType, fingerprintHash, ...rest } = options ?? {};
|
|
264
|
+
const body = {
|
|
265
|
+
external_id: externalId,
|
|
266
|
+
profile_type: profileType || "customer",
|
|
267
|
+
...rest
|
|
268
|
+
};
|
|
269
|
+
if (fingerprintHash) body.fingerprint_hash = fingerprintHash;
|
|
270
|
+
return apiRequest(this.cfg, "POST", "/v1/profiles", body);
|
|
271
|
+
}
|
|
272
|
+
/** Submit an order for real-time fraud scoring. POST /v1/orders. */
|
|
273
|
+
submitOrder(order) {
|
|
274
|
+
return apiRequest(this.cfg, "POST", "/v1/orders", order);
|
|
275
|
+
}
|
|
276
|
+
/** Get the risk profile for a user. GET /v1/profiles/{externalId}. */
|
|
277
|
+
getProfileRisk(externalId) {
|
|
278
|
+
return apiRequest(
|
|
279
|
+
this.cfg,
|
|
280
|
+
"GET",
|
|
281
|
+
`/v1/profiles/${encodeURIComponent(externalId)}`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
/** Report a profile as fraud or legitimate. POST /v1/profiles/{externalId}/outcome. */
|
|
285
|
+
async reportOutcome(externalId, outcome) {
|
|
286
|
+
await apiRequest(
|
|
287
|
+
this.cfg,
|
|
288
|
+
"POST",
|
|
289
|
+
`/v1/profiles/${encodeURIComponent(externalId)}/outcome`,
|
|
290
|
+
{ outcome }
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// src/rum.ts
|
|
296
|
+
var DEFAULT_BATCH_SIZE = 30;
|
|
297
|
+
var DEFAULT_FLUSH_INTERVAL = 1e4;
|
|
298
|
+
var DEFAULT_ENDPOINT = "/v1/rum/events";
|
|
299
|
+
function genId() {
|
|
300
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
301
|
+
}
|
|
302
|
+
var SimplrRUM = class {
|
|
303
|
+
constructor(cfg) {
|
|
304
|
+
this.cfg = cfg;
|
|
305
|
+
}
|
|
306
|
+
cfg;
|
|
307
|
+
config = null;
|
|
308
|
+
initialized = false;
|
|
309
|
+
queue = [];
|
|
310
|
+
timer = null;
|
|
311
|
+
flushing = false;
|
|
312
|
+
sessionId = null;
|
|
313
|
+
currentViewId = null;
|
|
314
|
+
userId;
|
|
315
|
+
userAttributes;
|
|
316
|
+
globalAttributes = {};
|
|
317
|
+
batchSize = DEFAULT_BATCH_SIZE;
|
|
318
|
+
endpoint = DEFAULT_ENDPOINT;
|
|
319
|
+
/** Initialize the SDK, start a session, and begin the flush timer. */
|
|
320
|
+
initialize(config) {
|
|
321
|
+
if (this.initialized) return;
|
|
322
|
+
this.config = config;
|
|
323
|
+
this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
324
|
+
this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;
|
|
325
|
+
this.sessionId = genId();
|
|
326
|
+
this.initialized = true;
|
|
327
|
+
this.trackEvent("session_start");
|
|
328
|
+
const interval = config.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
|
|
329
|
+
if (interval > 0) {
|
|
330
|
+
this.timer = setInterval(() => {
|
|
331
|
+
void this.flush();
|
|
332
|
+
}, interval);
|
|
333
|
+
this.timer?.unref?.();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
isInitialized() {
|
|
337
|
+
return this.initialized;
|
|
338
|
+
}
|
|
339
|
+
/** Associate subsequent events with a user. */
|
|
340
|
+
setUser(userId, attributes) {
|
|
341
|
+
this.userId = userId;
|
|
342
|
+
this.userAttributes = attributes;
|
|
343
|
+
}
|
|
344
|
+
clearUser() {
|
|
345
|
+
this.userId = void 0;
|
|
346
|
+
this.userAttributes = void 0;
|
|
347
|
+
}
|
|
348
|
+
addAttribute(key, value) {
|
|
349
|
+
this.globalAttributes[key] = value;
|
|
350
|
+
}
|
|
351
|
+
removeAttribute(key) {
|
|
352
|
+
delete this.globalAttributes[key];
|
|
353
|
+
}
|
|
354
|
+
/** Track a screen/page view. */
|
|
355
|
+
trackView(name, attributes) {
|
|
356
|
+
if (!this.initialized) return;
|
|
357
|
+
this.currentViewId = genId();
|
|
358
|
+
this.trackEvent("view", {
|
|
359
|
+
view: { id: this.currentViewId, name },
|
|
360
|
+
attributes
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/** Track a user action. */
|
|
364
|
+
trackAction(name, attributes) {
|
|
365
|
+
if (!this.initialized) return;
|
|
366
|
+
this.trackEvent("action", { action: { name, type: "custom" }, attributes });
|
|
367
|
+
}
|
|
368
|
+
/** Track an error. */
|
|
369
|
+
trackError(error, attributes) {
|
|
370
|
+
if (!this.initialized) return;
|
|
371
|
+
const data = error instanceof Error ? { message: error.message, stack: error.stack, type: error.constructor.name } : error;
|
|
372
|
+
this.trackEvent("error", { error: data, attributes });
|
|
373
|
+
}
|
|
374
|
+
/** Emit a log line. */
|
|
375
|
+
log(level, message, attributes) {
|
|
376
|
+
if (!this.initialized) return;
|
|
377
|
+
this.trackEvent("log", { log: { level, message }, attributes });
|
|
378
|
+
}
|
|
379
|
+
trackEvent(type, data) {
|
|
380
|
+
if (!this.initialized || !this.sessionId) return;
|
|
381
|
+
const event = {
|
|
382
|
+
type,
|
|
383
|
+
timestamp: Date.now(),
|
|
384
|
+
sessionId: this.sessionId,
|
|
385
|
+
viewId: this.currentViewId || void 0,
|
|
386
|
+
userId: this.userId,
|
|
387
|
+
applicationId: this.config.applicationId,
|
|
388
|
+
applicationVersion: this.config?.applicationVersion,
|
|
389
|
+
environment: this.config?.environment,
|
|
390
|
+
userAttributes: this.userAttributes,
|
|
391
|
+
globalAttributes: Object.keys(this.globalAttributes).length > 0 ? this.globalAttributes : void 0,
|
|
392
|
+
...data
|
|
393
|
+
};
|
|
394
|
+
this.queue.push(event);
|
|
395
|
+
if (this.queue.length >= this.batchSize) void this.flush();
|
|
396
|
+
}
|
|
397
|
+
/** Flush queued events to POST /v1/rum/events. */
|
|
398
|
+
async flush() {
|
|
399
|
+
if (this.flushing || this.queue.length === 0) return;
|
|
400
|
+
this.flushing = true;
|
|
401
|
+
const events = this.queue;
|
|
402
|
+
this.queue = [];
|
|
403
|
+
try {
|
|
404
|
+
await apiRequest(this.cfg, "POST", this.endpoint, {
|
|
405
|
+
events,
|
|
406
|
+
sentAt: Date.now()
|
|
407
|
+
});
|
|
408
|
+
} catch {
|
|
409
|
+
this.queue = [...events, ...this.queue];
|
|
410
|
+
} finally {
|
|
411
|
+
this.flushing = false;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/** End the session, flush remaining events, and stop the timer. */
|
|
415
|
+
async stopSession() {
|
|
416
|
+
if (!this.initialized) return;
|
|
417
|
+
this.trackEvent("session_end");
|
|
418
|
+
await this.flush();
|
|
419
|
+
if (this.timer) {
|
|
420
|
+
clearInterval(this.timer);
|
|
421
|
+
this.timer = null;
|
|
422
|
+
}
|
|
423
|
+
this.initialized = false;
|
|
424
|
+
}
|
|
425
|
+
getSessionId() {
|
|
426
|
+
return this.sessionId;
|
|
427
|
+
}
|
|
428
|
+
getViewId() {
|
|
429
|
+
return this.currentViewId;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
// src/ai.ts
|
|
434
|
+
function mapDelegation(d) {
|
|
435
|
+
return {
|
|
436
|
+
delegationId: d.delegation_id,
|
|
437
|
+
endUserId: d.end_user_id,
|
|
438
|
+
bindingMode: d.binding_mode,
|
|
439
|
+
status: d.status,
|
|
440
|
+
expiresAt: d.expires_at,
|
|
441
|
+
useCount: d.use_count,
|
|
442
|
+
lastUsedAt: d.last_used_at,
|
|
443
|
+
createdAt: d.created_at
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
var SimplrAI = class {
|
|
447
|
+
constructor(cfg) {
|
|
448
|
+
this.cfg = cfg;
|
|
449
|
+
}
|
|
450
|
+
cfg;
|
|
451
|
+
/** Create a new AI delegation token for a user. POST /v1/ai/delegations. */
|
|
452
|
+
async createDelegation(options) {
|
|
453
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/delegations", {
|
|
454
|
+
end_user_id: options.userId,
|
|
455
|
+
end_user_email: options.email,
|
|
456
|
+
binding: options.binding || "any_location",
|
|
457
|
+
expires_in_days: options.expiresInDays || 7,
|
|
458
|
+
session_id: options.sessionId,
|
|
459
|
+
fingerprint_hash: options.fingerprintHash
|
|
460
|
+
});
|
|
461
|
+
const d = content.delegation;
|
|
462
|
+
return {
|
|
463
|
+
token: d.token,
|
|
464
|
+
delegationId: d.delegation_id,
|
|
465
|
+
expiresAt: d.expires_at,
|
|
466
|
+
bindingMode: d.binding_mode
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
/** Validate (introspect) an AI delegation token. POST /v1/ai/validate. */
|
|
470
|
+
async validate(token, options) {
|
|
471
|
+
try {
|
|
472
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/validate", {
|
|
473
|
+
token,
|
|
474
|
+
fingerprint_hash: options?.fingerprintHash,
|
|
475
|
+
ai_provider: options?.aiProvider,
|
|
476
|
+
action: options?.action
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
valid: true,
|
|
480
|
+
sessionType: content.session_type,
|
|
481
|
+
endUserId: content.end_user_id,
|
|
482
|
+
delegation: content.delegation ? {
|
|
483
|
+
delegationId: content.delegation.delegation_id,
|
|
484
|
+
bindingMode: content.delegation.binding_mode,
|
|
485
|
+
expiresAt: content.delegation.expires_at,
|
|
486
|
+
useCount: content.delegation.use_count
|
|
487
|
+
} : void 0
|
|
488
|
+
};
|
|
489
|
+
} catch (err) {
|
|
490
|
+
return { valid: false, error: err instanceof Error ? err.message : "Validation failed" };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/** Revoke a delegation. POST /v1/ai/delegations/{id}/revoke. */
|
|
494
|
+
async revoke(delegationId, reason) {
|
|
495
|
+
await apiRequest(
|
|
496
|
+
this.cfg,
|
|
497
|
+
"POST",
|
|
498
|
+
`/v1/ai/delegations/${encodeURIComponent(delegationId)}/revoke`,
|
|
499
|
+
{ reason }
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
/** List delegations, optionally filtered by user. GET /v1/ai/delegations. */
|
|
503
|
+
async list(userId) {
|
|
504
|
+
const path = userId ? `/v1/ai/delegations?end_user_id=${encodeURIComponent(userId)}` : "/v1/ai/delegations";
|
|
505
|
+
const content = await apiRequest(this.cfg, "GET", path);
|
|
506
|
+
return (content.delegations || []).map(mapDelegation);
|
|
507
|
+
}
|
|
508
|
+
/** Get a single delegation. GET /v1/ai/delegations/{id}. */
|
|
509
|
+
async get(delegationId) {
|
|
510
|
+
const content = await apiRequest(
|
|
511
|
+
this.cfg,
|
|
512
|
+
"GET",
|
|
513
|
+
`/v1/ai/delegations/${encodeURIComponent(delegationId)}`
|
|
514
|
+
);
|
|
515
|
+
return mapDelegation(content.delegation);
|
|
516
|
+
}
|
|
517
|
+
/** Get delegation statistics. GET /v1/ai/stats. */
|
|
518
|
+
async stats() {
|
|
519
|
+
const content = await apiRequest(this.cfg, "GET", "/v1/ai/stats");
|
|
520
|
+
const s = content.stats;
|
|
521
|
+
return {
|
|
522
|
+
totalDelegations: s.total_delegations,
|
|
523
|
+
activeDelegations: s.active_delegations,
|
|
524
|
+
totalUses: s.total_uses,
|
|
525
|
+
delegationsByBinding: {
|
|
526
|
+
verifiedDevice: s.delegations_by_binding.verified_device,
|
|
527
|
+
anyLocation: s.delegations_by_binding.any_location
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
/** Revoke all delegations for a user (e.g. on logout). POST /v1/ai/revoke-all. */
|
|
532
|
+
async revokeAllForUser(userId, reason) {
|
|
533
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/revoke-all", {
|
|
534
|
+
end_user_id: userId,
|
|
535
|
+
reason
|
|
536
|
+
});
|
|
537
|
+
return content.revoked_count;
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
|
|
140
541
|
// src/webhooks.ts
|
|
141
542
|
var webhooks_exports = {};
|
|
142
543
|
__export(webhooks_exports, {
|
|
@@ -191,6 +592,91 @@ function constructEvent(payload, header, secret, options = {}) {
|
|
|
191
592
|
}
|
|
192
593
|
var webhooks = { verify, constructEvent };
|
|
193
594
|
|
|
595
|
+
// src/admin.ts
|
|
596
|
+
function qs(params) {
|
|
597
|
+
const entries = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null);
|
|
598
|
+
if (!entries.length) return "";
|
|
599
|
+
return "?" + entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&");
|
|
600
|
+
}
|
|
601
|
+
var UsageApi = class {
|
|
602
|
+
constructor(cfg) {
|
|
603
|
+
this.cfg = cfg;
|
|
604
|
+
}
|
|
605
|
+
cfg;
|
|
606
|
+
/** Aggregate usage stats for an org. */
|
|
607
|
+
stats(orgId) {
|
|
608
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/stats${qs({ org_id: orgId })}`);
|
|
609
|
+
}
|
|
610
|
+
/** Raw usage logs for an org. */
|
|
611
|
+
logs(orgId, params = {}) {
|
|
612
|
+
return apiRequest(this.cfg, "GET", `/v1/usage/logs${qs({ org_id: orgId, ...params })}`);
|
|
613
|
+
}
|
|
614
|
+
/** Billing usage breakdown (per-service totals + estimated cost). */
|
|
615
|
+
billing(orgId) {
|
|
616
|
+
return apiRequest(this.cfg, "GET", `/v1/billing/usage${qs({ org_id: orgId })}`);
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
var FlagsAdminApi = class {
|
|
620
|
+
constructor(cfg) {
|
|
621
|
+
this.cfg = cfg;
|
|
622
|
+
}
|
|
623
|
+
cfg;
|
|
624
|
+
list(orgId, environment) {
|
|
625
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags${qs({ org_id: orgId, environment })}`);
|
|
626
|
+
}
|
|
627
|
+
get(orgId, id) {
|
|
628
|
+
return apiRequest(this.cfg, "GET", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
629
|
+
}
|
|
630
|
+
create(orgId, data) {
|
|
631
|
+
return apiRequest(this.cfg, "POST", "/v1/feature-flags", { org_id: orgId, ...data });
|
|
632
|
+
}
|
|
633
|
+
update(orgId, id, data) {
|
|
634
|
+
return apiRequest(this.cfg, "PATCH", `/v1/feature-flags/${id}`, { org_id: orgId, ...data });
|
|
635
|
+
}
|
|
636
|
+
remove(orgId, id) {
|
|
637
|
+
return apiRequest(this.cfg, "DELETE", `/v1/feature-flags/${id}${qs({ org_id: orgId })}`);
|
|
638
|
+
}
|
|
639
|
+
history(orgId, id, params = {}) {
|
|
640
|
+
return apiRequest(
|
|
641
|
+
this.cfg,
|
|
642
|
+
"GET",
|
|
643
|
+
`/v1/feature-flags/${id}/history${qs({ org_id: orgId, ...params })}`
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
var RumApi = class {
|
|
648
|
+
constructor(cfg) {
|
|
649
|
+
this.cfg = cfg;
|
|
650
|
+
}
|
|
651
|
+
cfg;
|
|
652
|
+
overview(orgId, params = {}) {
|
|
653
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/overview${qs({ org_id: orgId, ...params })}`);
|
|
654
|
+
}
|
|
655
|
+
sessions(orgId, params = {}) {
|
|
656
|
+
return apiRequest(this.cfg, "GET", `/v1/rum/sessions${qs({ org_id: orgId, ...params })}`);
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
var SimplrAdmin = class {
|
|
660
|
+
usage;
|
|
661
|
+
flags;
|
|
662
|
+
rum;
|
|
663
|
+
constructor(options) {
|
|
664
|
+
if (!options?.token) throw new Error("SimplrAdmin: `token` is required");
|
|
665
|
+
const cfg = {
|
|
666
|
+
authHeaders: { Authorization: `Bearer ${options.token}` },
|
|
667
|
+
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
668
|
+
timeoutMs: options.timeoutMs ?? 15e3,
|
|
669
|
+
fetchImpl: options.fetch ?? globalThis.fetch
|
|
670
|
+
};
|
|
671
|
+
if (typeof cfg.fetchImpl !== "function") {
|
|
672
|
+
throw new Error("SimplrAdmin: no global fetch available \u2014 use Node 18+ or pass `fetch`");
|
|
673
|
+
}
|
|
674
|
+
this.usage = new UsageApi(cfg);
|
|
675
|
+
this.flags = new FlagsAdminApi(cfg);
|
|
676
|
+
this.rum = new RumApi(cfg);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
194
680
|
// src/index.ts
|
|
195
681
|
var DEFAULT_BASE_URL = "https://api.simplr.sh";
|
|
196
682
|
var Simplr = class {
|
|
@@ -198,12 +684,19 @@ var Simplr = class {
|
|
|
198
684
|
orders;
|
|
199
685
|
phone;
|
|
200
686
|
edge;
|
|
687
|
+
/** Anonymous user profiles + order fraud monitoring. */
|
|
688
|
+
profiles;
|
|
689
|
+
/** Real User Monitoring — batched events to /v1/rum/events. */
|
|
690
|
+
rum;
|
|
691
|
+
/** AI delegation — OAuth-like AI authentication. */
|
|
692
|
+
ai;
|
|
201
693
|
/** Webhook signature helpers (no network). */
|
|
202
694
|
webhooks = webhooks_exports;
|
|
695
|
+
_flags;
|
|
203
696
|
constructor(options) {
|
|
204
697
|
if (!options?.apiKey) throw new Error("Simplr: `apiKey` is required");
|
|
205
698
|
this.cfg = {
|
|
206
|
-
|
|
699
|
+
authHeaders: { "X-API-Key": options.apiKey },
|
|
207
700
|
baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
208
701
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
209
702
|
fetchImpl: options.fetch ?? globalThis.fetch
|
|
@@ -214,6 +707,30 @@ var Simplr = class {
|
|
|
214
707
|
this.orders = new OrdersResource(this.cfg);
|
|
215
708
|
this.phone = new PhoneResource(this.cfg);
|
|
216
709
|
this.edge = new EdgeResource(this.cfg);
|
|
710
|
+
this.profiles = new SimplrProfiles(this.cfg);
|
|
711
|
+
this.rum = new SimplrRUM(this.cfg);
|
|
712
|
+
this.ai = new SimplrAI(this.cfg);
|
|
713
|
+
if (options.publicKey) {
|
|
714
|
+
this._flags = new SimplrFlags({
|
|
715
|
+
publicKey: options.publicKey,
|
|
716
|
+
environment: options.environment,
|
|
717
|
+
baseUrl: this.cfg.baseUrl,
|
|
718
|
+
timeoutMs: this.cfg.timeoutMs,
|
|
719
|
+
fetch: this.cfg.fetchImpl
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Server-side feature flags. Requires a `publicKey` in the constructor options
|
|
725
|
+
* (flag config is read with the public key). Call `simplr.flags.initialize()` once.
|
|
726
|
+
*/
|
|
727
|
+
get flags() {
|
|
728
|
+
if (!this._flags) {
|
|
729
|
+
throw new Error(
|
|
730
|
+
"Simplr.flags requires a `publicKey` \u2014 pass it to `new Simplr({ apiKey, publicKey })`."
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
return this._flags;
|
|
217
734
|
}
|
|
218
735
|
/** Run an identity/fraud check. Provide any of email, phone, device, behavior. */
|
|
219
736
|
check(input) {
|
|
@@ -228,7 +745,12 @@ var src_default = Simplr;
|
|
|
228
745
|
// Annotate the CommonJS export names for ESM import in node:
|
|
229
746
|
0 && (module.exports = {
|
|
230
747
|
Simplr,
|
|
748
|
+
SimplrAI,
|
|
749
|
+
SimplrAdmin,
|
|
231
750
|
SimplrError,
|
|
751
|
+
SimplrFlags,
|
|
752
|
+
SimplrProfiles,
|
|
753
|
+
SimplrRUM,
|
|
232
754
|
WebhookVerificationError,
|
|
233
755
|
constructWebhookEvent,
|
|
234
756
|
verifyWebhook
|