@letsping/sdk 0.1.5 → 0.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 CHANGED
@@ -10,9 +10,9 @@ LetsPing is a behavioral firewall and Human-in-the-Loop (HITL) infrastructure la
10
10
  - **Smart-Accept Drift Adaptation:** Approval decisions mathematically alter the baseline. Old unused reasoning paths decay automatically via Exponential Moving Average (EMA).
11
11
 
12
12
  ## Requirements
13
-
14
13
  - Node.js 18+
15
14
  - TypeScript 5+ (recommended)
15
+ - (Optional) `@langchain/langgraph` and `@langchain/core` for state persistence
16
16
 
17
17
  ## Installation
18
18
 
@@ -92,21 +92,115 @@ const { id } = await lp.defer({
92
92
  console.log(`Approval request queued → ${id}`);
93
93
  ```
94
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.
95
+ ### Webhook Rehydration (Next.js Example)
96
+
97
+ When you pass `state_snapshot` to `ask` / `defer`, the SDK:
98
+
99
+ - Encrypts the snapshot with either `LETSPING_ENCRYPTION_KEY` or a one‑time DEK.
100
+ - Uploads it directly to your storage bucket using a signed URL.
101
+ - Includes a `state_download_url` (and DEK) in subsequent webhooks.
102
+
103
+ You can use the built‑in `webhookHandler` to validate and hydrate webhooks in a Next.js App Router route:
97
104
 
98
105
  ```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
106
+ // Example Next.js App Router route
107
+ import { NextRequest, NextResponse } from "next/server";
108
+ import { LetsPing } from "@letsping/sdk";
109
+
110
+ const lp = new LetsPing();
111
+ const WEBHOOK_SECRET = process.env.LETSPING_WEBHOOK_SECRET!;
112
+
113
+ export async function POST(req: NextRequest) {
114
+ const rawBody = await req.text();
115
+ const signature = req.headers.get("x-letsping-signature") || "";
116
+
117
+ try {
118
+ const { id, event, data, state_snapshot } = await lp.webhookHandler(
119
+ rawBody,
120
+ signature,
121
+ WEBHOOK_SECRET
122
+ );
123
+
124
+ // At this point:
125
+ // - `data` contains the decision payload (status, payload, patched_payload, metadata, etc.)
126
+ // - `state_snapshot` contains your decrypted agent state, if Cryo-Sleep was used.
127
+
128
+ await handleDecision({ id, event, data, state_snapshot });
129
+
130
+ return NextResponse.json({ ok: true });
131
+ } catch (err: any) {
132
+ console.error("LetsPing webhook error:", err);
133
+ return NextResponse.json({ error: "invalid webhook" }, { status: 400 });
134
+ }
107
135
  }
136
+
137
+ async function handleDecision(args: {
138
+ id: string;
139
+ event: string;
140
+ data: any;
141
+ state_snapshot?: Record<string, any>;
142
+ }) {
143
+ // Example: resume a workflow run or LangGraph thread using `state_snapshot`
144
+ }
145
+ ```
146
+
147
+ This pattern works similarly for Express/Fastify — call `lp.webhookHandler(rawBody, signature, secret)`, then resume your framework using the provided `state_snapshot`.
148
+
149
+ ### LangGraph Integration (Persisted State)
150
+
151
+ LetsPing provides a `LetsPingCheckpointer` for LangGraph JS/TS under `@letsping/sdk/integrations/langgraph`.
152
+ In v0.2 this checkpointer persists checkpoints **remotely** via the LetsPing control plane — encrypted alongside your existing Cryo‑Sleep state in Supabase Storage. Threads can survive process restarts without you wiring your own database.
153
+
154
+ ```typescript
155
+ import { StateGraph } from "@langchain/langgraph";
156
+ import { LetsPing } from "@letsping/sdk";
157
+ import { LetsPingCheckpointer } from "@letsping/sdk/integrations/langgraph";
158
+
159
+ const lp = new LetsPing(process.env.LETSPING_API_KEY!);
160
+ const checkpointer = new LetsPingCheckpointer(lp);
161
+
162
+ const builder = new StateGraph<any /* your state type */>({});
163
+ const graph = builder.compile({ checkpointer });
108
164
  ```
109
165
 
166
+ #### Auto‑resuming a thread after approval (webhook + checkpointer)
167
+
168
+ Because checkpoints are stored remotely, you can resume a LangGraph thread from any worker once a human clicks Approve. A minimal Next.js webhook + auto‑resume flow looks like:
169
+
170
+ ```ts
171
+ // Example Next.js App Router route for LangGraph auto-resume
172
+ import { NextRequest, NextResponse } from "next/server";
173
+ import { LetsPing } from "@letsping/sdk";
174
+ import { StateGraph } from "@langchain/langgraph";
175
+ import { LetsPingCheckpointer } from "@letsping/sdk/integrations/langgraph";
176
+ import { graphBuilder } from "@/lib/langgraph"; // your app's graph definition
177
+
178
+ const lp = new LetsPing(process.env.LETSPING_API_KEY!);
179
+ const checkpointer = new LetsPingCheckpointer(lp);
180
+ const graph = graphBuilder.compile({ checkpointer });
181
+
182
+ export async function POST(req: NextRequest) {
183
+ const raw = await req.text();
184
+ const sig = req.headers.get("x-letsping-signature") || "";
185
+
186
+ const event = await lp.webhookHandler(raw, sig, process.env.LETSPING_WEBHOOK_SECRET!);
187
+ const { data, state_snapshot } = event;
188
+
189
+ // You decide how to encode the thread id into your state snapshot.
190
+ const threadId = state_snapshot?.thread_id as string | undefined;
191
+ if (!threadId) return NextResponse.json({ ok: false, error: "missing_thread_id" }, { status: 400 });
192
+
193
+ // Resume the graph from the latest remote checkpoint.
194
+ await graph.invoke(state_snapshot.input, {
195
+ configurable: { thread_id: threadId },
196
+ });
197
+
198
+ return NextResponse.json({ ok: true });
199
+ }
200
+ ```
201
+
202
+ In your agent runner, you simply include `thread_id` and `state_snapshot` when you first call LetsPing from inside a LangGraph node. The checkpointer and webhook then keep the thread resumable across restarts.
203
+
110
204
  ## API Reference
111
205
 
112
206
  ### `new LetsPing(apiKey, options?)`
@@ -148,4 +242,68 @@ interface Decision {
148
242
  For full documentation, request schema examples, error codes, and dashboard integration see:
149
243
  https://letsping.co/docs#sdk
150
244
 
151
- Deploy agents with confidence.
245
+ Deploy agents with confidence.
246
+
247
+ ## 2-Minute Demo (Node/TypeScript)
248
+
249
+ You can feel the full LetsPing loop (intercept → approve → resume) in under 2 minutes.
250
+
251
+ ```ts
252
+ // demo.ts
253
+ import { LetsPing } from "@letsping/sdk";
254
+
255
+ async function main() {
256
+ const apiKey = process.env.LETSPING_API_KEY;
257
+ if (!apiKey) {
258
+ console.error("Missing LETSPING_API_KEY env var.");
259
+ process.exit(1);
260
+ }
261
+
262
+ const lp = new LetsPing(apiKey);
263
+
264
+ console.log("Sending demo approval request to LetsPing…");
265
+ const decision = await lp.ask({
266
+ service: "demo-agent",
267
+ action: "transfer_funds",
268
+ priority: "high",
269
+ payload: {
270
+ amount: 500,
271
+ currency: "USD",
272
+ recipient: "acct_demo_123",
273
+ },
274
+ });
275
+
276
+ if (decision.status === "REJECTED") {
277
+ console.log("Demo request REJECTED by human. No action taken.");
278
+ } else if (decision.status === "APPROVED_WITH_MODIFICATIONS") {
279
+ console.log("APPROVED WITH MODIFICATIONS:");
280
+ console.dir(decision.diff_summary, { depth: null });
281
+ } else {
282
+ console.log("APPROVED with original payload.");
283
+ }
284
+ }
285
+
286
+ main().catch((err) => {
287
+ console.error("Demo failed:", err);
288
+ process.exit(1);
289
+ });
290
+ ```
291
+
292
+ Run:
293
+
294
+ ```bash
295
+ export LETSPING_API_KEY="lp_live_..."
296
+ node demo.ts
297
+ ```
298
+
299
+ Then open the LetsPing dashboard for your project, approve/reject the `demo-agent / transfer_funds` request, and watch the script resume.
300
+
301
+ If you’re using the local tunnel (`npx @letsping/cli dev`), you can also point the SDK at it during local development:
302
+
303
+ ```ts
304
+ const lp = new LetsPing(process.env.LETSPING_API_KEY!, {
305
+ baseUrl: "http://localhost:<port>/api",
306
+ });
307
+ ```
308
+
309
+ All `ask` / `defer` calls made through that client will flow through your local tunnel into the LetsPing dashboard.
package/dist/index.d.ts CHANGED
@@ -8,6 +8,13 @@ export interface RequestOptions {
8
8
  state_snapshot?: Record<string, any>;
9
9
  timeoutMs?: number;
10
10
  role?: string;
11
+ /**
12
+ * Optional distributed tracing identifiers. If provided, these will be
13
+ * attached to the request envelope so downstream frameworks can stitch
14
+ * together multi-agent flows.
15
+ */
16
+ trace_id?: string;
17
+ parent_request_id?: string;
11
18
  }
12
19
  export interface Decision {
13
20
  status: "APPROVED" | "REJECTED" | "APPROVED_WITH_MODIFICATIONS";
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ var require_package = __commonJS({
35
35
  "package.json"(exports2, module2) {
36
36
  module2.exports = {
37
37
  name: "@letsping/sdk",
38
- version: "0.1.5",
38
+ version: "0.2.0",
39
39
  description: "Behavioral Firewall and Cryo-Sleep State Parking for Autonomous Agents",
40
40
  main: "./dist/index.js",
41
41
  module: "./dist/index.mjs",
@@ -45,6 +45,11 @@ var require_package = __commonJS({
45
45
  types: "./dist/index.d.ts",
46
46
  require: "./dist/index.js",
47
47
  import: "./dist/index.mjs"
48
+ },
49
+ "./integrations/langgraph": {
50
+ types: "./dist/integrations/langgraph.d.ts",
51
+ require: "./dist/integrations/langgraph.js",
52
+ import: "./dist/integrations/langgraph.mjs"
48
53
  }
49
54
  },
50
55
  scripts: {
@@ -52,20 +57,29 @@ var require_package = __commonJS({
52
57
  dev: "tsup --watch",
53
58
  clean: "rm -rf dist .turbo"
54
59
  },
55
- dependencies: {},
56
60
  peerDependencies: {
61
+ "@langchain/core": ">=0.1.52",
62
+ "@langchain/langgraph": ">=0.0.1",
57
63
  "@opentelemetry/api": "^1.0.0"
58
64
  },
59
65
  peerDependenciesMeta: {
60
66
  "@opentelemetry/api": {
61
67
  optional: true
68
+ },
69
+ "@langchain/langgraph": {
70
+ optional: true
71
+ },
72
+ "@langchain/core": {
73
+ optional: true
62
74
  }
63
75
  },
64
76
  devDependencies: {
65
- tsup: "^8.0.0",
66
- typescript: "^5.7.2",
77
+ "@langchain/core": "^1.1.28",
78
+ "@langchain/langgraph": "^1.1.5",
79
+ "@opentelemetry/api": "^1.9.0",
67
80
  "@types/node": "^22.0.0",
68
- "@opentelemetry/api": "^1.9.0"
81
+ tsup: "^8.0.0",
82
+ typescript: "^5.7.2"
69
83
  },
70
84
  publishConfig: {
71
85
  access: "public"
@@ -83,7 +97,7 @@ __export(index_exports, {
83
97
  });
84
98
  module.exports = __toCommonJS(index_exports);
85
99
  var import_node_crypto = require("crypto");
86
- var SDK_VERSION = "0.1.5";
100
+ var SDK_VERSION = "0.2.0";
87
101
  try {
88
102
  SDK_VERSION = require_package().version;
89
103
  } catch {
@@ -221,14 +235,27 @@ var LetsPing = class {
221
235
  }
222
236
  });
223
237
  }
238
+ const traceId = options.trace_id;
239
+ const parentId = options.parent_request_id;
240
+ const basePayload = options.payload || {};
241
+ const metaKey = "_lp_meta";
242
+ const existingMeta = basePayload[metaKey] || {};
243
+ const enrichedPayload = {
244
+ ...basePayload,
245
+ [metaKey]: {
246
+ ...existingMeta,
247
+ ...traceId ? { trace_id: traceId } : {},
248
+ ...parentId ? { parent_request_id: parentId } : {}
249
+ }
250
+ };
224
251
  try {
225
252
  const res = await this.request("POST", "/ingest", {
226
253
  service: options.service,
227
254
  action: options.action,
228
- payload: this._encrypt(options.payload),
255
+ payload: this._encrypt(enrichedPayload),
229
256
  priority: options.priority || "medium",
230
257
  schema: options.schema,
231
- metadata: { role: options.role, sdk: "node" }
258
+ metadata: { role: options.role, sdk: "node", trace_id: traceId, parent_request_id: parentId }
232
259
  });
233
260
  const { id, uploadUrl, dek } = res;
234
261
  if (uploadUrl && options.state_snapshot) {
@@ -311,10 +338,27 @@ var LetsPing = class {
311
338
  }
312
339
  });
313
340
  }
341
+ const traceId = options.trace_id;
342
+ const parentId = options.parent_request_id;
343
+ const basePayload = options.payload || {};
344
+ const metaKey = "_lp_meta";
345
+ const existingMeta = basePayload[metaKey] || {};
346
+ const enrichedPayload = {
347
+ ...basePayload,
348
+ [metaKey]: {
349
+ ...existingMeta,
350
+ ...traceId ? { trace_id: traceId } : {},
351
+ ...parentId ? { parent_request_id: parentId } : {}
352
+ }
353
+ };
314
354
  try {
315
355
  const res = await this.request("POST", "/ingest", {
316
- ...options,
317
- payload: this._encrypt(options.payload)
356
+ service: options.service,
357
+ action: options.action,
358
+ payload: this._encrypt(enrichedPayload),
359
+ priority: options.priority || "medium",
360
+ schema: options.schema,
361
+ metadata: { role: options.role, sdk: "node", trace_id: traceId, parent_request_id: parentId }
318
362
  });
319
363
  if (res.uploadUrl && options.state_snapshot) {
320
364
  try {
@@ -411,10 +455,25 @@ var LetsPing = class {
411
455
  };
412
456
  }
413
457
  async webhookHandler(payloadStr, signatureHeader, webhookSecret) {
414
- const hmac = (0, import_node_crypto.createHmac)("sha256", webhookSecret).update(payloadStr).digest("hex");
415
458
  const sigParts = signatureHeader.split(",").map((p) => p.split("="));
416
459
  const sigMap = Object.fromEntries(sigParts);
417
- if (sigMap["v1"] !== hmac) {
460
+ const rawTs = sigMap["t"];
461
+ const rawSig = sigMap["v1"];
462
+ if (!rawTs || !rawSig) {
463
+ throw new LetsPingError("LetsPing Error: Missing webhook signature fields", 401);
464
+ }
465
+ const ts = Number(rawTs);
466
+ if (!Number.isFinite(ts)) {
467
+ throw new LetsPingError("LetsPing Error: Invalid webhook timestamp", 401);
468
+ }
469
+ const now = Date.now();
470
+ const skewMs = Math.abs(now - ts);
471
+ const maxSkewMs = 5 * 60 * 1e3;
472
+ if (skewMs > maxSkewMs) {
473
+ throw new LetsPingError("LetsPing Error: Webhook replay window exceeded", 401);
474
+ }
475
+ const expected = (0, import_node_crypto.createHmac)("sha256", webhookSecret).update(payloadStr).digest("hex");
476
+ if (rawSig !== expected) {
418
477
  throw new LetsPingError("LetsPing Error: Invalid webhook signature", 401);
419
478
  }
420
479
  const payload = JSON.parse(payloadStr);
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.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"]}
1
+ {"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@letsping/sdk\",\n \"version\": \"0.2.0\",\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 \"./integrations/langgraph\": {\n \"types\": \"./dist/integrations/langgraph.d.ts\",\n \"require\": \"./dist/integrations/langgraph.js\",\n \"import\": \"./dist/integrations/langgraph.mjs\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup && tsc --emitDeclarationOnly --outDir dist\",\n \"dev\": \"tsup --watch\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"peerDependencies\": {\n \"@langchain/core\": \">=0.1.52\",\n \"@langchain/langgraph\": \">=0.0.1\",\n \"@opentelemetry/api\": \"^1.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@opentelemetry/api\": {\n \"optional\": true\n },\n \"@langchain/langgraph\": {\n \"optional\": true\n },\n \"@langchain/core\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@langchain/core\": \"^1.1.28\",\n \"@langchain/langgraph\": \"^1.1.5\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@types/node\": \"^22.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.7.2\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import { createCipheriv, createDecipheriv, randomBytes, createHmac } from \"node:crypto\";\r\n\r\nlet SDK_VERSION = \"0.2.0\";\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\n * Optional distributed tracing identifiers. If provided, these will be\r\n * attached to the request envelope so downstream frameworks can stitch\r\n * together multi-agent flows.\r\n */\r\n trace_id?: string;\r\n parent_request_id?: 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 const traceId = options.trace_id;\r\n const parentId = options.parent_request_id;\r\n\r\n // Do not mutate caller payload; attach tracing metadata under a reserved key.\r\n const basePayload = options.payload || {};\r\n const metaKey = \"_lp_meta\";\r\n const existingMeta = (basePayload as any)[metaKey] || {};\r\n const enrichedPayload = {\r\n ...basePayload,\r\n [metaKey]: {\r\n ...existingMeta,\r\n ...(traceId ? { trace_id: traceId } : {}),\r\n ...(parentId ? { parent_request_id: parentId } : {}),\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(enrichedPayload),\r\n priority: options.priority || \"medium\",\r\n schema: options.schema,\r\n metadata: { role: options.role, sdk: \"node\", trace_id: traceId, parent_request_id: parentId }\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 const traceId = options.trace_id;\r\n const parentId = options.parent_request_id;\r\n const basePayload = options.payload || {};\r\n const metaKey = \"_lp_meta\";\r\n const existingMeta = (basePayload as any)[metaKey] || {};\r\n const enrichedPayload = {\r\n ...basePayload,\r\n [metaKey]: {\r\n ...existingMeta,\r\n ...(traceId ? { trace_id: traceId } : {}),\r\n ...(parentId ? { parent_request_id: parentId } : {}),\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(enrichedPayload),\r\n priority: options.priority || \"medium\",\r\n schema: options.schema,\r\n metadata: { role: options.role, sdk: \"node\", trace_id: traceId, parent_request_id: parentId },\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 sigParts = signatureHeader.split(\",\").map(p => p.split(\"=\"));\r\n const sigMap = Object.fromEntries(sigParts);\r\n\r\n const rawTs = sigMap[\"t\"];\r\n const rawSig = sigMap[\"v1\"];\r\n if (!rawTs || !rawSig) {\r\n throw new LetsPingError(\"LetsPing Error: Missing webhook signature fields\", 401);\r\n }\r\n\r\n const ts = Number(rawTs);\r\n if (!Number.isFinite(ts)) {\r\n throw new LetsPingError(\"LetsPing Error: Invalid webhook timestamp\", 401);\r\n }\r\n\r\n const now = Date.now();\r\n const skewMs = Math.abs(now - ts);\r\n const maxSkewMs = 5 * 60 * 1000; // 5 minutes\r\n if (skewMs > maxSkewMs) {\r\n throw new LetsPingError(\"LetsPing Error: Webhook replay window exceeded\", 401);\r\n }\r\n\r\n const expected = createHmac(\"sha256\", webhookSecret).update(payloadStr).digest(\"hex\");\r\n if (rawSig !== expected) {\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"]}