@letsping/sdk 0.3.0 → 0.3.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@letsping/sdk\",\n \"version\": \"0.3.2\",\n \"description\": \"Agent trust layer: behavioral firewall, HITL, and Cryo-Sleep state for AI agents. Works with LangGraph, Vercel AI SDK, and custom runners.\",\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 \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup && tsc --emitDeclarationOnly --outDir dist\",\n \"dev\": \"tsup --watch\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"homepage\": \"https://letsping.co\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"letsping\",\n \"agent\",\n \"hitl\",\n \"human-in-the-loop\",\n \"behavioral-firewall\",\n \"langgraph\",\n \"vercel-ai\",\n \"cryo-sleep\",\n \"state-parking\"\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 \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CordiaLabs/LetsPing.git\",\n \"directory\": \"packages/sdk\"\n }\n}","import { createCipheriv, createDecipheriv, randomBytes, createHmac } from \"node:crypto\";\r\n\r\nlet SDK_VERSION = \"0.2.1\";\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\n/** Status of a request returned by GET /status/:id. Use with defer() + getRequestStatus() for polling without reading the raw HTTP API. */\r\nexport interface RequestStatus {\r\n id: string;\r\n status: \"PENDING\" | \"APPROVED\" | \"REJECTED\";\r\n payload?: any;\r\n patched_payload?: any;\r\n resolved_at?: string | null;\r\n actor_id?: string | null;\r\n}\r\n\r\n/** Base URL for error documentation. Errors may include a link to a specific anchor. */\r\nexport const LETSPING_DOCS_BASE = \"https://letsping.co/docs\";\r\n\r\n/** Known error codes for programmatic handling and doc links. */\r\nexport type LetsPingErrorCode =\r\n | \"LETSPING_401_AUTH\"\r\n | \"LETSPING_402_QUOTA\"\r\n | \"LETSPING_403_FORBIDDEN\"\r\n | \"LETSPING_404_NOT_FOUND\"\r\n | \"LETSPING_429_RATE_LIMIT\"\r\n | \"LETSPING_TIMEOUT\"\r\n | \"LETSPING_NETWORK\"\r\n | \"LETSPING_WEBHOOK_INVALID\"\r\n | string;\r\n\r\nexport class LetsPingError extends Error {\r\n /** HTTP status when the error came from the API (e.g. 402, 429). */\r\n public readonly status?: number;\r\n /** Stable code for handling (e.g. LETSPING_402_QUOTA). Use for branching or logging. */\r\n public readonly code?: LetsPingErrorCode;\r\n /** Link to the relevant doc section. Present when code is set. */\r\n public readonly documentationUrl?: string;\r\n\r\n constructor(\r\n message: string,\r\n status?: number,\r\n code?: LetsPingErrorCode,\r\n documentationUrl?: string\r\n ) {\r\n super(message);\r\n this.name = \"LetsPingError\";\r\n this.status = status;\r\n this.code = code ?? (status ? statusToCode(status) : undefined);\r\n this.documentationUrl = documentationUrl ?? (this.code ? codeToDocUrl(this.code) : undefined);\r\n }\r\n}\r\n\r\nfunction statusToCode(status: number): LetsPingErrorCode {\r\n switch (status) {\r\n case 401: return \"LETSPING_401_AUTH\";\r\n case 402: return \"LETSPING_402_QUOTA\";\r\n case 403: return \"LETSPING_403_FORBIDDEN\";\r\n case 404: return \"LETSPING_404_NOT_FOUND\";\r\n case 429: return \"LETSPING_429_RATE_LIMIT\";\r\n case 408: return \"LETSPING_TIMEOUT\";\r\n default: return status >= 500 ? \"LETSPING_NETWORK\" : (`LETSPING_${status}` as LetsPingErrorCode);\r\n }\r\n}\r\n\r\nfunction codeToDocUrl(code: LetsPingErrorCode): string {\r\n const anchor: Record<string, string> = {\r\n LETSPING_401_AUTH: \"#auth\",\r\n LETSPING_402_QUOTA: \"#billing\",\r\n LETSPING_403_FORBIDDEN: \"#auth\",\r\n LETSPING_404_NOT_FOUND: \"#requests\",\r\n LETSPING_429_RATE_LIMIT: \"#rate-limits\",\r\n LETSPING_TIMEOUT: \"#timeouts\",\r\n LETSPING_NETWORK: \"#errors\",\r\n LETSPING_WEBHOOK_INVALID: \"#webhooks\",\r\n };\r\n return `${LETSPING_DOCS_BASE}${anchor[code] ?? \"\"}`;\r\n}\r\n\r\nfunction parseApiError(responseStatus: number, body: { message?: string; error?: string; code?: string }): { message: string; code: LetsPingErrorCode; documentationUrl: string } {\r\n const message = body?.message ?? body?.error ?? `API Error [${responseStatus}]`;\r\n const code = (body?.code as LetsPingErrorCode) ?? statusToCode(responseStatus);\r\n return { message, code, documentationUrl: codeToDocUrl(code) };\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 interface EscrowEnvelope {\r\n id: string;\r\n event: string;\r\n data: any;\r\n escrow?: {\r\n mode: \"none\" | \"handoff\" | \"finalized\";\r\n handoff_signature: string | null;\r\n upstream_agent_id: string | null;\r\n downstream_agent_id: string | null;\r\n x402_mandate?: any;\r\n ap2_mandate?: any;\r\n };\r\n}\r\n\r\nexport function verifyEscrow(event: EscrowEnvelope, secret: string): boolean {\r\n if (!event.escrow || !event.escrow.handoff_signature) return false;\r\n const base = {\r\n id: event.id,\r\n event: event.event,\r\n data: event.data,\r\n upstream_agent_id: event.escrow.upstream_agent_id,\r\n downstream_agent_id: event.escrow.downstream_agent_id,\r\n x402_mandate: event.escrow.x402_mandate ?? null,\r\n ap2_mandate: event.escrow.ap2_mandate ?? null,\r\n };\r\n const expected = createHmac(\"sha256\", secret).update(JSON.stringify(base)).digest(\"hex\");\r\n return expected === event.escrow.handoff_signature;\r\n}\r\n\r\nexport interface AgentCallPayload {\r\n project_id: string;\r\n service: string;\r\n action: string;\r\n payload: any;\r\n}\r\n\r\nexport function signAgentCall(agentId: string, secret: string, call: AgentCallPayload): {\r\n agent_id: string;\r\n agent_signature: string;\r\n} {\r\n const canonical = JSON.stringify({\r\n project_id: call.project_id,\r\n service: call.service,\r\n action: call.action,\r\n payload: call.payload,\r\n });\r\n const signature = createHmac(\"sha256\", secret).update(canonical).digest(\"hex\");\r\n return {\r\n agent_id: agentId,\r\n agent_signature: signature,\r\n };\r\n}\r\n\r\nexport function signIngestBody(\r\n agentId: string,\r\n secret: string,\r\n body: {\r\n project_id: string;\r\n service: string;\r\n action: string;\r\n payload: any;\r\n }\r\n): {\r\n project_id: string;\r\n service: string;\r\n action: string;\r\n payload: any;\r\n agent_id: string;\r\n agent_signature: string;\r\n} {\r\n const { agent_id, agent_signature } = signAgentCall(agentId, secret, {\r\n project_id: body.project_id,\r\n service: body.service,\r\n action: body.action,\r\n payload: body.payload,\r\n });\r\n return {\r\n ...body,\r\n agent_id,\r\n agent_signature,\r\n };\r\n}\r\n\r\n/** Credentials returned by createAgentWorkspace. Use api_key for Bearer auth and ingestWithAgentSignature for signed ingest. */\r\nexport interface AgentWorkspaceCredentials {\r\n project_id: string;\r\n api_key: string;\r\n ingest_url: string;\r\n agents_register_url: string;\r\n agent_id: string;\r\n agent_secret: string;\r\n org_id?: string;\r\n docs_url?: string;\r\n}\r\n\r\n/**\r\n * Request a signup token, redeem it to create a workspace, and register one agent. Returns credentials so the agent can call ingestWithAgentSignature.\r\n * Rate limits apply (see letsping.co/docs). Throws on 4xx/5xx or if self-serve signup is disabled.\r\n * @param options.baseUrl - App root URL (e.g. https://letsping.co). Defaults to LETSPING_BASE_URL or https://letsping.co.\r\n */\r\nexport async function createAgentWorkspace(options?: { baseUrl?: string }): Promise<AgentWorkspaceCredentials> {\r\n const baseUrl = (options?.baseUrl ?? process.env.LETSPING_BASE_URL ?? \"https://letsping.co\").replace(/\\/+$/, \"\");\r\n\r\n const tokenRes = await fetch(`${baseUrl}/api/agent-signup/request-token`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: \"{}\",\r\n });\r\n if (!tokenRes.ok) {\r\n const err = await tokenRes.json().catch(() => ({})) as { error?: string; code?: string };\r\n const { message, code, documentationUrl } = parseApiError(tokenRes.status, err);\r\n throw new LetsPingError(message, tokenRes.status, code, documentationUrl);\r\n }\r\n const { token } = (await tokenRes.json()) as { token: string };\r\n if (!token) {\r\n throw new LetsPingError(\"LetsPing Error: No token in request-token response\");\r\n }\r\n\r\n const redeemRes = await fetch(`${baseUrl}/api/agent-signup`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ token }),\r\n });\r\n if (!redeemRes.ok) {\r\n const err = await redeemRes.json().catch(() => ({})) as { error?: string; message?: string };\r\n const { message, code, documentationUrl } = parseApiError(redeemRes.status, err);\r\n throw new LetsPingError(message, redeemRes.status, code, documentationUrl);\r\n }\r\n const redeem = (await redeemRes.json()) as {\r\n project_id: string;\r\n api_key: string;\r\n ingest_url: string;\r\n agents_register_url: string;\r\n org_id?: string;\r\n docs_url?: string;\r\n };\r\n if (!redeem.api_key || !redeem.agents_register_url) {\r\n throw new LetsPingError(\"LetsPing Error: Invalid redeem response (missing api_key or agents_register_url)\");\r\n }\r\n\r\n const registerRes = await fetch(redeem.agents_register_url, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${redeem.api_key}`,\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: \"{}\",\r\n });\r\n if (!registerRes.ok) {\r\n const err = await registerRes.json().catch(() => ({})) as { error?: string };\r\n const { message, code, documentationUrl } = parseApiError(registerRes.status, err);\r\n throw new LetsPingError(message, registerRes.status, code, documentationUrl);\r\n }\r\n const reg = (await registerRes.json()) as { agent_id: string; agent_secret: string };\r\n if (!reg.agent_id || !reg.agent_secret) {\r\n throw new LetsPingError(\"LetsPing Error: Invalid register response (missing agent_id or agent_secret)\");\r\n }\r\n\r\n return {\r\n project_id: redeem.project_id,\r\n api_key: redeem.api_key,\r\n ingest_url: redeem.ingest_url,\r\n agents_register_url: redeem.agents_register_url,\r\n agent_id: reg.agent_id,\r\n agent_secret: reg.agent_secret,\r\n org_id: redeem.org_id,\r\n docs_url: redeem.docs_url,\r\n };\r\n}\r\n\r\n/** Options for ingestWithAgentSignature. */\r\nexport interface IngestWithAgentSignatureOptions {\r\n projectId: string;\r\n ingestUrl: string;\r\n apiKey: string;\r\n}\r\n\r\n/** Ingest payload: service, action, and payload. */\r\nexport interface IngestPayload {\r\n service: string;\r\n action: string;\r\n payload: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Build a signed ingest body and POST it to the ingest URL with Bearer apiKey. Returns the JSON response; throws on non-2xx.\r\n * Use this so the agent quickstart does not require hand-rolled HMAC or curl. See also: signIngestBody.\r\n */\r\nexport async function ingestWithAgentSignature(\r\n agentId: string,\r\n agentSecret: string,\r\n payload: IngestPayload,\r\n options: IngestWithAgentSignatureOptions\r\n): Promise<Record<string, any>> {\r\n const body = signIngestBody(agentId, agentSecret, {\r\n project_id: options.projectId,\r\n service: payload.service,\r\n action: payload.action,\r\n payload: payload.payload ?? {},\r\n });\r\n const res = await fetch(options.ingestUrl, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${options.apiKey}`,\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n const data = (await res.json().catch(() => ({}))) as Record<string, any>;\r\n if (!res.ok) {\r\n const { message, code, documentationUrl } = parseApiError(res.status, data as { error?: string });\r\n throw new LetsPingError(message, res.status, code, documentationUrl);\r\n }\r\n return data;\r\n}\r\n\r\nexport function verifyAgentSignature(\r\n agentId: string,\r\n secret: string,\r\n call: AgentCallPayload,\r\n signature: string\r\n): boolean {\r\n const { agent_signature } = signAgentCall(agentId, secret, call);\r\n return agent_signature === signature;\r\n}\r\n\r\nexport function chainHandoff(previous: EscrowEnvelope, nextData: {\r\n service: string;\r\n action: string;\r\n payload: any;\r\n upstream_agent_id: string;\r\n downstream_agent_id: string;\r\n}, secret: string): {\r\n payload: any;\r\n escrow: {\r\n mode: \"handoff\";\r\n upstream_agent_id: string;\r\n downstream_agent_id: string;\r\n handoff_signature: string;\r\n };\r\n} {\r\n const base = {\r\n id: previous.id,\r\n event: previous.event,\r\n data: nextData.payload,\r\n upstream_agent_id: nextData.upstream_agent_id,\r\n downstream_agent_id: nextData.downstream_agent_id,\r\n };\r\n const handoff_signature = createHmac(\"sha256\", secret).update(JSON.stringify(base)).digest(\"hex\");\r\n return {\r\n payload: nextData.payload,\r\n escrow: {\r\n mode: \"handoff\",\r\n upstream_agent_id: nextData.upstream_agent_id,\r\n downstream_agent_id: nextData.downstream_agent_id,\r\n handoff_signature,\r\n },\r\n };\r\n}\r\n\r\n/** Optional retry config for ingest and status calls. Disabled when maxAttempts is 1 or omitted. */\r\nexport interface RetryOptions {\r\n /** Max attempts per request (default 1 = no retry). Try 3 for transient resilience. */\r\n maxAttempts?: number;\r\n /** Initial delay in ms before first retry (default 1000). */\r\n initialDelayMs?: number;\r\n /** Cap on delay between retries in ms (default 10000). */\r\n maxDelayMs?: number;\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 private readonly retry: Required<RetryOptions>;\r\n\r\n constructor(apiKey?: string, options?: { baseUrl?: string; encryptionKey?: string; retry?: RetryOptions }) {\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 const r = options?.retry ?? {};\r\n this.retry = {\r\n maxAttempts: r.maxAttempts ?? 1,\r\n initialDelayMs: r.initialDelayMs ?? 1000,\r\n maxDelayMs: r.maxDelayMs ?? 10000,\r\n };\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 /**\r\n * Send a request and block until a human approves or rejects it (or timeout). Use for HITL steps in your agent.\r\n * @param options - service, action, payload; optional priority, schema, state_snapshot, timeoutMs, role\r\n * @returns Decision with status APPROVED | REJECTED | APPROVED_WITH_MODIFICATIONS and payload (or patched_payload)\r\n * @throws LetsPingError with code/documentationUrl on API or network errors, or LETSPING_TIMEOUT if no decision in time\r\n * @see https://letsping.co/docs#ask\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(\r\n `Request ${id} timed out waiting for approval.`,\r\n undefined,\r\n \"LETSPING_TIMEOUT\",\r\n `${LETSPING_DOCS_BASE}#timeouts`\r\n );\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 /**\r\n * Fetch the current status of a request by id. Use after defer() to poll until status is APPROVED or REJECTED without calling the raw HTTP API.\r\n * @param id - Request id returned from defer()\r\n * @returns RequestStatus with status PENDING | APPROVED | REJECTED, payload, resolved_at, actor_id\r\n * @see https://letsping.co/docs#requests\r\n */\r\n async getRequestStatus(id: string): Promise<RequestStatus> {\r\n const raw = await this.request<RequestStatus>(\"GET\", `/status/${id}`);\r\n return raw;\r\n }\r\n\r\n /**\r\n * Send a request and return immediately with the request id. Poll with getRequestStatus(id) or waitForDecision(id) until resolved.\r\n * Use for async flows (e.g. webhook rehydration) where you do not want to block in-process.\r\n * @param options - service, action, payload; optional priority, schema, state_snapshot, role\r\n * @returns { id } - use id with getRequestStatus(id) or waitForDecision(id)\r\n * @see https://letsping.co/docs#defer\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 const maxAttempts = Math.max(1, this.retry.maxAttempts);\r\n let lastError: LetsPingError | null = null;\r\n\r\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\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 errorBody: { message?: string; error?: string; code?: string } = {};\r\n try {\r\n errorBody = JSON.parse(errorText);\r\n } catch { }\r\n const { message, code, documentationUrl } = parseApiError(response.status, errorBody);\r\n lastError = new LetsPingError(message, response.status, code, documentationUrl);\r\n const retryable = response.status === 429 || response.status >= 500;\r\n if (retryable && attempt < maxAttempts) {\r\n await this._delay(attempt);\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n return await response.json() as T;\r\n } catch (e: any) {\r\n if (e instanceof LetsPingError) {\r\n lastError = e;\r\n const retryable = e.status === 429 || (e.status != null && e.status >= 500);\r\n if (retryable && attempt < maxAttempts) {\r\n await this._delay(attempt);\r\n continue;\r\n }\r\n throw e;\r\n }\r\n lastError = new LetsPingError(\r\n `Network Error: ${e?.message ?? \"Unknown\"}`,\r\n undefined,\r\n \"LETSPING_NETWORK\",\r\n `${LETSPING_DOCS_BASE}#errors`\r\n );\r\n if (attempt < maxAttempts) {\r\n await this._delay(attempt);\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n }\r\n\r\n throw lastError ?? new LetsPingError(\"Request failed\", undefined, \"LETSPING_NETWORK\", `${LETSPING_DOCS_BASE}#errors`);\r\n }\r\n\r\n private _delay(attempt: number): Promise<void> {\r\n const delay = Math.min(\r\n this.retry.initialDelayMs * Math.pow(1.5, attempt - 1) + Math.random() * 200,\r\n this.retry.maxDelayMs\r\n );\r\n return new Promise(r => setTimeout(r, delay));\r\n }\r\n\r\n /**\r\n * Poll for a decision on a request created with defer(). Blocks until status is APPROVED/REJECTED or timeout.\r\n * @param id - request id from defer()\r\n * @param options - originalPayload (fallback if payload not in response), timeoutMs (default 24h)\r\n * @returns Decision same shape as ask()\r\n * @see https://letsping.co/docs#requests\r\n */\r\n async waitForDecision(\r\n id: string,\r\n options?: { originalPayload?: Record<string, any>; timeoutMs?: number }\r\n ): Promise<Decision> {\r\n const basePayload = options?.originalPayload || {};\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) ?? basePayload;\r\n const decryptedPatched = check.patched_payload ? this._decrypt(check.patched_payload) : undefined;\r\n\r\n let diff_summary;\r\n let finalStatus: Decision[\"status\"] = check.status;\r\n if (check.status === \"APPROVED\" && decryptedPatched !== undefined) {\r\n finalStatus = \"APPROVED_WITH_MODIFICATIONS\";\r\n const diff = computeDiff(decryptedPayload, decryptedPatched);\r\n diff_summary = diff ? { changes: diff } : { changes: \"Unknown structure changes\" };\r\n }\r\n\r\n return {\r\n status: finalStatus,\r\n payload: decryptedPayload,\r\n patched_payload: decryptedPatched,\r\n diff_summary,\r\n metadata: {\r\n resolved_at: check.resolved_at,\r\n actor_id: check.actor_id,\r\n }\r\n };\r\n }\r\n } catch (e: any) {\r\n const s = e.status;\r\n if (s && s >= 400 && s < 500 && s !== 404 && s !== 429) throw e;\r\n }\r\n\r\n const jitter = Math.random() * 200;\r\n await new Promise(r => setTimeout(r, delay + jitter));\r\n delay = Math.min(delay * 1.5, maxDelay);\r\n }\r\n\r\n throw new LetsPingError(\r\n `Request ${id} timed out waiting for approval.`,\r\n undefined,\r\n \"LETSPING_TIMEOUT\",\r\n `${LETSPING_DOCS_BASE}#timeouts`\r\n );\r\n }\r\n\r\n /**\r\n * Build a callable tool (e.g. for LangChain) that runs ask(service, action, payload) and returns a result string.\r\n * @param service - LetsPing service name\r\n * @param action - action name\r\n * @param priority - optional priority (default medium)\r\n * @returns Async function(context) => string; context can be JSON string or object\r\n * @see https://letsping.co/docs#tool\r\n */\r\n tool(service: string, action: string, priority: Priority = \"medium\"): (context: string | Record<string, any>) => Promise<string> {\r\n return async (context: string | Record<string, any>): Promise<string> => {\r\n let payload: Record<string, any>;\r\n try {\r\n if (typeof context === \"string\") {\r\n try { payload = JSON.parse(context); }\r\n catch { payload = { raw_context: context }; }\r\n } else if (typeof context === \"object\" && context !== null) {\r\n payload = context;\r\n } else {\r\n payload = { raw_context: String(context) };\r\n }\r\n\r\n const result = await this.ask({ service, action, payload, priority });\r\n\r\n if (result.status === \"REJECTED\") {\r\n return \"STOP: Action Rejected by Human.\";\r\n }\r\n\r\n if (result.status === \"APPROVED_WITH_MODIFICATIONS\") {\r\n return JSON.stringify({\r\n status: \"APPROVED_WITH_MODIFICATIONS\",\r\n message: \"The human reviewer authorized this action but modified your original payload. Please review the diff_summary to learn from this correction.\",\r\n diff_summary: result.diff_summary,\r\n original_payload: result.payload,\r\n executed_payload: result.patched_payload\r\n });\r\n }\r\n\r\n return JSON.stringify({\r\n status: \"APPROVED\",\r\n executed_payload: result.payload\r\n });\r\n } catch (e: any) {\r\n return `ERROR: System Failure: ${e.message}`;\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Validate and parse an incoming LetsPing webhook body. Verifies signature and optionally fetches/decrypts state_snapshot.\r\n * @param payloadStr - raw request body (e.g. await req.text())\r\n * @param signatureHeader - x-letsping-signature header\r\n * @param webhookSecret - secret from dashboard → Settings → Webhooks\r\n * @returns { id, event, data, state_snapshot } for resuming your workflow\r\n * @throws LetsPingError with code LETSPING_WEBHOOK_INVALID and documentationUrl on invalid signature or replay\r\n * @see https://letsping.co/docs#webhooks\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 const docUrl = `${LETSPING_DOCS_BASE}#webhooks`;\r\n if (!rawTs || !rawSig) {\r\n throw new LetsPingError(\"LetsPing Error: Missing webhook signature fields\", 401, \"LETSPING_WEBHOOK_INVALID\", docUrl);\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, \"LETSPING_WEBHOOK_INVALID\", docUrl);\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, \"LETSPING_WEBHOOK_INVALID\", docUrl);\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, \"LETSPING_WEBHOOK_INVALID\", docUrl);\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":[]}
@@ -0,0 +1,20 @@
1
+ import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata, CheckpointTuple } from '@langchain/langgraph';
2
+ import { RunnableConfig } from '@langchain/core/runnables';
3
+ import { LetsPing } from '../index.mjs';
4
+
5
+ declare class LetsPingCheckpointer extends BaseCheckpointSaver {
6
+ client: LetsPing;
7
+ private checkpoints;
8
+ constructor(client: LetsPing);
9
+ private getTransport;
10
+ private saveRemote;
11
+ private loadRemote;
12
+ private deleteRemote;
13
+ put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, newVersions?: Record<string, string | number>): Promise<RunnableConfig>;
14
+ putWrites(config: RunnableConfig, writes: any, taskId: string): Promise<void>;
15
+ deleteThread(threadId: string): Promise<void>;
16
+ getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
17
+ list(config: RunnableConfig, options?: any): AsyncGenerator<CheckpointTuple>;
18
+ }
19
+
20
+ export { LetsPingCheckpointer };
@@ -0,0 +1,17 @@
1
+ import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata, CheckpointTuple } from "@langchain/langgraph";
2
+ import { RunnableConfig } from "@langchain/core/runnables";
3
+ import { LetsPing } from "../index";
4
+ export declare class LetsPingCheckpointer extends BaseCheckpointSaver {
5
+ client: LetsPing;
6
+ private checkpoints;
7
+ constructor(client: LetsPing);
8
+ private getTransport;
9
+ private saveRemote;
10
+ private loadRemote;
11
+ private deleteRemote;
12
+ put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, newVersions?: Record<string, string | number>): Promise<RunnableConfig>;
13
+ putWrites(config: RunnableConfig, writes: any, taskId: string): Promise<void>;
14
+ deleteThread(threadId: string): Promise<void>;
15
+ getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
16
+ list(config: RunnableConfig, options?: any): AsyncGenerator<CheckpointTuple>;
17
+ }
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/integrations/langgraph.ts
21
+ var langgraph_exports = {};
22
+ __export(langgraph_exports, {
23
+ LetsPingCheckpointer: () => LetsPingCheckpointer
24
+ });
25
+ module.exports = __toCommonJS(langgraph_exports);
26
+ var import_langgraph = require("@langchain/langgraph");
27
+ var LetsPingCheckpointer = class extends import_langgraph.BaseCheckpointSaver {
28
+ constructor(client) {
29
+ super();
30
+ this.client = client;
31
+ this.checkpoints = {};
32
+ }
33
+ getTransport() {
34
+ const clientAny = this.client;
35
+ if (typeof clientAny.request === "function") {
36
+ return clientAny.request.bind(this.client);
37
+ }
38
+ return null;
39
+ }
40
+ async saveRemote(threadId, checkpointId, checkpoint, metadata) {
41
+ const transport = this.getTransport();
42
+ if (!transport) {
43
+ console.warn("[LetsPingCheckpointer] Missing underlying transport; falling back to in-memory only.");
44
+ return;
45
+ }
46
+ try {
47
+ await transport("POST", "/langgraph/checkpoints", {
48
+ thread_id: threadId,
49
+ checkpoint_id: checkpointId,
50
+ checkpoint,
51
+ metadata
52
+ });
53
+ } catch (e) {
54
+ console.warn("[LetsPingCheckpointer] Failed to persist checkpoint remotely; falling back to in-memory only.", e);
55
+ }
56
+ }
57
+ async loadRemote(threadId, checkpointId) {
58
+ const transport = this.getTransport();
59
+ if (!transport) {
60
+ console.warn("[LetsPingCheckpointer] Missing underlying transport; using in-memory checkpoints only.");
61
+ return null;
62
+ }
63
+ const search = checkpointId ? `?thread_id=${encodeURIComponent(threadId)}&checkpoint_id=${encodeURIComponent(checkpointId)}` : `?thread_id=${encodeURIComponent(threadId)}&latest=1`;
64
+ try {
65
+ const res = await transport("GET", `/langgraph/checkpoints${search}`);
66
+ if (res && res.checkpoint && res.metadata) {
67
+ return { checkpoint: res.checkpoint, metadata: res.metadata };
68
+ }
69
+ } catch (e) {
70
+ console.warn("[LetsPingCheckpointer] Failed to load remote checkpoint", e);
71
+ }
72
+ return null;
73
+ }
74
+ async deleteRemote(threadId) {
75
+ const transport = this.getTransport();
76
+ if (!transport) return;
77
+ const search = `?thread_id=${encodeURIComponent(threadId)}`;
78
+ try {
79
+ await transport("DELETE", `/langgraph/checkpoints${search}`);
80
+ } catch (e) {
81
+ console.warn("[LetsPingCheckpointer] Failed to delete remote checkpoints", e);
82
+ }
83
+ }
84
+ async put(config, checkpoint, metadata, newVersions) {
85
+ const threadId = config.configurable?.thread_id;
86
+ const checkpointId = checkpoint.id;
87
+ if (!threadId || !checkpointId) {
88
+ return config;
89
+ }
90
+ this.checkpoints[`${threadId}:${checkpointId}`] = { checkpoint, metadata };
91
+ await this.saveRemote(threadId, checkpointId, checkpoint, metadata);
92
+ return {
93
+ configurable: {
94
+ thread_id: threadId,
95
+ checkpoint_id: checkpointId
96
+ }
97
+ };
98
+ }
99
+ // METHODS REQUIRED BY LANGGRAPH V0.1+
100
+ async putWrites(config, writes, taskId) {
101
+ }
102
+ async deleteThread(threadId) {
103
+ for (const key of Object.keys(this.checkpoints)) {
104
+ if (key.startsWith(`${threadId}:`)) {
105
+ delete this.checkpoints[key];
106
+ }
107
+ }
108
+ await this.deleteRemote(threadId);
109
+ }
110
+ async getTuple(config) {
111
+ const threadId = config.configurable?.thread_id;
112
+ const checkpointId = config.configurable?.checkpoint_id;
113
+ if (!threadId) return void 0;
114
+ const remote = await this.loadRemote(threadId, checkpointId);
115
+ if (remote) {
116
+ return { config, checkpoint: remote.checkpoint, metadata: remote.metadata };
117
+ }
118
+ if (checkpointId) {
119
+ const match = this.checkpoints[`${threadId}:${checkpointId}`];
120
+ if (match) {
121
+ return { config, checkpoint: match.checkpoint, metadata: match.metadata };
122
+ }
123
+ }
124
+ let latest;
125
+ for (const [key, val] of Object.entries(this.checkpoints)) {
126
+ if (key.startsWith(`${threadId}:`)) {
127
+ latest = { config, checkpoint: val.checkpoint, metadata: val.metadata };
128
+ }
129
+ }
130
+ return latest;
131
+ }
132
+ async *list(config, options) {
133
+ const threadId = config.configurable?.thread_id;
134
+ if (!threadId) return;
135
+ const remoteLatest = await this.loadRemote(threadId);
136
+ if (remoteLatest) {
137
+ yield { config, checkpoint: remoteLatest.checkpoint, metadata: remoteLatest.metadata };
138
+ }
139
+ for (const [key, val] of Object.entries(this.checkpoints)) {
140
+ if (key.startsWith(`${threadId}:`)) {
141
+ yield { config, checkpoint: val.checkpoint, metadata: val.metadata };
142
+ }
143
+ }
144
+ }
145
+ };
146
+ // Annotate the CommonJS export names for ESM import in node:
147
+ 0 && (module.exports = {
148
+ LetsPingCheckpointer
149
+ });
150
+ //# sourceMappingURL=langgraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/langgraph.ts"],"sourcesContent":["import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata, CheckpointTuple } from \"@langchain/langgraph\";\r\nimport { RunnableConfig } from \"@langchain/core/runnables\";\r\nimport { LetsPing } from \"../index\";\r\n\r\ntype StoredCheckpoint = {\r\n checkpoint: Checkpoint;\r\n metadata: CheckpointMetadata;\r\n};\r\n\r\nexport class LetsPingCheckpointer extends BaseCheckpointSaver {\r\n private checkpoints: Record<string, StoredCheckpoint> = {};\r\n\r\n constructor(public client: LetsPing) {\r\n super();\r\n }\r\n\r\n private getTransport(): (<T = any>(method: string, path: string, body?: any) => Promise<T>) | null {\r\n const clientAny = this.client as any;\r\n if (typeof clientAny.request === \"function\") {\r\n return clientAny.request.bind(this.client);\r\n }\r\n return null;\r\n }\r\n\r\n private async saveRemote(\r\n threadId: string,\r\n checkpointId: string,\r\n checkpoint: Checkpoint,\r\n metadata: CheckpointMetadata\r\n ): Promise<void> {\r\n const transport = this.getTransport();\r\n if (!transport) {\r\n console.warn(\"[LetsPingCheckpointer] Missing underlying transport; falling back to in-memory only.\");\r\n return;\r\n }\r\n try {\r\n await transport(\"POST\", \"/langgraph/checkpoints\", {\r\n thread_id: threadId,\r\n checkpoint_id: checkpointId,\r\n checkpoint,\r\n metadata,\r\n });\r\n } catch (e) {\r\n console.warn(\"[LetsPingCheckpointer] Failed to persist checkpoint remotely; falling back to in-memory only.\", e);\r\n }\r\n }\r\n\r\n private async loadRemote(\r\n threadId: string,\r\n checkpointId?: string\r\n ): Promise<StoredCheckpoint | null> {\r\n const transport = this.getTransport();\r\n if (!transport) {\r\n console.warn(\"[LetsPingCheckpointer] Missing underlying transport; using in-memory checkpoints only.\");\r\n return null;\r\n }\r\n const search = checkpointId\r\n ? `?thread_id=${encodeURIComponent(threadId)}&checkpoint_id=${encodeURIComponent(checkpointId)}`\r\n : `?thread_id=${encodeURIComponent(threadId)}&latest=1`;\r\n try {\r\n const res = await transport<any>(\"GET\", `/langgraph/checkpoints${search}`);\r\n if (res && res.checkpoint && res.metadata) {\r\n return { checkpoint: res.checkpoint as Checkpoint, metadata: res.metadata as CheckpointMetadata };\r\n }\r\n } catch (e) {\r\n // If not found or backend unavailable, fall back to local cache only.\r\n console.warn(\"[LetsPingCheckpointer] Failed to load remote checkpoint\", e);\r\n }\r\n return null;\r\n }\r\n\r\n private async deleteRemote(threadId: string): Promise<void> {\r\n const transport = this.getTransport();\r\n if (!transport) return;\r\n const search = `?thread_id=${encodeURIComponent(threadId)}`;\r\n try {\r\n await transport(\"DELETE\", `/langgraph/checkpoints${search}`);\r\n } catch (e) {\r\n console.warn(\"[LetsPingCheckpointer] Failed to delete remote checkpoints\", e);\r\n }\r\n }\r\n\r\n async put(\r\n config: RunnableConfig,\r\n checkpoint: Checkpoint,\r\n metadata: CheckpointMetadata,\r\n newVersions?: Record<string, string | number>\r\n ): Promise<RunnableConfig> {\r\n const threadId = config.configurable?.thread_id;\r\n const checkpointId = checkpoint.id;\r\n\r\n if (!threadId || !checkpointId) {\r\n return config;\r\n }\r\n\r\n this.checkpoints[`${threadId}:${checkpointId}`] = { checkpoint, metadata };\r\n await this.saveRemote(threadId, checkpointId, checkpoint, metadata);\r\n\r\n return {\r\n configurable: {\r\n thread_id: threadId,\r\n checkpoint_id: checkpointId,\r\n },\r\n };\r\n }\r\n\r\n // METHODS REQUIRED BY LANGGRAPH V0.1+\r\n async putWrites(config: RunnableConfig, writes: any, taskId: string): Promise<void> {\r\n // No-op for V1: LetsPing focuses on primary state parking, not granular sub-task writes.\r\n }\r\n\r\n async deleteThread(threadId: string): Promise<void> {\r\n for (const key of Object.keys(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n delete this.checkpoints[key];\r\n }\r\n }\r\n await this.deleteRemote(threadId);\r\n }\r\n\r\n async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {\r\n const threadId = config.configurable?.thread_id;\r\n const checkpointId = config.configurable?.checkpoint_id;\r\n if (!threadId) return undefined;\r\n\r\n // Prefer remote truth, fall back to local cache.\r\n const remote = await this.loadRemote(threadId, checkpointId);\r\n if (remote) {\r\n return { config, checkpoint: remote.checkpoint, metadata: remote.metadata };\r\n }\r\n\r\n if (checkpointId) {\r\n const match = this.checkpoints[`${threadId}:${checkpointId}`];\r\n if (match) {\r\n return { config, checkpoint: match.checkpoint, metadata: match.metadata };\r\n }\r\n }\r\n\r\n let latest: CheckpointTuple | undefined;\r\n for (const [key, val] of Object.entries(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n latest = { config, checkpoint: val.checkpoint, metadata: val.metadata };\r\n }\r\n }\r\n return latest;\r\n }\r\n\r\n async *list(config: RunnableConfig, options?: any): AsyncGenerator<CheckpointTuple> {\r\n const threadId = config.configurable?.thread_id;\r\n if (!threadId) return;\r\n\r\n const remoteLatest = await this.loadRemote(threadId);\r\n if (remoteLatest) {\r\n yield { config, checkpoint: remoteLatest.checkpoint, metadata: remoteLatest.metadata };\r\n }\r\n\r\n for (const [key, val] of Object.entries(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n yield { config, checkpoint: val.checkpoint, metadata: val.metadata };\r\n }\r\n }\r\n }\r\n}"],"mappings":"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","names":[]}
@@ -0,0 +1,125 @@
1
+ // src/integrations/langgraph.ts
2
+ import { BaseCheckpointSaver } from "@langchain/langgraph";
3
+ var LetsPingCheckpointer = class extends BaseCheckpointSaver {
4
+ constructor(client) {
5
+ super();
6
+ this.client = client;
7
+ this.checkpoints = {};
8
+ }
9
+ getTransport() {
10
+ const clientAny = this.client;
11
+ if (typeof clientAny.request === "function") {
12
+ return clientAny.request.bind(this.client);
13
+ }
14
+ return null;
15
+ }
16
+ async saveRemote(threadId, checkpointId, checkpoint, metadata) {
17
+ const transport = this.getTransport();
18
+ if (!transport) {
19
+ console.warn("[LetsPingCheckpointer] Missing underlying transport; falling back to in-memory only.");
20
+ return;
21
+ }
22
+ try {
23
+ await transport("POST", "/langgraph/checkpoints", {
24
+ thread_id: threadId,
25
+ checkpoint_id: checkpointId,
26
+ checkpoint,
27
+ metadata
28
+ });
29
+ } catch (e) {
30
+ console.warn("[LetsPingCheckpointer] Failed to persist checkpoint remotely; falling back to in-memory only.", e);
31
+ }
32
+ }
33
+ async loadRemote(threadId, checkpointId) {
34
+ const transport = this.getTransport();
35
+ if (!transport) {
36
+ console.warn("[LetsPingCheckpointer] Missing underlying transport; using in-memory checkpoints only.");
37
+ return null;
38
+ }
39
+ const search = checkpointId ? `?thread_id=${encodeURIComponent(threadId)}&checkpoint_id=${encodeURIComponent(checkpointId)}` : `?thread_id=${encodeURIComponent(threadId)}&latest=1`;
40
+ try {
41
+ const res = await transport("GET", `/langgraph/checkpoints${search}`);
42
+ if (res && res.checkpoint && res.metadata) {
43
+ return { checkpoint: res.checkpoint, metadata: res.metadata };
44
+ }
45
+ } catch (e) {
46
+ console.warn("[LetsPingCheckpointer] Failed to load remote checkpoint", e);
47
+ }
48
+ return null;
49
+ }
50
+ async deleteRemote(threadId) {
51
+ const transport = this.getTransport();
52
+ if (!transport) return;
53
+ const search = `?thread_id=${encodeURIComponent(threadId)}`;
54
+ try {
55
+ await transport("DELETE", `/langgraph/checkpoints${search}`);
56
+ } catch (e) {
57
+ console.warn("[LetsPingCheckpointer] Failed to delete remote checkpoints", e);
58
+ }
59
+ }
60
+ async put(config, checkpoint, metadata, newVersions) {
61
+ const threadId = config.configurable?.thread_id;
62
+ const checkpointId = checkpoint.id;
63
+ if (!threadId || !checkpointId) {
64
+ return config;
65
+ }
66
+ this.checkpoints[`${threadId}:${checkpointId}`] = { checkpoint, metadata };
67
+ await this.saveRemote(threadId, checkpointId, checkpoint, metadata);
68
+ return {
69
+ configurable: {
70
+ thread_id: threadId,
71
+ checkpoint_id: checkpointId
72
+ }
73
+ };
74
+ }
75
+ // METHODS REQUIRED BY LANGGRAPH V0.1+
76
+ async putWrites(config, writes, taskId) {
77
+ }
78
+ async deleteThread(threadId) {
79
+ for (const key of Object.keys(this.checkpoints)) {
80
+ if (key.startsWith(`${threadId}:`)) {
81
+ delete this.checkpoints[key];
82
+ }
83
+ }
84
+ await this.deleteRemote(threadId);
85
+ }
86
+ async getTuple(config) {
87
+ const threadId = config.configurable?.thread_id;
88
+ const checkpointId = config.configurable?.checkpoint_id;
89
+ if (!threadId) return void 0;
90
+ const remote = await this.loadRemote(threadId, checkpointId);
91
+ if (remote) {
92
+ return { config, checkpoint: remote.checkpoint, metadata: remote.metadata };
93
+ }
94
+ if (checkpointId) {
95
+ const match = this.checkpoints[`${threadId}:${checkpointId}`];
96
+ if (match) {
97
+ return { config, checkpoint: match.checkpoint, metadata: match.metadata };
98
+ }
99
+ }
100
+ let latest;
101
+ for (const [key, val] of Object.entries(this.checkpoints)) {
102
+ if (key.startsWith(`${threadId}:`)) {
103
+ latest = { config, checkpoint: val.checkpoint, metadata: val.metadata };
104
+ }
105
+ }
106
+ return latest;
107
+ }
108
+ async *list(config, options) {
109
+ const threadId = config.configurable?.thread_id;
110
+ if (!threadId) return;
111
+ const remoteLatest = await this.loadRemote(threadId);
112
+ if (remoteLatest) {
113
+ yield { config, checkpoint: remoteLatest.checkpoint, metadata: remoteLatest.metadata };
114
+ }
115
+ for (const [key, val] of Object.entries(this.checkpoints)) {
116
+ if (key.startsWith(`${threadId}:`)) {
117
+ yield { config, checkpoint: val.checkpoint, metadata: val.metadata };
118
+ }
119
+ }
120
+ }
121
+ };
122
+ export {
123
+ LetsPingCheckpointer
124
+ };
125
+ //# sourceMappingURL=langgraph.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/langgraph.ts"],"sourcesContent":["import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata, CheckpointTuple } from \"@langchain/langgraph\";\r\nimport { RunnableConfig } from \"@langchain/core/runnables\";\r\nimport { LetsPing } from \"../index\";\r\n\r\ntype StoredCheckpoint = {\r\n checkpoint: Checkpoint;\r\n metadata: CheckpointMetadata;\r\n};\r\n\r\nexport class LetsPingCheckpointer extends BaseCheckpointSaver {\r\n private checkpoints: Record<string, StoredCheckpoint> = {};\r\n\r\n constructor(public client: LetsPing) {\r\n super();\r\n }\r\n\r\n private getTransport(): (<T = any>(method: string, path: string, body?: any) => Promise<T>) | null {\r\n const clientAny = this.client as any;\r\n if (typeof clientAny.request === \"function\") {\r\n return clientAny.request.bind(this.client);\r\n }\r\n return null;\r\n }\r\n\r\n private async saveRemote(\r\n threadId: string,\r\n checkpointId: string,\r\n checkpoint: Checkpoint,\r\n metadata: CheckpointMetadata\r\n ): Promise<void> {\r\n const transport = this.getTransport();\r\n if (!transport) {\r\n console.warn(\"[LetsPingCheckpointer] Missing underlying transport; falling back to in-memory only.\");\r\n return;\r\n }\r\n try {\r\n await transport(\"POST\", \"/langgraph/checkpoints\", {\r\n thread_id: threadId,\r\n checkpoint_id: checkpointId,\r\n checkpoint,\r\n metadata,\r\n });\r\n } catch (e) {\r\n console.warn(\"[LetsPingCheckpointer] Failed to persist checkpoint remotely; falling back to in-memory only.\", e);\r\n }\r\n }\r\n\r\n private async loadRemote(\r\n threadId: string,\r\n checkpointId?: string\r\n ): Promise<StoredCheckpoint | null> {\r\n const transport = this.getTransport();\r\n if (!transport) {\r\n console.warn(\"[LetsPingCheckpointer] Missing underlying transport; using in-memory checkpoints only.\");\r\n return null;\r\n }\r\n const search = checkpointId\r\n ? `?thread_id=${encodeURIComponent(threadId)}&checkpoint_id=${encodeURIComponent(checkpointId)}`\r\n : `?thread_id=${encodeURIComponent(threadId)}&latest=1`;\r\n try {\r\n const res = await transport<any>(\"GET\", `/langgraph/checkpoints${search}`);\r\n if (res && res.checkpoint && res.metadata) {\r\n return { checkpoint: res.checkpoint as Checkpoint, metadata: res.metadata as CheckpointMetadata };\r\n }\r\n } catch (e) {\r\n // If not found or backend unavailable, fall back to local cache only.\r\n console.warn(\"[LetsPingCheckpointer] Failed to load remote checkpoint\", e);\r\n }\r\n return null;\r\n }\r\n\r\n private async deleteRemote(threadId: string): Promise<void> {\r\n const transport = this.getTransport();\r\n if (!transport) return;\r\n const search = `?thread_id=${encodeURIComponent(threadId)}`;\r\n try {\r\n await transport(\"DELETE\", `/langgraph/checkpoints${search}`);\r\n } catch (e) {\r\n console.warn(\"[LetsPingCheckpointer] Failed to delete remote checkpoints\", e);\r\n }\r\n }\r\n\r\n async put(\r\n config: RunnableConfig,\r\n checkpoint: Checkpoint,\r\n metadata: CheckpointMetadata,\r\n newVersions?: Record<string, string | number>\r\n ): Promise<RunnableConfig> {\r\n const threadId = config.configurable?.thread_id;\r\n const checkpointId = checkpoint.id;\r\n\r\n if (!threadId || !checkpointId) {\r\n return config;\r\n }\r\n\r\n this.checkpoints[`${threadId}:${checkpointId}`] = { checkpoint, metadata };\r\n await this.saveRemote(threadId, checkpointId, checkpoint, metadata);\r\n\r\n return {\r\n configurable: {\r\n thread_id: threadId,\r\n checkpoint_id: checkpointId,\r\n },\r\n };\r\n }\r\n\r\n // METHODS REQUIRED BY LANGGRAPH V0.1+\r\n async putWrites(config: RunnableConfig, writes: any, taskId: string): Promise<void> {\r\n // No-op for V1: LetsPing focuses on primary state parking, not granular sub-task writes.\r\n }\r\n\r\n async deleteThread(threadId: string): Promise<void> {\r\n for (const key of Object.keys(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n delete this.checkpoints[key];\r\n }\r\n }\r\n await this.deleteRemote(threadId);\r\n }\r\n\r\n async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {\r\n const threadId = config.configurable?.thread_id;\r\n const checkpointId = config.configurable?.checkpoint_id;\r\n if (!threadId) return undefined;\r\n\r\n // Prefer remote truth, fall back to local cache.\r\n const remote = await this.loadRemote(threadId, checkpointId);\r\n if (remote) {\r\n return { config, checkpoint: remote.checkpoint, metadata: remote.metadata };\r\n }\r\n\r\n if (checkpointId) {\r\n const match = this.checkpoints[`${threadId}:${checkpointId}`];\r\n if (match) {\r\n return { config, checkpoint: match.checkpoint, metadata: match.metadata };\r\n }\r\n }\r\n\r\n let latest: CheckpointTuple | undefined;\r\n for (const [key, val] of Object.entries(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n latest = { config, checkpoint: val.checkpoint, metadata: val.metadata };\r\n }\r\n }\r\n return latest;\r\n }\r\n\r\n async *list(config: RunnableConfig, options?: any): AsyncGenerator<CheckpointTuple> {\r\n const threadId = config.configurable?.thread_id;\r\n if (!threadId) return;\r\n\r\n const remoteLatest = await this.loadRemote(threadId);\r\n if (remoteLatest) {\r\n yield { config, checkpoint: remoteLatest.checkpoint, metadata: remoteLatest.metadata };\r\n }\r\n\r\n for (const [key, val] of Object.entries(this.checkpoints)) {\r\n if (key.startsWith(`${threadId}:`)) {\r\n yield { config, checkpoint: val.checkpoint, metadata: val.metadata };\r\n }\r\n }\r\n }\r\n}"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letsping/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Agent trust layer: behavioral firewall, HITL, and Cryo-Sleep state for AI agents. Works with LangGraph, Vercel AI SDK, and custom runners.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -17,6 +17,9 @@
17
17
  "import": "./dist/integrations/langgraph.mjs"
