@simplr-ai/node 1.1.0 → 1.2.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/README.md +94 -2
- package/dist/index.cjs +523 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +322 -4
- package/dist/index.d.ts +322 -4
- package/dist/index.js +519 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -22,17 +22,128 @@ var WebhookVerificationError = class extends Error {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// src/network-log.ts
|
|
26
|
+
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
27
|
+
"authorization",
|
|
28
|
+
"cookie",
|
|
29
|
+
"set-cookie",
|
|
30
|
+
"x-api-key",
|
|
31
|
+
"x-auth-token",
|
|
32
|
+
"x-csrf-token",
|
|
33
|
+
"x-xsrf-token"
|
|
34
|
+
]);
|
|
35
|
+
var SENSITIVE_KEY_PARTS = [
|
|
36
|
+
"password",
|
|
37
|
+
"passwd",
|
|
38
|
+
"secret",
|
|
39
|
+
"token",
|
|
40
|
+
"api_key",
|
|
41
|
+
"apikey",
|
|
42
|
+
"authorization",
|
|
43
|
+
"auth",
|
|
44
|
+
"credential",
|
|
45
|
+
"private_key",
|
|
46
|
+
"card",
|
|
47
|
+
"cardnumber",
|
|
48
|
+
"pan",
|
|
49
|
+
"cvv",
|
|
50
|
+
"cvc",
|
|
51
|
+
"ssn",
|
|
52
|
+
"pin",
|
|
53
|
+
"otp"
|
|
54
|
+
];
|
|
55
|
+
var MAX_REDACT_DEPTH = 8;
|
|
56
|
+
var MAX_BODY_CHARS = 1e4;
|
|
57
|
+
function isSensitiveKey(key, extraKeys) {
|
|
58
|
+
const lower = key.toLowerCase();
|
|
59
|
+
if (extraKeys.some((k) => lower === k.toLowerCase())) return true;
|
|
60
|
+
return SENSITIVE_KEY_PARTS.some((part) => lower.includes(part));
|
|
61
|
+
}
|
|
62
|
+
function redactDeep(value, extraKeys, depth = 0) {
|
|
63
|
+
if (depth >= MAX_REDACT_DEPTH) return "[truncated]";
|
|
64
|
+
if (Array.isArray(value)) return value.map((v) => redactDeep(v, extraKeys, depth + 1));
|
|
65
|
+
if (value && typeof value === "object") {
|
|
66
|
+
const out = {};
|
|
67
|
+
for (const [key, val] of Object.entries(value)) {
|
|
68
|
+
out[key] = isSensitiveKey(key, extraKeys) ? "[REDACTED]" : redactDeep(val, extraKeys, depth + 1);
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function redactHeaders(headers) {
|
|
75
|
+
if (!headers) return void 0;
|
|
76
|
+
const out = {};
|
|
77
|
+
const set = (key, value) => {
|
|
78
|
+
out[key] = SENSITIVE_HEADERS.has(key.toLowerCase()) ? "[REDACTED]" : value;
|
|
79
|
+
};
|
|
80
|
+
if (typeof headers.forEach === "function" && !Array.isArray(headers)) {
|
|
81
|
+
headers.forEach((value, key) => set(key, value));
|
|
82
|
+
} else {
|
|
83
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
84
|
+
set(key, String(value));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
function previewBody(raw, redactFields = []) {
|
|
90
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
91
|
+
let value = raw;
|
|
92
|
+
if (typeof raw === "string") {
|
|
93
|
+
try {
|
|
94
|
+
value = JSON.parse(raw);
|
|
95
|
+
} catch {
|
|
96
|
+
return raw.length > MAX_BODY_CHARS ? raw.slice(0, MAX_BODY_CHARS) + "\u2026[truncated]" : raw;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const redacted = redactDeep(value, redactFields);
|
|
100
|
+
let text;
|
|
101
|
+
try {
|
|
102
|
+
text = JSON.stringify(redacted);
|
|
103
|
+
} catch {
|
|
104
|
+
return "[unserializable]";
|
|
105
|
+
}
|
|
106
|
+
if (text.length > MAX_BODY_CHARS) {
|
|
107
|
+
return text.slice(0, MAX_BODY_CHARS) + "\u2026[truncated]";
|
|
108
|
+
}
|
|
109
|
+
return redacted;
|
|
110
|
+
}
|
|
111
|
+
function newLogId() {
|
|
112
|
+
const uuid = globalThis?.crypto?.randomUUID;
|
|
113
|
+
if (typeof uuid === "function") return uuid.call(globalThis.crypto);
|
|
114
|
+
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
25
117
|
// src/http.ts
|
|
26
118
|
async function apiRequest(cfg, method, path, body) {
|
|
27
119
|
const controller = new AbortController();
|
|
28
120
|
const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);
|
|
121
|
+
const url = `${cfg.baseUrl}${path}`;
|
|
122
|
+
const requestHeaders = {
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
...cfg.authHeaders
|
|
125
|
+
};
|
|
126
|
+
const startedAt = Date.now();
|
|
127
|
+
const log = cfg.onNetworkLog ? {
|
|
128
|
+
id: newLogId(),
|
|
129
|
+
source: "backend",
|
|
130
|
+
timestamp: new Date(startedAt).toISOString(),
|
|
131
|
+
method,
|
|
132
|
+
url,
|
|
133
|
+
requestHeaders: redactHeaders(requestHeaders),
|
|
134
|
+
requestBody: cfg.logBodies ? previewBody(body, cfg.redactFields) : void 0
|
|
135
|
+
} : null;
|
|
136
|
+
const emit = (extra) => {
|
|
137
|
+
if (!log || !cfg.onNetworkLog) return;
|
|
138
|
+
try {
|
|
139
|
+
cfg.onNetworkLog({ ...log, durationMs: Date.now() - startedAt, ...extra });
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
};
|
|
29
143
|
try {
|
|
30
|
-
const res = await cfg.fetchImpl(
|
|
144
|
+
const res = await cfg.fetchImpl(url, {
|
|
31
145
|
method,
|
|
32
|
-
headers:
|
|
33
|
-
"Content-Type": "application/json",
|
|
34
|
-
...cfg.authHeaders
|
|
35
|
-
},
|
|
146
|
+
headers: requestHeaders,
|
|
36
147
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
37
148
|
signal: controller.signal
|
|
38
149
|
});
|
|
@@ -43,6 +154,13 @@ async function apiRequest(cfg, method, path, body) {
|
|
|
43
154
|
} catch {
|
|
44
155
|
parsed = text;
|
|
45
156
|
}
|
|
157
|
+
emit({
|
|
158
|
+
status: res.status,
|
|
159
|
+
statusText: res.statusText,
|
|
160
|
+
ok: res.ok,
|
|
161
|
+
responseHeaders: redactHeaders(res.headers),
|
|
162
|
+
responseBody: cfg.logBodies ? previewBody(parsed ?? text, cfg.redactFields) : void 0
|
|
163
|
+
});
|
|
46
164
|
if (!res.ok) {
|
|
47
165
|
const message = parsed && (parsed.message || parsed.error) || `Simplr API error ${res.status}`;
|
|
48
166
|
throw new SimplrError(message, res.status, parsed);
|
|
@@ -51,14 +169,68 @@ async function apiRequest(cfg, method, path, body) {
|
|
|
51
169
|
} catch (err) {
|
|
52
170
|
if (err instanceof SimplrError) throw err;
|
|
53
171
|
if (err instanceof Error && err.name === "AbortError") {
|
|
172
|
+
emit({ ok: false, error: `timed out after ${cfg.timeoutMs}ms` });
|
|
54
173
|
throw new SimplrError(`Request to ${path} timed out after ${cfg.timeoutMs}ms`, 0, null);
|
|
55
174
|
}
|
|
175
|
+
emit({ ok: false, error: err instanceof Error ? err.message : "Network error" });
|
|
56
176
|
throw new SimplrError(err instanceof Error ? err.message : "Network error", 0, null);
|
|
57
177
|
} finally {
|
|
58
178
|
clearTimeout(timer);
|
|
59
179
|
}
|
|
60
180
|
}
|
|
61
181
|
|
|
182
|
+
// src/network-shipper.ts
|
|
183
|
+
var DEFAULT_BATCH = 25;
|
|
184
|
+
var DEFAULT_FLUSH_MS = 5e3;
|
|
185
|
+
var NetworkLogShipper = class {
|
|
186
|
+
cfg;
|
|
187
|
+
queue = [];
|
|
188
|
+
timer = null;
|
|
189
|
+
constructor(cfg) {
|
|
190
|
+
this.cfg = cfg;
|
|
191
|
+
}
|
|
192
|
+
start() {
|
|
193
|
+
if (this.timer) return;
|
|
194
|
+
const interval = this.cfg.flushIntervalMs ?? DEFAULT_FLUSH_MS;
|
|
195
|
+
this.timer = setInterval(() => {
|
|
196
|
+
void this.flush();
|
|
197
|
+
}, interval);
|
|
198
|
+
this.timer?.unref?.();
|
|
199
|
+
}
|
|
200
|
+
add(entry) {
|
|
201
|
+
this.queue.push({
|
|
202
|
+
...entry,
|
|
203
|
+
sdk: this.cfg.sdk,
|
|
204
|
+
applicationId: entry.applicationId ?? this.cfg.applicationId,
|
|
205
|
+
environment: entry.environment ?? this.cfg.environment
|
|
206
|
+
});
|
|
207
|
+
if (this.queue.length >= (this.cfg.batchSize ?? DEFAULT_BATCH)) {
|
|
208
|
+
void this.flush();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async flush() {
|
|
212
|
+
if (this.queue.length === 0) return;
|
|
213
|
+
const logs = this.queue;
|
|
214
|
+
this.queue = [];
|
|
215
|
+
try {
|
|
216
|
+
await this.cfg.fetchImpl(`${this.cfg.baseUrl}/v1/network-logs`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
headers: {
|
|
219
|
+
"Content-Type": "application/json",
|
|
220
|
+
"X-API-Key": this.cfg.apiKey
|
|
221
|
+
},
|
|
222
|
+
body: JSON.stringify({ logs })
|
|
223
|
+
});
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
stop() {
|
|
228
|
+
if (this.timer) clearInterval(this.timer);
|
|
229
|
+
this.timer = null;
|
|
230
|
+
void this.flush();
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
62
234
|
// src/resources.ts
|
|
63
235
|
var OrdersResource = class {
|
|
64
236
|
constructor(cfg) {
|
|
@@ -161,7 +333,10 @@ var SimplrFlags = class {
|
|
|
161
333
|
authHeaders: { "X-API-Key": options.publicKey },
|
|
162
334
|
baseUrl: (options.baseUrl || "https://api.simplr.sh").replace(/\/+$/, ""),
|
|
163
335
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
164
|
-
fetchImpl: options.fetch ?? globalThis.fetch
|
|
336
|
+
fetchImpl: options.fetch ?? globalThis.fetch,
|
|
337
|
+
onNetworkLog: options.onNetworkLog,
|
|
338
|
+
logBodies: options.logBodies,
|
|
339
|
+
redactFields: options.redactFields
|
|
165
340
|
};
|
|
166
341
|
this.environment = options.environment;
|
|
167
342
|
this.refreshIntervalMs = options.refreshIntervalMs ?? 6e4;
|
|
@@ -183,7 +358,7 @@ var SimplrFlags = class {
|
|
|
183
358
|
}
|
|
184
359
|
/** Re-fetch the flag config (counts as one billable request). */
|
|
185
360
|
async refresh() {
|
|
186
|
-
const path = this.environment ? `/v1/flags?environment=${this.environment}` : "/v1/flags";
|
|
361
|
+
const path = this.environment ? `/v1/flags?environment=${encodeURIComponent(this.environment)}` : "/v1/flags";
|
|
187
362
|
try {
|
|
188
363
|
const content = await apiRequest(this.cfg, "GET", path);
|
|
189
364
|
const list = content?.flags || [];
|
|
@@ -219,6 +394,295 @@ var SimplrFlags = class {
|
|
|
219
394
|
}
|
|
220
395
|
};
|
|
221
396
|
|
|
397
|
+
// src/profiles.ts
|
|
398
|
+
var SimplrProfiles = class {
|
|
399
|
+
constructor(cfg) {
|
|
400
|
+
this.cfg = cfg;
|
|
401
|
+
}
|
|
402
|
+
cfg;
|
|
403
|
+
/**
|
|
404
|
+
* Identify a user — creates or updates an anonymous profile and (optionally)
|
|
405
|
+
* links a device fingerprint. POST /v1/profiles.
|
|
406
|
+
*/
|
|
407
|
+
identify(externalId, options) {
|
|
408
|
+
const { profileType, fingerprintHash, ...rest } = options ?? {};
|
|
409
|
+
const body = {
|
|
410
|
+
external_id: externalId,
|
|
411
|
+
profile_type: profileType || "customer",
|
|
412
|
+
...rest
|
|
413
|
+
};
|
|
414
|
+
if (fingerprintHash) body.fingerprint_hash = fingerprintHash;
|
|
415
|
+
return apiRequest(this.cfg, "POST", "/v1/profiles", body);
|
|
416
|
+
}
|
|
417
|
+
/** Submit an order for real-time fraud scoring. POST /v1/orders. */
|
|
418
|
+
submitOrder(order) {
|
|
419
|
+
return apiRequest(this.cfg, "POST", "/v1/orders", order);
|
|
420
|
+
}
|
|
421
|
+
/** Get the risk profile for a user. GET /v1/profiles/{externalId}. */
|
|
422
|
+
getProfileRisk(externalId) {
|
|
423
|
+
return apiRequest(
|
|
424
|
+
this.cfg,
|
|
425
|
+
"GET",
|
|
426
|
+
`/v1/profiles/${encodeURIComponent(externalId)}`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
/** Report a profile as fraud or legitimate. POST /v1/profiles/{externalId}/outcome. */
|
|
430
|
+
async reportOutcome(externalId, outcome) {
|
|
431
|
+
await apiRequest(
|
|
432
|
+
this.cfg,
|
|
433
|
+
"POST",
|
|
434
|
+
`/v1/profiles/${encodeURIComponent(externalId)}/outcome`,
|
|
435
|
+
{ outcome }
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// src/rum.ts
|
|
441
|
+
var DEFAULT_BATCH_SIZE = 30;
|
|
442
|
+
var DEFAULT_FLUSH_INTERVAL = 1e4;
|
|
443
|
+
var DEFAULT_ENDPOINT = "/v1/rum/events";
|
|
444
|
+
function genId() {
|
|
445
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
446
|
+
}
|
|
447
|
+
var SimplrRUM = class {
|
|
448
|
+
constructor(cfg) {
|
|
449
|
+
this.cfg = cfg;
|
|
450
|
+
}
|
|
451
|
+
cfg;
|
|
452
|
+
config = null;
|
|
453
|
+
initialized = false;
|
|
454
|
+
queue = [];
|
|
455
|
+
timer = null;
|
|
456
|
+
flushing = false;
|
|
457
|
+
sessionId = null;
|
|
458
|
+
currentViewId = null;
|
|
459
|
+
userId;
|
|
460
|
+
userAttributes;
|
|
461
|
+
globalAttributes = {};
|
|
462
|
+
batchSize = DEFAULT_BATCH_SIZE;
|
|
463
|
+
endpoint = DEFAULT_ENDPOINT;
|
|
464
|
+
/** Initialize the SDK, start a session, and begin the flush timer. */
|
|
465
|
+
initialize(config) {
|
|
466
|
+
if (this.initialized) return;
|
|
467
|
+
this.config = config;
|
|
468
|
+
this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
469
|
+
this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;
|
|
470
|
+
this.sessionId = genId();
|
|
471
|
+
this.initialized = true;
|
|
472
|
+
this.trackEvent("session_start");
|
|
473
|
+
const interval = config.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
|
|
474
|
+
if (interval > 0) {
|
|
475
|
+
this.timer = setInterval(() => {
|
|
476
|
+
void this.flush();
|
|
477
|
+
}, interval);
|
|
478
|
+
this.timer?.unref?.();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
isInitialized() {
|
|
482
|
+
return this.initialized;
|
|
483
|
+
}
|
|
484
|
+
/** Associate subsequent events with a user. */
|
|
485
|
+
setUser(userId, attributes) {
|
|
486
|
+
this.userId = userId;
|
|
487
|
+
this.userAttributes = attributes;
|
|
488
|
+
}
|
|
489
|
+
clearUser() {
|
|
490
|
+
this.userId = void 0;
|
|
491
|
+
this.userAttributes = void 0;
|
|
492
|
+
}
|
|
493
|
+
addAttribute(key, value) {
|
|
494
|
+
this.globalAttributes[key] = value;
|
|
495
|
+
}
|
|
496
|
+
removeAttribute(key) {
|
|
497
|
+
delete this.globalAttributes[key];
|
|
498
|
+
}
|
|
499
|
+
/** Track a screen/page view. */
|
|
500
|
+
trackView(name, attributes) {
|
|
501
|
+
if (!this.initialized) return;
|
|
502
|
+
this.currentViewId = genId();
|
|
503
|
+
this.trackEvent("view", {
|
|
504
|
+
view: { id: this.currentViewId, name },
|
|
505
|
+
attributes
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
/** Track a user action. */
|
|
509
|
+
trackAction(name, attributes) {
|
|
510
|
+
if (!this.initialized) return;
|
|
511
|
+
this.trackEvent("action", { action: { name, type: "custom" }, attributes });
|
|
512
|
+
}
|
|
513
|
+
/** Track an error. */
|
|
514
|
+
trackError(error, attributes) {
|
|
515
|
+
if (!this.initialized) return;
|
|
516
|
+
const data = error instanceof Error ? { message: error.message, stack: error.stack, type: error.constructor.name } : error;
|
|
517
|
+
this.trackEvent("error", { error: data, attributes });
|
|
518
|
+
}
|
|
519
|
+
/** Emit a log line. */
|
|
520
|
+
log(level, message, attributes) {
|
|
521
|
+
if (!this.initialized) return;
|
|
522
|
+
this.trackEvent("log", { log: { level, message }, attributes });
|
|
523
|
+
}
|
|
524
|
+
trackEvent(type, data) {
|
|
525
|
+
if (!this.initialized || !this.sessionId) return;
|
|
526
|
+
const event = {
|
|
527
|
+
type,
|
|
528
|
+
timestamp: Date.now(),
|
|
529
|
+
sessionId: this.sessionId,
|
|
530
|
+
viewId: this.currentViewId || void 0,
|
|
531
|
+
userId: this.userId,
|
|
532
|
+
applicationId: this.config.applicationId,
|
|
533
|
+
applicationVersion: this.config?.applicationVersion,
|
|
534
|
+
environment: this.config?.environment,
|
|
535
|
+
userAttributes: this.userAttributes,
|
|
536
|
+
globalAttributes: Object.keys(this.globalAttributes).length > 0 ? this.globalAttributes : void 0,
|
|
537
|
+
...data
|
|
538
|
+
};
|
|
539
|
+
this.queue.push(event);
|
|
540
|
+
if (this.queue.length >= this.batchSize) void this.flush();
|
|
541
|
+
}
|
|
542
|
+
/** Flush queued events to POST /v1/rum/events. */
|
|
543
|
+
async flush() {
|
|
544
|
+
if (this.flushing || this.queue.length === 0) return;
|
|
545
|
+
this.flushing = true;
|
|
546
|
+
const events = this.queue;
|
|
547
|
+
this.queue = [];
|
|
548
|
+
try {
|
|
549
|
+
await apiRequest(this.cfg, "POST", this.endpoint, {
|
|
550
|
+
events,
|
|
551
|
+
sentAt: Date.now()
|
|
552
|
+
});
|
|
553
|
+
} catch {
|
|
554
|
+
this.queue = [...events, ...this.queue];
|
|
555
|
+
} finally {
|
|
556
|
+
this.flushing = false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/** End the session, flush remaining events, and stop the timer. */
|
|
560
|
+
async stopSession() {
|
|
561
|
+
if (!this.initialized) return;
|
|
562
|
+
this.trackEvent("session_end");
|
|
563
|
+
await this.flush();
|
|
564
|
+
if (this.timer) {
|
|
565
|
+
clearInterval(this.timer);
|
|
566
|
+
this.timer = null;
|
|
567
|
+
}
|
|
568
|
+
this.initialized = false;
|
|
569
|
+
}
|
|
570
|
+
getSessionId() {
|
|
571
|
+
return this.sessionId;
|
|
572
|
+
}
|
|
573
|
+
getViewId() {
|
|
574
|
+
return this.currentViewId;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
// src/ai.ts
|
|
579
|
+
function mapDelegation(d) {
|
|
580
|
+
return {
|
|
581
|
+
delegationId: d.delegation_id,
|
|
582
|
+
endUserId: d.end_user_id,
|
|
583
|
+
bindingMode: d.binding_mode,
|
|
584
|
+
status: d.status,
|
|
585
|
+
expiresAt: d.expires_at,
|
|
586
|
+
useCount: d.use_count,
|
|
587
|
+
lastUsedAt: d.last_used_at,
|
|
588
|
+
createdAt: d.created_at
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
var SimplrAI = class {
|
|
592
|
+
constructor(cfg) {
|
|
593
|
+
this.cfg = cfg;
|
|
594
|
+
}
|
|
595
|
+
cfg;
|
|
596
|
+
/** Create a new AI delegation token for a user. POST /v1/ai/delegations. */
|
|
597
|
+
async createDelegation(options) {
|
|
598
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/delegations", {
|
|
599
|
+
end_user_id: options.userId,
|
|
600
|
+
end_user_email: options.email,
|
|
601
|
+
binding: options.binding || "any_location",
|
|
602
|
+
expires_in_days: options.expiresInDays || 7,
|
|
603
|
+
session_id: options.sessionId,
|
|
604
|
+
fingerprint_hash: options.fingerprintHash
|
|
605
|
+
});
|
|
606
|
+
const d = content.delegation;
|
|
607
|
+
return {
|
|
608
|
+
token: d.token,
|
|
609
|
+
delegationId: d.delegation_id,
|
|
610
|
+
expiresAt: d.expires_at,
|
|
611
|
+
bindingMode: d.binding_mode
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
/** Validate (introspect) an AI delegation token. POST /v1/ai/validate. */
|
|
615
|
+
async validate(token, options) {
|
|
616
|
+
try {
|
|
617
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/validate", {
|
|
618
|
+
token,
|
|
619
|
+
fingerprint_hash: options?.fingerprintHash,
|
|
620
|
+
ai_provider: options?.aiProvider,
|
|
621
|
+
action: options?.action
|
|
622
|
+
});
|
|
623
|
+
return {
|
|
624
|
+
valid: true,
|
|
625
|
+
sessionType: content.session_type,
|
|
626
|
+
endUserId: content.end_user_id,
|
|
627
|
+
delegation: content.delegation ? {
|
|
628
|
+
delegationId: content.delegation.delegation_id,
|
|
629
|
+
bindingMode: content.delegation.binding_mode,
|
|
630
|
+
expiresAt: content.delegation.expires_at,
|
|
631
|
+
useCount: content.delegation.use_count
|
|
632
|
+
} : void 0
|
|
633
|
+
};
|
|
634
|
+
} catch (err) {
|
|
635
|
+
return { valid: false, error: err instanceof Error ? err.message : "Validation failed" };
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/** Revoke a delegation. POST /v1/ai/delegations/{id}/revoke. */
|
|
639
|
+
async revoke(delegationId, reason) {
|
|
640
|
+
await apiRequest(
|
|
641
|
+
this.cfg,
|
|
642
|
+
"POST",
|
|
643
|
+
`/v1/ai/delegations/${encodeURIComponent(delegationId)}/revoke`,
|
|
644
|
+
{ reason }
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
/** List delegations, optionally filtered by user. GET /v1/ai/delegations. */
|
|
648
|
+
async list(userId) {
|
|
649
|
+
const path = userId ? `/v1/ai/delegations?end_user_id=${encodeURIComponent(userId)}` : "/v1/ai/delegations";
|
|
650
|
+
const content = await apiRequest(this.cfg, "GET", path);
|
|
651
|
+
return (content.delegations || []).map(mapDelegation);
|
|
652
|
+
}
|
|
653
|
+
/** Get a single delegation. GET /v1/ai/delegations/{id}. */
|
|
654
|
+
async get(delegationId) {
|
|
655
|
+
const content = await apiRequest(
|
|
656
|
+
this.cfg,
|
|
657
|
+
"GET",
|
|
658
|
+
`/v1/ai/delegations/${encodeURIComponent(delegationId)}`
|
|
659
|
+
);
|
|
660
|
+
return mapDelegation(content.delegation);
|
|
661
|
+
}
|
|
662
|
+
/** Get delegation statistics. GET /v1/ai/stats. */
|
|
663
|
+
async stats() {
|
|
664
|
+
const content = await apiRequest(this.cfg, "GET", "/v1/ai/stats");
|
|
665
|
+
const s = content.stats;
|
|
666
|
+
return {
|
|
667
|
+
totalDelegations: s.total_delegations,
|
|
668
|
+
activeDelegations: s.active_delegations,
|
|
669
|
+
totalUses: s.total_uses,
|
|
670
|
+
delegationsByBinding: {
|
|
671
|
+
verifiedDevice: s.delegations_by_binding.verified_device,
|
|
672
|
+
anyLocation: s.delegations_by_binding.any_location
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
/** Revoke all delegations for a user (e.g. on logout). POST /v1/ai/revoke-all. */
|
|
677
|
+
async revokeAllForUser(userId, reason) {
|
|
678
|
+
const content = await apiRequest(this.cfg, "POST", "/v1/ai/revoke-all", {
|
|
679
|
+
end_user_id: userId,
|
|
680
|
+
reason
|
|
681
|
+
});
|
|
682
|
+
return content.revoked_count;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
222
686
|
// src/webhooks.ts
|
|
223
687
|
var webhooks_exports = {};
|
|
224
688
|
__export(webhooks_exports, {
|
|
@@ -365,16 +829,43 @@ var Simplr = class {
|
|
|
365
829
|
orders;
|
|
366
830
|
phone;
|
|
367
831
|
edge;
|
|
832
|
+
/** Anonymous user profiles + order fraud monitoring. */
|
|
833
|
+
profiles;
|
|
834
|
+
/** Real User Monitoring — batched events to /v1/rum/events. */
|
|
835
|
+
rum;
|
|
836
|
+
/** AI delegation — OAuth-like AI authentication. */
|
|
837
|
+
ai;
|
|
368
838
|
/** Webhook signature helpers (no network). */
|
|
369
839
|
webhooks = webhooks_exports;
|
|
370
840
|
_flags;
|
|
841
|
+
shipper;
|
|
371
842
|
constructor(options) {
|
|
372
843
|
if (!options?.apiKey) throw new Error("Simplr: `apiKey` is required");
|
|
844
|
+
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
845
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
846
|
+
if (options.shipNetworkLogs) {
|
|
847
|
+
this.shipper = new NetworkLogShipper({
|
|
848
|
+
baseUrl,
|
|
849
|
+
apiKey: options.apiKey,
|
|
850
|
+
fetchImpl,
|
|
851
|
+
sdk: "node",
|
|
852
|
+
applicationId: options.applicationId,
|
|
853
|
+
environment: options.environment
|
|
854
|
+
});
|
|
855
|
+
this.shipper.start();
|
|
856
|
+
}
|
|
857
|
+
const onNetworkLog = this.shipper || options.onNetworkLog ? (entry) => {
|
|
858
|
+
this.shipper?.add(entry);
|
|
859
|
+
options.onNetworkLog?.(entry);
|
|
860
|
+
} : void 0;
|
|
373
861
|
this.cfg = {
|
|
374
862
|
authHeaders: { "X-API-Key": options.apiKey },
|
|
375
|
-
baseUrl
|
|
863
|
+
baseUrl,
|
|
376
864
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
377
|
-
fetchImpl
|
|
865
|
+
fetchImpl,
|
|
866
|
+
onNetworkLog,
|
|
867
|
+
logBodies: options.logBodies ?? options.shipNetworkLogs,
|
|
868
|
+
redactFields: options.redactFields
|
|
378
869
|
};
|
|
379
870
|
if (typeof this.cfg.fetchImpl !== "function") {
|
|
380
871
|
throw new Error("Simplr: no global fetch available \u2014 use Node 18+ or pass `fetch` in options");
|
|
@@ -382,12 +873,19 @@ var Simplr = class {
|
|
|
382
873
|
this.orders = new OrdersResource(this.cfg);
|
|
383
874
|
this.phone = new PhoneResource(this.cfg);
|
|
384
875
|
this.edge = new EdgeResource(this.cfg);
|
|
876
|
+
this.profiles = new SimplrProfiles(this.cfg);
|
|
877
|
+
this.rum = new SimplrRUM(this.cfg);
|
|
878
|
+
this.ai = new SimplrAI(this.cfg);
|
|
385
879
|
if (options.publicKey) {
|
|
386
880
|
this._flags = new SimplrFlags({
|
|
387
881
|
publicKey: options.publicKey,
|
|
882
|
+
environment: options.environment,
|
|
388
883
|
baseUrl: this.cfg.baseUrl,
|
|
389
884
|
timeoutMs: this.cfg.timeoutMs,
|
|
390
|
-
fetch: this.cfg.fetchImpl
|
|
885
|
+
fetch: this.cfg.fetchImpl,
|
|
886
|
+
onNetworkLog: this.cfg.onNetworkLog,
|
|
887
|
+
logBodies: this.cfg.logBodies,
|
|
888
|
+
redactFields: options.redactFields
|
|
391
889
|
});
|
|
392
890
|
}
|
|
393
891
|
}
|
|
@@ -411,13 +909,24 @@ var Simplr = class {
|
|
|
411
909
|
checkBulk(items) {
|
|
412
910
|
return apiRequest(this.cfg, "POST", "/v1/check/bulk", { items });
|
|
413
911
|
}
|
|
912
|
+
flushNetworkLogs() {
|
|
913
|
+
return this.shipper?.flush() ?? Promise.resolve();
|
|
914
|
+
}
|
|
915
|
+
close() {
|
|
916
|
+
this.shipper?.stop();
|
|
917
|
+
this._flags?.dispose();
|
|
918
|
+
}
|
|
414
919
|
};
|
|
415
920
|
var src_default = Simplr;
|
|
416
921
|
export {
|
|
922
|
+
NetworkLogShipper,
|
|
417
923
|
Simplr,
|
|
924
|
+
SimplrAI,
|
|
418
925
|
SimplrAdmin,
|
|
419
926
|
SimplrError,
|
|
420
927
|
SimplrFlags,
|
|
928
|
+
SimplrProfiles,
|
|
929
|
+
SimplrRUM,
|
|
421
930
|
WebhookVerificationError,
|
|
422
931
|
constructEvent as constructWebhookEvent,
|
|
423
932
|
src_default as default,
|