@letsping/sdk 0.1.3 → 0.1.5

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 CHANGED
@@ -2,7 +2,12 @@
2
2
 
3
3
  The official Node.js/TypeScript SDK for [LetsPing](https://letsping.co).
4
4
 
5
- LetsPing is the Human-in-the-Loop control plane for autonomous agents the durable state layer that pauses execution before sensitive actions, persists encrypted agent state, and resumes only after explicit human approval (or rejection/correction).
5
+ LetsPing is a behavioral firewall and Human-in-the-Loop (HITL) infrastructure layer for Agentic AI. It provides mathematically secure state-parking (Cryo-Sleep) and execution governance for autonomous agents built on frameworks like LangGraph, Vercel AI SDK, and custom architectures.
6
+
7
+ ### Features
8
+ - **The Behavioral Shield:** Silently profiles your agent's execution paths via Markov Chains. Automatically intercepts 0-probability reasoning anomalies (hallucinations/prompt injections).
9
+ - **Cryo-Sleep State Parking:** Pauses execution and securely uploads massive agent states directly to storage using Signed URLs, entirely bypassing serverless timeouts and webhook payload limits.
10
+ - **Smart-Accept Drift Adaptation:** Approval decisions mathematically alter the baseline. Old unused reasoning paths decay automatically via Exponential Moving Average (EMA).
6
11
 
7
12
  ## Requirements
8
13
 
@@ -78,12 +83,30 @@ const { id } = await lp.defer({
78
83
  subject: "Your invoice is ready",
79
84
  amount: 249.99
80
85
  },
81
- priority: "medium"
86
+ priority: "medium",
87
+ // Optional: Pass the full LangGraph/Vercel state dict.
88
+ // It will be encrypted client-side and uploaded directly to S3.
89
+ state_snapshot: agentState
82
90
  });
83
91
 
84
92
  console.log(`Approval request queued → ${id}`);
