@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 +170 -12
- package/dist/index.d.ts +7 -0
- package/dist/index.js +71 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -12
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/langgraph.d.mts +20 -0
- package/dist/integrations/langgraph.d.ts +17 -0
- package/dist/integrations/langgraph.js +150 -0
- package/dist/integrations/langgraph.js.map +1 -0
- package/dist/integrations/langgraph.mjs +125 -0
- package/dist/integrations/langgraph.mjs.map +1 -0
- package/examples/langgraph-demo.ts +80 -0
- package/package.json +20 -6
- package/src/index.ts +67 -7
- package/src/integrations/langgraph.ts +163 -0
- package/tsup.config.ts +1 -1
- package/tsc_error.log +0 -213
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 (
|
|
96
|
-
|
|
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
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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.
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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"]}
|