{"_id":"@actenon/sdk","name":"@actenon/sdk","dist-tags":{"latest":"1.4.0"},"versions":{"1.4.0":{"name":"@actenon/sdk","version":"1.4.0","description":"Official TypeScript SDK for Actenon — protected execution for AI agents with discriminated result types, receipt verification, and protocol parity with the Python SDK.","type":"module","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./protocol":{"types":"./dist/protocol.d.ts","import":"./dist/protocol.js"},"./crypto":{"types":"./dist/crypto.d.ts","import":"./dist/crypto.js"}},"scripts":{"test":"bun test","typecheck":"tsc --noEmit","build":"tsc","prepack":"bun run build","pack:test":"bun run build && npm pack --dry-run"},"keywords":["ai","agents","security","authorization","pdp","pep","capabilities","policy","actenon","broker","proof"],"license":"Apache-2.0","author":{"name":"Actenon"},"repository":{"type":"git","url":"git+https://github.com/Actenon/actenon-permit.git","directory":"ts-sdk"},"engines":{"node":">=18"},"devDependencies":{"@types/bun":"^1.3.14","typescript":"^5.5.0"},"_id":"@actenon/sdk@1.4.0","gitHead":"7781dca6d4e5b1c9ea646e85821d7d6a8a5954f7","bugs":{"url":"https://github.com/Actenon/actenon-permit/issues"},"homepage":"https://github.com/Actenon/actenon-permit#readme","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-bnz7UHshMrKtzyTLTKyKJxZ5CglUN7NgEL03/poQDAJiaoApxJycLtzgTkdBaaalJPsjqcQCPopN/lprbpXrIw==","shasum":"f9000df6821c072ec60c410f0368685a1575567c","tarball":"https://registry.npmjs.org/@actenon/sdk/-/sdk-1.4.0.tgz","fileCount":34,"unpackedSize":96960,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC7Mgv1A7+XVDUTazkblaquHLu4xbaK3VzpkF3Mlj8ONwIgb/tZzHhrtQfvGp60/LsXxFG4sCjEiWjYEe+aUKDlWU8="}]},"_npmUser":{"name":"actenon","email":"ross.buckley1990@gmail.com"},"directories":{},"maintainers":[{"name":"actenon","email":"ross.buckley1990@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_1.4.0_1784763073166_0.5647443739956948"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-22T23:31:12.987Z","1.4.0":"2026-07-22T23:31:13.306Z","modified":"2026-07-22T23:31:13.499Z"},"maintainers":[{"name":"actenon","email":"ross.buckley1990@gmail.com"}],"description":"Official TypeScript SDK for Actenon — protected execution for AI agents with discriminated result types, receipt verification, and protocol parity with the Python SDK.","homepage":"https://github.com/Actenon/actenon-permit#readme","keywords":["ai","agents","security","authorization","pdp","pep","capabilities","policy","actenon","broker","proof"],"repository":{"type":"git","url":"git+https://github.com/Actenon/actenon-permit.git","directory":"ts-sdk"},"author":{"name":"Actenon"},"bugs":{"url":"https://github.com/Actenon/actenon-permit/issues"},"license":"Apache-2.0","readme":"# @actenon/sdk\n\nThe official TypeScript SDK for [Actenon](https://github.com/Actenon/actenon-permit) —\nprotected execution for AI agents with discriminated result types, receipt\nverification, and protocol parity with the Python SDK.\n\n## Installation\n\n```bash\nnpm install @actenon/sdk\n# or\nbun add @actenon/sdk\n# or\nyarn add @actenon/sdk\n```\n\n## Quickstart\n\n```typescript\nimport { Actenon } from \"@actenon/sdk\";\n\nconst client = Actenon.cloud({\n  baseUrl: \"http://localhost:7780\",\n  grantToken: \"v1.YOUR_GRANT_TOKEN\",\n});\n\nconst intent = await client.authorisedExecutionIntents.create({\n  action: \"github.issue.create\",\n  target: \"github\",\n  parameters: {\n    title: \"Hello from TS SDK\",\n    body: \"Created through authorised execution.\",\n  },\n});\n\nconst result = await intent.execute();\n\n// Result is a discriminated union — you MUST narrow on `mode`.\nif (result.mode === \"brokered\" && result.state === \"succeeded\") {\n  console.log(\"Issue created:\", result.evidence);\n  console.log(\"Receipt verified:\", result.receiptVerified);\n}\n```\n\n## Type safety\n\nResults are discriminated unions. The TypeScript compiler enforces mode-aware\ninterpretation — you cannot access `receiptVerified` on a `resource_owned`\nresult without first narrowing:\n\n```typescript\n// ✅ Correct — narrowing on mode\nif (result.mode === \"brokered\") {\n  console.log(result.receiptVerified); // OK\n} else {\n  console.log(result.resourceReceiptVerified); // OK\n}\n\n// ❌ Type error — no narrowing\nconsole.log(result.receiptVerified); // Error: Property does not exist on ResourceOwnedResult\n```\n\nThis prevents the unsafe pattern:\n\n```typescript\n// ❌ Not allowed — result.state is not enough; you must understand who executed it\nif (result.state === \"succeeded\") {\n  // Without checking result.mode, you don't know if this was brokered or resource-owned\n}\n```\n\n## Discriminated results\n\n### BrokeredResult\n\n```typescript\ninterface BrokeredResult {\n  mode: \"brokered\";\n  intentId: string;\n  state: \"succeeded\" | \"failed\" | \"refused\" | \"outcome_unknown\";\n  finality: \"final\" | \"non_final\";\n  providerExecutionObserved: boolean;\n  receiptReceived: boolean;\n  receiptVerified: boolean;\n  evidence: Record<string, unknown>;\n  attemptId: string | null;\n}\n```\n\n### ResourceOwnedResult\n\n```typescript\ninterface ResourceOwnedResult {\n  mode: \"resource_owned\";\n  intentId: string;\n  state: \"submitted\" | \"accepted\" | \"refused\" | \"succeeded\" | \"failed\" | \"outcome_unknown\";\n  finality: \"final\" | \"non_final\";\n  providerExecutionObserved: boolean;\n  resourceReceiptReceived: boolean;\n  resourceReceiptVerified: boolean;\n  submissionReference: string | null;\n  evidence: Record<string, unknown>;\n  attemptId: string | null;\n}\n```\n\n## Structured exceptions\n\n```typescript\nimport { ExecutionRefusedError, OutcomeUnknownError } from \"@actenon/sdk\";\n\ntry {\n  const result = await intent.execute();\n} catch (e) {\n  if (e instanceof ExecutionRefusedError) {\n    console.error(\"refused:\", e.message, \"rule:\", e.rule);\n  } else if (e instanceof OutcomeUnknownError) {\n    console.error(\"outcome unknown (retryable):\", e.message);\n  }\n}\n```\n\n| Exception | When | Retryable |\n|---|---|---|\n| `ExecutionRefusedError` | Action refused (out of scope, proof invalid) | No |\n| `ExecutionFailedError` | Provider call failed | No |\n| `OutcomeUnknownError` | Timeout, partial response | Yes |\n| `ProviderError` | Adapter crash | Depends |\n| `IntentNotFoundError` | Intent id not found | No |\n\n## Receipt verification\n\n```typescript\nimport { verifyResourceReceipt } from \"@actenon/sdk\";\n\nconst verified = verifyResourceReceipt(\n  { charge_id: \"ch_123\", signing_key_id: \"rk_1\", signature: \"abc...\" },\n  new Map([[\"rk_1\", new TextEncoder().encode(\"the-secret\")]]),\n);\nif (!verified) throw new Error(\"forged receipt!\");\n```\n\n## Capabilities\n\n```typescript\nconst caps = client.capabilities;\n// {\n//   transport: \"cloud\",\n//   supportsBrokered: true,\n//   supportsResourceOwned: true,\n//   supportsAsync: true,\n//   supportsPolling: true,\n//   durable: true,\n//   productionMode: true\n// }\n```\n\n## Environment support\n\n| Environment | Supported | Notes |\n|---|---|---|\n| Node.js 18+ (LTS) | ✅ | Primary target. Uses `node:crypto` for HMAC. |\n| Node.js 20+ (LTS) | ✅ | Recommended. |\n| Node.js 22+ (LTS) | ✅ | |\n| Bun | ✅ | Tested with Bun 1.3+. |\n| Deno | ⚠️ | Should work via npm: specifier; not tested. |\n| Browser | ⚠️ | Receipt verification works (uses Web Crypto). **Credential registration is blocked** — secret-bearing broker code must not run in an untrusted browser. |\n| ESM | ✅ | `\"type\": \"module\"` |\n| CommonJS | ❌ | Not supported. ESM-only. |\n\n### Browser safety\n\nThe SDK blocks `registerCredential()` and `registerResourceFromConfig()` in\nbrowser environments. These methods require server-side execution because they\nhandle secret material. Browser clients should only use `Actenon.cloud()` to\ntalk to a server-side gateway that holds the credentials.\n\n## Python parity\n\nThe TypeScript and Python SDKs agree on all protocol-level semantics:\n\n| Feature | Python | TypeScript | Parity |\n|---|---|---|---|\n| Lifecycle states | 14 states | 14 states | ✅ |\n| Execution modes | brokered, resource_owned | brokered, resource_owned | ✅ |\n| Brokered result states | succeeded, failed, refused, outcome_unknown | same | ✅ |\n| Resource-owned result states | 6 states | 6 states | ✅ |\n| Finality | final, non_final | final, non_final | ✅ |\n| Discriminated union | `BrokeredResult \\| ResourceOwnedResult` | `BrokeredResult \\| ResourceOwnedResult` | ✅ |\n| Receipt verification | HMAC-SHA256, canonical JSON | HMAC-SHA256, canonical JSON | ✅ |\n| Canonicalisation | JCS (sorted keys, no whitespace) | JCS (sorted keys, no whitespace) | ✅ |\n| Exception hierarchy | `ActenonError` → 6 subclasses | `ActenonError` → 6 subclasses | ✅ |\n| Retryability | `.retryable` property | `.retryable` property | ✅ |\n| Capability info | `CapabilityInfo` dataclass | `CapabilityInfo` interface | ✅ |\n\n### Known differences from Python\n\n| Aspect | Python | TypeScript | Reason |\n|---|---|---|---|\n| Sync API | ✅ `Actenon.local()` sync | ❌ async only | TS is async-first; sync broker calls would block the event loop |\n| In-process broker | ✅ `LocalActenonClient` runs broker in-process | ❌ HTTP to local gateway | Secret-bearing code must stay server-side in TS |\n| Signing key auto-gen | ✅ `~/.actenon-permit/dev-signing-key` | ❌ server-side only | TS SDK doesn't run the broker in-process |\n| Naming | `snake_case` (e.g. `provider_execution_observed`) | `camelCase` (e.g. `providerExecutionObserved`) | Idiomatic TS |\n| Dev signing key warning | ✅ `UserWarning` | ❌ N/A (server-side) | TS SDK doesn't auto-gen keys |\n\n## Build\n\n```bash\nbun install\nbun run build        # tsc → dist/\nbun run typecheck    # tsc --noEmit\nbun test             # run tests\n```\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md","_rev":"1-a955edf05b2247204d52d4330505f1e2"}