85
93
  ```
86
94
 
95
+ ### Webhook Rehydration (Framework Agnostic)
96
+ LetsPing does **not** magically inject state back into your framework natively. You must handle the webhook and rehydrate your specific framework manually.
97
+
98
+ ```typescript
99
+ // Example Webhook Route Handler
100
+ if (body.status === "APPROVED") {
101
+ let hydratedState = null;
102
+ if (body.state_download_url) {
103
+ const res = await fetch(body.state_download_url);
104
+ hydratedState = lp._decrypt(await res.json());
105
+ }
106
+ // Manually push `hydratedState` back into your LangGraph/Vercel thread
107
+ }
108
+ ```
109
+
87
110
  ## API Reference
88
111
 
89
112
  ### `new LetsPing(apiKey, options?)`
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface RequestOptions {
5
5
  payload: Record<string, any>;
6
6
  priority?: Priority;
7
7
  schema?: Record<string, any>;
8
+ state_snapshot?: Record<string, any>;
8
9
  timeoutMs?: number;
9
10
  role?: string;
10
11
  }
@@ -34,11 +35,18 @@ export declare class LetsPing {
34
35
  });
35
36
  private _encrypt;
36
37
  private _decrypt;
38
+ private _prepareStateUpload;
37
39
  ask(options: RequestOptions): Promise<Decision>;
38
40
  defer(options: RequestOptions): Promise<{
39
41
  id: string;
40
42
  }>;
41
43
  private request;
42
44
  tool(service: string, action: string, priority?: Priority): (context: string | Record<string, any>) => Promise<string>;
45
+ webhookHandler(payloadStr: string, signatureHeader: string, webhookSecret: string): Promise<{
46
+ id: string;
47
+ event: string;
48
+ data: Decision;
49
+ state_snapshot?: Record<string, any>;
50
+ }>;
43
51
  }
44
52
  export { computeDiff };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __commonJS = (cb, mod) => function __require() {
7
9
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
@@ -18,6 +20,14 @@ var __copyProps = (to, from, except, desc) => {
18
20
  }
19
21
  return to;
20
22
  };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
21
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
32
 
23
33
  // package.json
@@ -25,13 +35,10 @@ var require_package = __commonJS({
25
35
  "package.json"(exports2, module2) {
26
36
  module2.exports = {
27
37
  name: "@letsping/sdk",
28
- version: "0.1.3",
29
- description: "The Human-in-the-Loop SDK for Autonomous Agents",
38
+ version: "0.1.5",
39
+ description: "Behavioral Firewall and Cryo-Sleep State Parking for Autonomous Agents",
30
40
  main: "./dist/index.js",
31
41
  module: "./dist/index.mjs",
32
- files: [
33
- "dist"
34
- ],
35
42
  types: "./dist/index.d.ts",
36
43
  exports: {
37
44
  ".": {
@@ -46,10 +53,19 @@ var require_package = __commonJS({
46
53
  clean: "rm -rf dist .turbo"
47
54
  },
48
55
  dependencies: {},
56
+ peerDependencies: {
57
+ "@opentelemetry/api": "^1.0.0"
58
+ },
59
+ peerDependenciesMeta: {
60
+ "@opentelemetry/api": {
61
+ optional: true
62
+ }
63
+ },
49
64
  devDependencies: {
50
65
  tsup: "^8.0.0",
51
66
  typescript: "^5.7.2",
52
- "@types/node": "^22.0.0"
67
+ "@types/node": "^22.0.0",
68
+ "@opentelemetry/api": "^1.9.0"
53
69
  },
54
70
  publishConfig: {
55
71
  access: "public"
@@ -67,11 +83,22 @@ __export(index_exports, {
67
83
  });
68
84
  module.exports = __toCommonJS(index_exports);
69
85
  var import_node_crypto = require("crypto");
70
- var SDK_VERSION = "0.1.2";
86
+ var SDK_VERSION = "0.1.5";
71
87
  try {
72
88
  SDK_VERSION = require_package().version;
73
89
  } catch {
74
90
  }
91
+ var otelApi = null;
92
+ var otelTried = false;
93
+ async function getOtel() {
94
+ if (otelTried) return otelApi;
95
+ otelTried = true;
96
+ try {
97
+ otelApi = await import("@opentelemetry/api");
98
+ } catch {
99
+ }
100
+ return otelApi;
101
+ }
75
102
  var LetsPingError = class extends Error {
76
103
  constructor(message, status) {
77
104
  super(message);
@@ -155,61 +182,168 @@ var LetsPing = class {
155
182
  return val;
156
183
  }
157
184
  }
185
+ _prepareStateUpload(stateSnapshot, fallbackDek) {
186
+ if (this.encryptionKey) {
187
+ return {
188
+ data: this._encrypt(stateSnapshot),
189
+ contentType: "application/json"
190
+ };
191
+ } else if (fallbackDek) {
192
+ const keyBuf = Buffer.from(fallbackDek, "base64");
193
+ const iv = (0, import_node_crypto.randomBytes)(12);
194
+ const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", keyBuf, iv);
195
+ const plain = Buffer.from(JSON.stringify(stateSnapshot), "utf8");
196
+ const ct = Buffer.concat([cipher.update(plain), cipher.final(), cipher.getAuthTag()]);
197
+ const finalPayload = Buffer.concat([iv, ct]);
198
+ return {
199
+ data: finalPayload,
200
+ contentType: "application/octet-stream"
201
+ };
202
+ }
203
+ return {
204
+ data: stateSnapshot,
205
+ contentType: "application/json"
206
+ };
207
+ }
158
208
  async ask(options) {
159
209
  if (options.schema && options.schema._def) {
160
210
  throw new LetsPingError("LetsPing Error: Raw Zod schema detected. You must convert it to JSON Schema (e.g. using 'zod-to-json-schema') before passing it to the SDK.");
161
211
  }
162
- const { id } = await this.request("POST", "/ingest", {
163
- service: options.service,
164
- action: options.action,
165
- payload: this._encrypt(options.payload),
166
- priority: options.priority || "medium",
167
- schema: options.schema,
168
- metadata: { role: options.role, sdk: "node" }
169
- });
170
- const timeout = options.timeoutMs || 24 * 60 * 60 * 1e3;
171
- const start = Date.now();
172
- let delay = 1e3;
173
- const maxDelay = 1e4;
174
- while (Date.now() - start < timeout) {
175
- try {
176
- const check = await this.request("GET", `/status/${id}`);
177
- if (check.status === "APPROVED" || check.status === "REJECTED") {
178
- const decryptedPayload = this._decrypt(check.payload) ?? options.payload;
179
- const decryptedPatched = check.patched_payload ? this._decrypt(check.patched_payload) : void 0;
180
- let diff_summary;
181
- let finalStatus = check.status;
182
- if (check.status === "APPROVED" && decryptedPatched !== void 0) {
183
- finalStatus = "APPROVED_WITH_MODIFICATIONS";
184
- const diff = computeDiff(decryptedPayload, decryptedPatched);
185
- diff_summary = diff ? { changes: diff } : { changes: "Unknown structure changes" };
212
+ const otel = await getOtel();
213
+ let span = null;
214
+ if (otel && otel.trace) {
215
+ const tracer = otel.trace.getTracer("letsping-sdk");
216
+ span = tracer.startSpan(`letsping.ask`, {
217
+ attributes: {
218
+ "letsping.service": options.service,
219
+ "letsping.action": options.action,
220
+ "letsping.priority": options.priority || "medium"
221
+ }
222
+ });
223
+ }
224
+ try {
225
+ const res = await this.request("POST", "/ingest", {
226
+ service: options.service,
227
+ action: options.action,
228
+ payload: this._encrypt(options.payload),
229
+ priority: options.priority || "medium",
230
+ schema: options.schema,
231
+ metadata: { role: options.role, sdk: "node" }
232
+ });
233
+ const { id, uploadUrl, dek } = res;
234
+ if (uploadUrl && options.state_snapshot) {
235
+ try {
236
+ const { data, contentType } = this._prepareStateUpload(options.state_snapshot, dek);
237
+ const putRes = await fetch(uploadUrl, {
238
+ method: "PUT",
239
+ headers: { "Content-Type": contentType },
240
+ body: Buffer.isBuffer(data) ? data : JSON.stringify(data)
241
+ });
242
+ if (!putRes.ok) {
243
+ console.warn("LetsPing: Failed to upload state_snapshot to storage", await putRes.text());
186
244
  }
187
- return {
188
- status: finalStatus,
189
- payload: decryptedPayload,
190
- patched_payload: decryptedPatched,
191
- diff_summary,
192
- metadata: {
193
- resolved_at: check.resolved_at,
194
- actor_id: check.actor_id
245
+ } catch (e) {
246
+ console.warn("LetsPing: Exception uploading state_snapshot", e.message);
247
+ }
248
+ }
249
+ if (span) span.setAttribute("letsping.request_id", id);
250
+ const timeout = options.timeoutMs || 24 * 60 * 60 * 1e3;
251
+ const start = Date.now();
252
+ let delay = 1e3;
253
+ const maxDelay = 1e4;
254
+ while (Date.now() - start < timeout) {
255
+ try {
256
+ const check = await this.request("GET", `/status/${id}`);
257
+ if (check.status === "APPROVED" || check.status === "REJECTED") {
258
+ const decryptedPayload = this._decrypt(check.payload) ?? options.payload;
259
+ const decryptedPatched = check.patched_payload ? this._decrypt(check.patched_payload) : void 0;
260
+ let diff_summary;
261
+ let finalStatus = check.status;
262
+ if (check.status === "APPROVED" && decryptedPatched !== void 0) {
263
+ finalStatus = "APPROVED_WITH_MODIFICATIONS";
264
+ const diff = computeDiff(decryptedPayload, decryptedPatched);
265
+ diff_summary = diff ? { changes: diff } : { changes: "Unknown structure changes" };
266
+ }
267
+ if (span) {
268
+ span.setAttribute("letsping.status", finalStatus);
269
+ if (check.actor_id) span.setAttribute("letsping.actor_id", check.actor_id);
270
+ span.end();
195
271
  }
196
- };
272
+ return {
273
+ status: finalStatus,
274
+ payload: decryptedPayload,
275
+ patched_payload: decryptedPatched,
276
+ diff_summary,
277
+ metadata: {
278
+ resolved_at: check.resolved_at,
279
+ actor_id: check.actor_id
280
+ }
281
+ };
282
+ }
283
+ } catch (e) {
284
+ const s = e.status;
285
+ if (s && s >= 400 && s < 500 && s !== 404 && s !== 429) throw e;
197
286
  }
198
- } catch (e) {
199
- const s = e.status;
200
- if (s && s >= 400 && s < 500 && s !== 404 && s !== 429) throw e;
287
+ const jitter = Math.random() * 200;
288
+ await new Promise((r) => setTimeout(r, delay + jitter));
289
+ delay = Math.min(delay * 1.5, maxDelay);
290
+ }
291
+ throw new LetsPingError(`Request ${id} timed out waiting for approval.`);
292
+ } catch (error) {
293
+ if (span) {
294
+ span.recordException(error);
295
+ span.setStatus({ code: otel.SpanStatusCode.ERROR });
296
+ span.end();
201
297
  }
202
- const jitter = Math.random() * 200;
203
- await new Promise((r) => setTimeout(r, delay + jitter));
204
- delay = Math.min(delay * 1.5, maxDelay);
298
+ throw error;
205
299
  }
206
- throw new LetsPingError(`Request ${id} timed out waiting for approval.`);
207
300
  }
208
301
  async defer(options) {
209
- return this.request("POST", "/ingest", {
210
- ...options,
211
- payload: this._encrypt(options.payload)
212
- });
302
+ const otel = await getOtel();
303
+ let span = null;
304
+ if (otel && otel.trace) {
305
+ const tracer = otel.trace.getTracer("letsping-sdk");
306
+ span = tracer.startSpan(`letsping.defer`, {
307
+ attributes: {
308
+ "letsping.service": options.service,
309
+ "letsping.action": options.action,
310
+ "letsping.priority": options.priority || "medium"
311
+ }
312
+ });
313
+ }
314
+ try {
315
+ const res = await this.request("POST", "/ingest", {
316
+ ...options,
317
+ payload: this._encrypt(options.payload)
318
+ });
319
+ if (res.uploadUrl && options.state_snapshot) {
320
+ try {
321
+ const { data, contentType } = this._prepareStateUpload(options.state_snapshot, res.dek);
322
+ const putRes = await fetch(res.uploadUrl, {
323
+ method: "PUT",
324
+ headers: { "Content-Type": contentType },
325
+ body: Buffer.isBuffer(data) ? data : JSON.stringify(data)
326
+ });
327
+ if (!putRes.ok) {
328
+ console.warn("LetsPing: Failed to upload state_snapshot to storage", await putRes.text());
329
+ }
330
+ } catch (e) {
331
+ console.warn("LetsPing: Exception uploading state_snapshot", e.message);
332
+ }
333
+ }
334
+ if (span) {
335
+ span.setAttribute("letsping.request_id", res.id);
336
+ span.end();
337
+ }
338
+ return { id: res.id };
339
+ } catch (error) {
340
+ if (span) {
341
+ span.recordException(error);
342
+ span.setStatus({ code: otel.SpanStatusCode.ERROR });
343
+ span.end();
344
+ }
345
+ throw error;
346
+ }
213
347
  }
214
348
  async request(method, path, body) {
215
349
  const headers = {
@@ -276,6 +410,55 @@ var LetsPing = class {
276
410
  }
277
411
  };
278
412
  }
413
+ async webhookHandler(payloadStr, signatureHeader, webhookSecret) {
414
+ const hmac = (0, import_node_crypto.createHmac)("sha256", webhookSecret).update(payloadStr).digest("hex");
415
+ const sigParts = signatureHeader.split(",").map((p) => p.split("="));
416
+ const sigMap = Object.fromEntries(sigParts);
417
+ if (sigMap["v1"] !== hmac) {
418
+ throw new LetsPingError("LetsPing Error: Invalid webhook signature", 401);
419
+ }
420
+ const payload = JSON.parse(payloadStr);
421
+ const data = payload.data;
422
+ let state_snapshot = void 0;
423
+ if (data && data.state_download_url) {
424
+ try {
425
+ const res = await fetch(data.state_download_url);
426
+ if (res.ok) {
427
+ const contentType = res.headers.get("content-type") || "";
428
+ if (contentType.includes("application/octet-stream")) {
429
+ const fallbackDek = data.dek;
430
+ if (fallbackDek) {
431
+ const buffer = Buffer.from(await res.arrayBuffer());
432
+ const keyBuf = Buffer.from(fallbackDek, "base64");
433
+ const iv = buffer.subarray(0, 12);
434
+ const ctFull = buffer.subarray(12);
435
+ const authTag = ctFull.subarray(ctFull.length - 16);
436
+ const ct = ctFull.subarray(0, ctFull.length - 16);
437
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", keyBuf, iv);
438
+ decipher.setAuthTag(authTag);
439
+ const plain = Buffer.concat([decipher.update(ct), decipher.final()]);
440
+ state_snapshot = JSON.parse(plain.toString("utf8"));
441
+ } else {
442
+ console.warn("LetsPing: Missing fallback DEK to decrypt octet-stream storage file");
443
+ }
444
+ } else {
445
+ const encState = await res.json();
446
+ state_snapshot = this._decrypt(encState);
447
+ }
448
+ } else {
449
+ console.warn("LetsPing: Could not fetch state_snapshot from storage", await res.text());
450
+ }
451
+ } catch (e) {
452
+ console.warn("LetsPing: Exception downloading state_snapshot from webhook url", e.message);
453
+ }
454
+ }
455
+ return {
456
+ id: payload.id,
457
+ event: payload.event,
458
+ data,
459
+ state_snapshot
460
+ };
461
+ }
279
462
  };
280
463
  // Annotate the CommonJS export names for ESM import in node:
281
464
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@letsping/sdk\",\n \"version\": \"0.1.3\",\n \"description\": \"The Human-in-the-Loop SDK for Autonomous Agents\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.mjs\",\n \"files\": [\n \"dist\"\n ],\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup && tsc --emitDeclarationOnly --outDir dist\",\n \"dev\": \"tsup --watch\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"dependencies\": {},\n \"devDependencies\": {\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.7.2\",\n \"@types/node\": \"^22.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}","import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\r\n\nlet SDK_VERSION = \"0.1.2\";\r\ntry {\r\n \n SDK_VERSION = require(\"../package.json\").version;\r\n} catch { }\r\n\r\nexport type Priority = \"low\" | \"medium\" | \"high\" | \"critical\";\r\n\nexport interface RequestOptions {\r\n \r\n service: string;\r\n \r\n action: string;\r\n \r\n payload: Record<string, any>;\r\n \r\n priority?: Priority;\r\n \r\n schema?: Record<string, any>;\r\n \r\n timeoutMs?: number;\r\n \r\n role?: string;\r\n}\r\n\nexport interface Decision {\r\n status: \"APPROVED\" | \"REJECTED\" | \"APPROVED_WITH_MODIFICATIONS\";\r\n \r\n payload: any;\r\n \r\n patched_payload?: any;\r\n \r\n diff_summary?: any;\r\n metadata?: {\r\n resolved_at: string;\r\n actor_id: string;\r\n method?: string;\r\n };\r\n}\r\n\r\nexport class LetsPingError extends Error {\r\n constructor(message: string, public status?: number) {\r\n super(message);\r\n this.name = \"LetsPingError\";\r\n }\r\n}\r\n\ninterface EncEnvelope {\r\n _lp_enc: true;\r\n iv: string; \n ct: string; \n}\r\n\r\nfunction isEncEnvelope(v: unknown): v is EncEnvelope {\r\n return (\r\n typeof v === \"object\" && v !== null &&\r\n (v as any)._lp_enc === true &&\r\n typeof (v as any).iv === \"string\" &&\r\n typeof (v as any).ct === \"string\"\r\n );\r\n}\r\n\r\nfunction encryptPayload(keyBase64: string, payload: Record<string, any>): EncEnvelope {\r\n const keyBuf = Buffer.from(keyBase64, \"base64\");\r\n const iv = randomBytes(12);\r\n const cipher = createCipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n const plain = Buffer.from(JSON.stringify(payload), \"utf8\");\r\n const ct = Buffer.concat([cipher.update(plain), cipher.final(), cipher.getAuthTag()]);\r\n return {\r\n _lp_enc: true,\r\n iv: iv.toString(\"base64\"),\r\n ct: ct.toString(\"base64\"),\r\n };\r\n}\r\n\r\nfunction decryptPayload(keyBase64: string, envelope: EncEnvelope): Record<string, any> {\r\n const keyBuf = Buffer.from(keyBase64, \"base64\");\r\n const iv = Buffer.from(envelope.iv, \"base64\");\r\n const ctFull = Buffer.from(envelope.ct, \"base64\");\r\n \n const authTag = ctFull.subarray(ctFull.length - 16);\r\n const ct = ctFull.subarray(0, ctFull.length - 16);\r\n const decipher = createDecipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n decipher.setAuthTag(authTag);\r\n const plain = Buffer.concat([decipher.update(ct), decipher.final()]);\r\n return JSON.parse(plain.toString(\"utf8\"));\r\n}\r\n\r\nfunction computeDiff(original: any, patched: any): any {\r\n if (original === patched) return null;\r\n\r\n if (\r\n typeof original !== \"object\" ||\r\n typeof patched !== \"object\" ||\r\n original === null ||\r\n patched === null ||\r\n Array.isArray(original) ||\r\n Array.isArray(patched)\r\n ) {\r\n if (JSON.stringify(original) !== JSON.stringify(patched)) {\r\n return { from: original, to: patched };\r\n }\r\n return null;\r\n }\r\n\r\n const changes: Record<string, any> = {};\r\n let hasChanges = false;\r\n const allKeys = new Set([...Object.keys(original), ...Object.keys(patched)]);\r\n\r\n for (const key of allKeys) {\r\n const oV = original[key];\r\n const pV = patched[key];\r\n\r\n if (!(key in original)) {\r\n changes[key] = { from: undefined, to: pV };\r\n hasChanges = true;\r\n } else if (!(key in patched)) {\r\n changes[key] = { from: oV, to: undefined };\r\n hasChanges = true;\r\n } else {\r\n const nestedDiff = computeDiff(oV, pV);\r\n if (nestedDiff) {\r\n changes[key] = nestedDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n }\r\n\r\n return hasChanges ? changes : null;\r\n}\r\n\nexport class LetsPing {\r\n private readonly apiKey: string;\r\n private readonly baseUrl: string;\r\n private readonly encryptionKey: string | null;\r\n\n constructor(apiKey?: string, options?: { baseUrl?: string; encryptionKey?: string }) {\r\n const key = apiKey || process.env.LETSPING_API_KEY;\r\n if (!key) throw new Error(\"LetsPing: API Key is required. Pass it to the constructor or set LETSPING_API_KEY env var.\");\r\n\r\n this.apiKey = key;\r\n this.baseUrl = options?.baseUrl || \"https://letsping.co/api\";\r\n this.encryptionKey = options?.encryptionKey\r\n ?? process.env.LETSPING_ENCRYPTION_KEY\r\n ?? null;\r\n }\r\n\r\n private _encrypt(payload: Record<string, any>): Record<string, any> {\r\n if (!this.encryptionKey) return payload;\r\n return encryptPayload(this.encryptionKey, payload) as any;\r\n }\r\n\r\n private _decrypt(val: any): any {\r\n if (!this.encryptionKey || !isEncEnvelope(val)) return val;\r\n try {\r\n return decryptPayload(this.encryptionKey, val);\r\n } catch {\r\n \n return val;\r\n }\r\n }\r\n\n async ask(options: RequestOptions): Promise<Decision> {\r\n if (options.schema && (options.schema as any)._def) {\r\n throw new LetsPingError(\"LetsPing Error: Raw Zod schema detected. You must convert it to JSON Schema (e.g. using 'zod-to-json-schema') before passing it to the SDK.\");\r\n }\r\n\r\n const { id } = await this.request<{ id: string }>(\"POST\", \"/ingest\", {\r\n service: options.service,\r\n action: options.action,\r\n payload: this._encrypt(options.payload),\r\n priority: options.priority || \"medium\",\r\n schema: options.schema,\r\n metadata: { role: options.role, sdk: \"node\" }\r\n });\r\n\r\n const timeout = options.timeoutMs || 24 * 60 * 60 * 1000;\r\n const start = Date.now();\r\n let delay = 1000;\r\n const maxDelay = 10000;\r\n\r\n while (Date.now() - start < timeout) {\r\n try {\r\n const check = await this.request<any>(\"GET\", `/status/${id}`);\r\n\r\n if (check.status === \"APPROVED\" || check.status === \"REJECTED\") {\r\n const decryptedPayload = this._decrypt(check.payload) ?? options.payload;\r\n const decryptedPatched = check.patched_payload ? this._decrypt(check.patched_payload) : undefined;\r\n\r\n let diff_summary;\r\n let finalStatus = check.status;\r\n if (check.status === \"APPROVED\" && decryptedPatched !== undefined) {\r\n finalStatus = \"APPROVED_WITH_MODIFICATIONS\";\r\n const diff = computeDiff(decryptedPayload, decryptedPatched);\r\n diff_summary = diff ? { changes: diff } : { changes: \"Unknown structure changes\" };\r\n }\r\n\r\n return {\r\n status: finalStatus,\r\n payload: decryptedPayload,\r\n patched_payload: decryptedPatched,\r\n diff_summary,\r\n metadata: {\r\n resolved_at: check.resolved_at,\r\n actor_id: check.actor_id,\r\n }\r\n };\r\n }\r\n } catch (e: any) {\r\n const s = e.status;\r\n if (s && s >= 400 && s < 500 && s !== 404 && s !== 429) throw e;\r\n }\r\n\r\n const jitter = Math.random() * 200;\r\n await new Promise(r => setTimeout(r, delay + jitter));\r\n delay = Math.min(delay * 1.5, maxDelay);\r\n }\r\n\r\n throw new LetsPingError(`Request ${id} timed out waiting for approval.`);\r\n }\r\n\r\n async defer(options: RequestOptions): Promise<{ id: string }> {\r\n return this.request<{ id: string }>(\"POST\", \"/ingest\", {\r\n ...options,\r\n payload: this._encrypt(options.payload),\r\n });\r\n }\r\n\r\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Authorization\": `Bearer ${this.apiKey}`,\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": `letsping-node/${SDK_VERSION}`,\r\n };\r\n\r\n try {\r\n const response = await fetch(`${this.baseUrl}${path}`, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n let message = errorText;\r\n try {\r\n const json = JSON.parse(errorText);\r\n if (json.message) message = json.message;\r\n } catch { }\r\n throw new LetsPingError(`API Error [${response.status}]: ${message}`, response.status);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n } catch (e: any) {\r\n if (e instanceof LetsPingError) throw e;\r\n throw new LetsPingError(`Network Error: ${e.message}`);\r\n }\r\n }\r\n\r\n tool(service: string, action: string, priority: Priority = \"medium\"): (context: string | Record<string, any>) => Promise<string> {\r\n return async (context: string | Record<string, any>): Promise<string> => {\r\n let payload: Record<string, any>;\r\n try {\r\n if (typeof context === \"string\") {\r\n try { payload = JSON.parse(context); }\r\n catch { payload = { raw_context: context }; }\r\n } else if (typeof context === \"object\" && context !== null) {\r\n payload = context;\r\n } else {\r\n payload = { raw_context: String(context) };\r\n }\r\n\r\n const result = await this.ask({ service, action, payload, priority });\r\n\r\n if (result.status === \"REJECTED\") {\r\n return \"STOP: Action Rejected by Human.\";\r\n }\r\n\r\n if (result.status === \"APPROVED_WITH_MODIFICATIONS\") {\r\n return JSON.stringify({\r\n status: \"APPROVED_WITH_MODIFICATIONS\",\r\n message: \"The human reviewer authorized this action but modified your original payload. Please review the diff_summary to learn from this correction.\",\r\n diff_summary: result.diff_summary,\r\n original_payload: result.payload,\r\n executed_payload: result.patched_payload\r\n });\r\n }\r\n\r\n return JSON.stringify({\r\n status: \"APPROVED\",\r\n executed_payload: result.payload\r\n });\r\n } catch (e: any) {\r\n return `ERROR: System Failure: ${e.message}`;\r\n }\r\n };\r\n }\r\n}\r\n\r\nexport { computeDiff };"],"mappings":"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","names":["exports","module"]}
1
+ {"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@letsping/sdk\",\n \"version\": \"0.1.5\",\n \"description\": \"Behavioral Firewall and Cryo-Sleep State Parking for Autonomous Agents\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup && tsc --emitDeclarationOnly --outDir dist\",\n \"dev\": \"tsup --watch\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"dependencies\": {},\n \"peerDependencies\": {\n \"@opentelemetry/api\": \"^1.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@opentelemetry/api\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.7.2\",\n \"@types/node\": \"^22.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}","import { createCipheriv, createDecipheriv, randomBytes, createHmac } from \"node:crypto\";\r\n\r\nlet SDK_VERSION = \"0.1.5\";\r\ntry {\r\n\r\n SDK_VERSION = require(\"../package.json\").version;\r\n} catch { }\r\n\r\nlet otelApi: any = null;\r\nlet otelTried = false;\r\n\r\nasync function getOtel() {\r\n if (otelTried) return otelApi;\r\n otelTried = true;\r\n try {\r\n otelApi = await import(\"@opentelemetry/api\");\r\n } catch { }\r\n return otelApi;\r\n}\r\n\r\nexport type Priority = \"low\" | \"medium\" | \"high\" | \"critical\";\r\n\r\nexport interface RequestOptions {\r\n\r\n service: string;\r\n\r\n action: string;\r\n\r\n payload: Record<string, any>;\r\n\r\n priority?: Priority;\r\n\r\n schema?: Record<string, any>;\r\n\r\n state_snapshot?: Record<string, any>;\r\n\r\n timeoutMs?: number;\r\n\r\n role?: string;\r\n}\r\n\r\nexport interface Decision {\r\n status: \"APPROVED\" | \"REJECTED\" | \"APPROVED_WITH_MODIFICATIONS\";\r\n\r\n payload: any;\r\n\r\n patched_payload?: any;\r\n\r\n diff_summary?: any;\r\n metadata?: {\r\n resolved_at: string;\r\n actor_id: string;\r\n method?: string;\r\n };\r\n}\r\n\r\nexport class LetsPingError extends Error {\r\n constructor(message: string, public status?: number) {\r\n super(message);\r\n this.name = \"LetsPingError\";\r\n }\r\n}\r\n\r\ninterface EncEnvelope {\r\n _lp_enc: true;\r\n iv: string;\r\n ct: string;\r\n}\r\n\r\nfunction isEncEnvelope(v: unknown): v is EncEnvelope {\r\n return (\r\n typeof v === \"object\" && v !== null &&\r\n (v as any)._lp_enc === true &&\r\n typeof (v as any).iv === \"string\" &&\r\n typeof (v as any).ct === \"string\"\r\n );\r\n}\r\n\r\nfunction encryptPayload(keyBase64: string, payload: Record<string, any>): EncEnvelope {\r\n const keyBuf = Buffer.from(keyBase64, \"base64\");\r\n const iv = randomBytes(12);\r\n const cipher = createCipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n const plain = Buffer.from(JSON.stringify(payload), \"utf8\");\r\n const ct = Buffer.concat([cipher.update(plain), cipher.final(), cipher.getAuthTag()]);\r\n return {\r\n _lp_enc: true,\r\n iv: iv.toString(\"base64\"),\r\n ct: ct.toString(\"base64\"),\r\n };\r\n}\r\n\r\nfunction decryptPayload(keyBase64: string, envelope: EncEnvelope): Record<string, any> {\r\n const keyBuf = Buffer.from(keyBase64, \"base64\");\r\n const iv = Buffer.from(envelope.iv, \"base64\");\r\n const ctFull = Buffer.from(envelope.ct, \"base64\");\r\n\r\n const authTag = ctFull.subarray(ctFull.length - 16);\r\n const ct = ctFull.subarray(0, ctFull.length - 16);\r\n const decipher = createDecipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n decipher.setAuthTag(authTag);\r\n const plain = Buffer.concat([decipher.update(ct), decipher.final()]);\r\n return JSON.parse(plain.toString(\"utf8\"));\r\n}\r\n\r\nfunction computeDiff(original: any, patched: any): any {\r\n if (original === patched) return null;\r\n\r\n if (\r\n typeof original !== \"object\" ||\r\n typeof patched !== \"object\" ||\r\n original === null ||\r\n patched === null ||\r\n Array.isArray(original) ||\r\n Array.isArray(patched)\r\n ) {\r\n if (JSON.stringify(original) !== JSON.stringify(patched)) {\r\n return { from: original, to: patched };\r\n }\r\n return null;\r\n }\r\n\r\n const changes: Record<string, any> = {};\r\n let hasChanges = false;\r\n const allKeys = new Set([...Object.keys(original), ...Object.keys(patched)]);\r\n\r\n for (const key of allKeys) {\r\n const oV = original[key];\r\n const pV = patched[key];\r\n\r\n if (!(key in original)) {\r\n changes[key] = { from: undefined, to: pV };\r\n hasChanges = true;\r\n } else if (!(key in patched)) {\r\n changes[key] = { from: oV, to: undefined };\r\n hasChanges = true;\r\n } else {\r\n const nestedDiff = computeDiff(oV, pV);\r\n if (nestedDiff) {\r\n changes[key] = nestedDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n }\r\n\r\n return hasChanges ? changes : null;\r\n}\r\n\r\nexport class LetsPing {\r\n private readonly apiKey: string;\r\n private readonly baseUrl: string;\r\n private readonly encryptionKey: string | null;\r\n\r\n constructor(apiKey?: string, options?: { baseUrl?: string; encryptionKey?: string }) {\r\n const key = apiKey || process.env.LETSPING_API_KEY;\r\n if (!key) throw new Error(\"LetsPing: API Key is required. Pass it to the constructor or set LETSPING_API_KEY env var.\");\r\n\r\n this.apiKey = key;\r\n this.baseUrl = options?.baseUrl || \"https://letsping.co/api\";\r\n this.encryptionKey = options?.encryptionKey\r\n ?? process.env.LETSPING_ENCRYPTION_KEY\r\n ?? null;\r\n }\r\n\r\n private _encrypt(payload: Record<string, any>): Record<string, any> {\r\n if (!this.encryptionKey) return payload;\r\n return encryptPayload(this.encryptionKey, payload) as any;\r\n }\r\n\r\n private _decrypt(val: any): any {\r\n if (!this.encryptionKey || !isEncEnvelope(val)) return val;\r\n try {\r\n return decryptPayload(this.encryptionKey, val);\r\n } catch {\r\n\r\n return val;\r\n }\r\n }\r\n\r\n private _prepareStateUpload(\r\n stateSnapshot: Record<string, any>,\r\n fallbackDek?: string\r\n ): { data: any; contentType: string } {\r\n if (this.encryptionKey) {\r\n return {\r\n data: this._encrypt(stateSnapshot),\r\n contentType: \"application/json\"\r\n };\r\n } else if (fallbackDek) {\r\n const keyBuf = Buffer.from(fallbackDek, \"base64\");\r\n const iv = randomBytes(12);\r\n const cipher = createCipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n const plain = Buffer.from(JSON.stringify(stateSnapshot), \"utf8\");\r\n const ct = Buffer.concat([cipher.update(plain), cipher.final(), cipher.getAuthTag()]);\r\n const finalPayload = Buffer.concat([iv, ct]);\r\n\r\n return {\r\n data: finalPayload,\r\n contentType: \"application/octet-stream\"\r\n };\r\n }\r\n return {\r\n data: stateSnapshot,\r\n contentType: \"application/json\"\r\n };\r\n }\r\n\r\n async ask(options: RequestOptions): Promise<Decision> {\r\n if (options.schema && (options.schema as any)._def) {\r\n throw new LetsPingError(\"LetsPing Error: Raw Zod schema detected. You must convert it to JSON Schema (e.g. using 'zod-to-json-schema') before passing it to the SDK.\");\r\n }\r\n\r\n const otel = await getOtel();\r\n let span: any = null;\r\n if (otel && otel.trace) {\r\n const tracer = otel.trace.getTracer(\"letsping-sdk\");\r\n span = tracer.startSpan(`letsping.ask`, {\r\n attributes: {\r\n \"letsping.service\": options.service,\r\n \"letsping.action\": options.action,\r\n \"letsping.priority\": options.priority || \"medium\",\r\n }\r\n });\r\n }\r\n\r\n try {\r\n const res = await this.request<{ id: string, uploadUrl?: string, dek?: string }>(\"POST\", \"/ingest\", {\r\n service: options.service,\r\n action: options.action,\r\n payload: this._encrypt(options.payload),\r\n priority: options.priority || \"medium\",\r\n schema: options.schema,\r\n metadata: { role: options.role, sdk: \"node\" }\r\n });\r\n\r\n const { id, uploadUrl, dek } = res;\r\n\r\n if (uploadUrl && options.state_snapshot) {\r\n try {\r\n const { data, contentType } = this._prepareStateUpload(options.state_snapshot, dek);\r\n const putRes = await fetch(uploadUrl, {\r\n method: \"PUT\",\r\n headers: { \"Content-Type\": contentType },\r\n body: Buffer.isBuffer(data) ? (data as any) : JSON.stringify(data)\r\n });\r\n if (!putRes.ok) {\r\n console.warn(\"LetsPing: Failed to upload state_snapshot to storage\", await putRes.text());\r\n }\r\n } catch (e: any) {\r\n console.warn(\"LetsPing: Exception uploading state_snapshot\", e.message);\r\n }\r\n }\r\n\r\n if (span) span.setAttribute(\"letsping.request_id\", id);\r\n\r\n const timeout = options.timeoutMs || 24 * 60 * 60 * 1000;\r\n const start = Date.now();\r\n let delay = 1000;\r\n const maxDelay = 10000;\r\n\r\n while (Date.now() - start < timeout) {\r\n try {\r\n const check = await this.request<any>(\"GET\", `/status/${id}`);\r\n\r\n if (check.status === \"APPROVED\" || check.status === \"REJECTED\") {\r\n const decryptedPayload = this._decrypt(check.payload) ?? options.payload;\r\n const decryptedPatched = check.patched_payload ? this._decrypt(check.patched_payload) : undefined;\r\n\r\n let diff_summary;\r\n let finalStatus = check.status;\r\n if (check.status === \"APPROVED\" && decryptedPatched !== undefined) {\r\n finalStatus = \"APPROVED_WITH_MODIFICATIONS\";\r\n const diff = computeDiff(decryptedPayload, decryptedPatched);\r\n diff_summary = diff ? { changes: diff } : { changes: \"Unknown structure changes\" };\r\n }\r\n\r\n if (span) {\r\n span.setAttribute(\"letsping.status\", finalStatus);\r\n if (check.actor_id) span.setAttribute(\"letsping.actor_id\", check.actor_id);\r\n span.end();\r\n }\r\n\r\n return {\r\n status: finalStatus,\r\n payload: decryptedPayload,\r\n patched_payload: decryptedPatched,\r\n diff_summary,\r\n metadata: {\r\n resolved_at: check.resolved_at,\r\n actor_id: check.actor_id,\r\n }\r\n };\r\n }\r\n } catch (e: any) {\r\n const s = e.status;\r\n if (s && s >= 400 && s < 500 && s !== 404 && s !== 429) throw e;\r\n }\r\n\r\n const jitter = Math.random() * 200;\r\n await new Promise(r => setTimeout(r, delay + jitter));\r\n delay = Math.min(delay * 1.5, maxDelay);\r\n }\r\n\r\n throw new LetsPingError(`Request ${id} timed out waiting for approval.`);\r\n } catch (error: any) {\r\n if (span) {\r\n span.recordException(error);\r\n span.setStatus({ code: otel.SpanStatusCode.ERROR });\r\n span.end();\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n async defer(options: RequestOptions): Promise<{ id: string }> {\r\n const otel = await getOtel();\r\n let span: any = null;\r\n if (otel && otel.trace) {\r\n const tracer = otel.trace.getTracer(\"letsping-sdk\");\r\n span = tracer.startSpan(`letsping.defer`, {\r\n attributes: {\r\n \"letsping.service\": options.service,\r\n \"letsping.action\": options.action,\r\n \"letsping.priority\": options.priority || \"medium\",\r\n }\r\n });\r\n }\r\n\r\n try {\r\n const res = await this.request<{ id: string, uploadUrl?: string, dek?: string }>(\"POST\", \"/ingest\", {\r\n ...options,\r\n payload: this._encrypt(options.payload),\r\n });\r\n if (res.uploadUrl && options.state_snapshot) {\r\n try {\r\n const { data, contentType } = this._prepareStateUpload(options.state_snapshot, res.dek);\r\n const putRes = await fetch(res.uploadUrl, {\r\n method: \"PUT\",\r\n headers: { \"Content-Type\": contentType },\r\n body: Buffer.isBuffer(data) ? (data as any) : JSON.stringify(data)\r\n });\r\n if (!putRes.ok) {\r\n console.warn(\"LetsPing: Failed to upload state_snapshot to storage\", await putRes.text());\r\n }\r\n } catch (e: any) {\r\n console.warn(\"LetsPing: Exception uploading state_snapshot\", e.message);\r\n }\r\n }\r\n\r\n if (span) {\r\n span.setAttribute(\"letsping.request_id\", res.id);\r\n span.end();\r\n }\r\n return { id: res.id };\r\n } catch (error: any) {\r\n if (span) {\r\n span.recordException(error);\r\n span.setStatus({ code: otel.SpanStatusCode.ERROR });\r\n span.end();\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Authorization\": `Bearer ${this.apiKey}`,\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": `letsping-node/${SDK_VERSION}`,\r\n };\r\n\r\n try {\r\n const response = await fetch(`${this.baseUrl}${path}`, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n let message = errorText;\r\n try {\r\n const json = JSON.parse(errorText);\r\n if (json.message) message = json.message;\r\n } catch { }\r\n throw new LetsPingError(`API Error [${response.status}]: ${message}`, response.status);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n } catch (e: any) {\r\n if (e instanceof LetsPingError) throw e;\r\n throw new LetsPingError(`Network Error: ${e.message}`);\r\n }\r\n }\r\n\r\n tool(service: string, action: string, priority: Priority = \"medium\"): (context: string | Record<string, any>) => Promise<string> {\r\n return async (context: string | Record<string, any>): Promise<string> => {\r\n let payload: Record<string, any>;\r\n try {\r\n if (typeof context === \"string\") {\r\n try { payload = JSON.parse(context); }\r\n catch { payload = { raw_context: context }; }\r\n } else if (typeof context === \"object\" && context !== null) {\r\n payload = context;\r\n } else {\r\n payload = { raw_context: String(context) };\r\n }\r\n\r\n const result = await this.ask({ service, action, payload, priority });\r\n\r\n if (result.status === \"REJECTED\") {\r\n return \"STOP: Action Rejected by Human.\";\r\n }\r\n\r\n if (result.status === \"APPROVED_WITH_MODIFICATIONS\") {\r\n return JSON.stringify({\r\n status: \"APPROVED_WITH_MODIFICATIONS\",\r\n message: \"The human reviewer authorized this action but modified your original payload. Please review the diff_summary to learn from this correction.\",\r\n diff_summary: result.diff_summary,\r\n original_payload: result.payload,\r\n executed_payload: result.patched_payload\r\n });\r\n }\r\n\r\n return JSON.stringify({\r\n status: \"APPROVED\",\r\n executed_payload: result.payload\r\n });\r\n } catch (e: any) {\r\n return `ERROR: System Failure: ${e.message}`;\r\n }\r\n };\r\n }\r\n\r\n async webhookHandler(\r\n payloadStr: string,\r\n signatureHeader: string,\r\n webhookSecret: string\r\n ): Promise<{ id: string; event: string; data: Decision; state_snapshot?: Record<string, any> }> {\r\n const hmac = createHmac(\"sha256\", webhookSecret).update(payloadStr).digest(\"hex\");\r\n const sigParts = signatureHeader.split(\",\").map(p => p.split(\"=\"));\r\n const sigMap = Object.fromEntries(sigParts);\r\n\r\n if (sigMap[\"v1\"] !== hmac) {\r\n throw new LetsPingError(\"LetsPing Error: Invalid webhook signature\", 401);\r\n }\r\n\r\n const payload = JSON.parse(payloadStr);\r\n const data = payload.data;\r\n let state_snapshot = undefined;\r\n\r\n if (data && data.state_download_url) {\r\n try {\r\n const res = await fetch(data.state_download_url);\r\n if (res.ok) {\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n if (contentType.includes(\"application/octet-stream\")) {\r\n const fallbackDek = data.dek;\r\n if (fallbackDek) {\r\n const buffer = Buffer.from(await res.arrayBuffer());\r\n const keyBuf = Buffer.from(fallbackDek, \"base64\");\r\n const iv = buffer.subarray(0, 12);\r\n const ctFull = buffer.subarray(12);\r\n\r\n const authTag = ctFull.subarray(ctFull.length - 16);\r\n const ct = ctFull.subarray(0, ctFull.length - 16);\r\n\r\n const decipher = createDecipheriv(\"aes-256-gcm\", keyBuf, iv);\r\n decipher.setAuthTag(authTag);\r\n const plain = Buffer.concat([decipher.update(ct), decipher.final()]);\r\n state_snapshot = JSON.parse(plain.toString(\"utf8\"));\r\n } else {\r\n console.warn(\"LetsPing: Missing fallback DEK to decrypt octet-stream storage file\");\r\n }\r\n } else {\r\n const encState = await res.json();\r\n state_snapshot = this._decrypt(encState);\r\n }\r\n } else {\r\n console.warn(\"LetsPing: Could not fetch state_snapshot from storage\", await res.text());\r\n }\r\n } catch (e: any) {\r\n console.warn(\"LetsPing: Exception downloading state_snapshot from webhook url\", e.message);\r\n }\r\n }\r\n\r\n return {\r\n id: payload.id,\r\n event: payload.event,\r\n data,\r\n state_snapshot\r\n };\r\n }\r\n}\r\n\r\nexport { computeDiff };"],"mappings":"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","names":["exports","module"]}