18
18
  }
19
19
  },
20
+ "files": [
21
+ "dist"
22
+ ],
20
23
  "scripts": {
21
24
  "build": "tsup && tsc --emitDeclarationOnly --outDir dist",
22
25
  "dev": "tsup --watch",
package/CHANGELOG.md DELETED
@@ -1,34 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [0.3.0] - 2026-02-28
9
-
10
- ### Added
11
- - First-run experience: single-command demo path and dashboard "Run this" flow for time to first approval.
12
- - Framework-specific examples: LangGraph + Next.js, Vercel AI SDK + tools, Python + FastAPI (clone, set key, run).
13
- - Agent path in SDK: helpers for agent workspace creation and signed ingest so agent quickstart does not require raw curl/HMAC.
14
- - Ergonomic improvements: structured error codes with documentation links, JSDoc "See also" on key methods, optional retries and status helper for defer flows.
15
- - README "Guides" section: HITL in 2 min, LangGraph, Vercel AI SDK, agent-only, webhooks (links to docs and examples).
16
-
17
- ### Changed
18
- - Compatibility: Node.js 18+ (unchanged). All packages aligned to 0.3.0 for coordinated release; public CordiaLabs/LetsPing repo synced with examples and READMEs.
19
-
20
- ## [0.2.1] - 2025-02-28
21
-
22
- ### Changed
23
- - Package metadata: repository, homepage, license, keywords, engines (Node 18+).
24
-
25
- ## [0.2.0] - 2025-02
26
-
27
- ### Added
28
- - LangGraph integration (`@letsping/sdk/integrations/langgraph`) for state persistence and HITL.
29
- - Agent identity and escrow helpers: `signAgentCall`, `verifyEscrow`, `chainHandoff`.
30
- - Cryo-Sleep state parking with signed URLs.
31
- - Behavioral firewall (Markov-based anomaly detection) and smart-accept drift.
32
-
33
- ### Changed
34
- - Improved TypeScript types and exports.