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