{"_id":"@ar.io/anchor-vercel","_rev":"2-186f8c6272614589075b880de95bef8e","name":"@ar.io/anchor-vercel","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@ar.io/anchor-vercel","version":"0.1.0","keywords":["ar.io","arweave","vercel","ai-sdk","ai","llm","provenance","audit-trail","anchoring"],"license":"MIT","_id":"@ar.io/anchor-vercel@0.1.0","maintainers":[{"name":"vilenarios","email":"info@ardrive.io"}],"homepage":"https://github.com/ar-io/ar-io-anchor/tree/main/packages/vercel","bugs":{"url":"https://github.com/ar-io/ar-io-anchor/issues"},"dist":{"shasum":"6d8e099475d657867696e179cab5713324dbecee","tarball":"https://registry.npmjs.org/@ar.io/anchor-vercel/-/anchor-vercel-0.1.0.tgz","fileCount":8,"integrity":"sha512-0RX8ieZFtNxZD4IWOo7Bps8m79H8LSTsUiQ2LMieyP63YYID9VLeAMz9xM/wrtNXA0J60ApLMUuGz8M+eF3CnA==","signatures":[{"sig":"MEQCIAUOpJ8GN/rEEIqvLdGFxzp7SWVM401FGCnTeZMjBRqCAiBPLRhGoH9mFCWtNVCmNXSATEC81Qr+HMPJ+DCwvCLZLg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40440},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"313afd63feca6438fc0b9c6416e78f1d0d862136","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"vilenarios","email":"info@ardrive.io"},"repository":{"url":"git+https://github.com/ar-io/ar-io-anchor.git","type":"git","directory":"packages/vercel"},"_npmVersion":"10.8.2","description":"Anchor your Vercel AI SDK calls as they run: one language-model middleware turns every generate/stream into a Merkle-batched, individually inclusion-proofed provenance record on ar.io — prompts and outputs are hashed locally and never uploaded.","directories":{},"sideEffects":false,"_nodeVersion":"20.18.2","dependencies":{"@ar.io/anchor":"^0.1.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ai":"^6.0.0","@ar.io/proof":"^0.2.0"},"peerDependencies":{"ai":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/anchor-vercel_0.1.0_1781626499221_0.4956291348333146","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ar.io/anchor-vercel","version":"0.2.0","description":"Anchor your Vercel AI SDK calls as they run: one language-model middleware turns every generate/stream into a Merkle-batched, individually inclusion-proofed provenance record on ar.io — prompts and outputs are hashed locally and never uploaded.","license":"MIT","type":"module","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"dependencies":{"@ar.io/anchor":"^0.2.0"},"peerDependencies":{"ai":"^6.0.0"},"devDependencies":{"ai":"^6.0.0","@ar.io/proof":"^0.2.0"},"repository":{"type":"git","url":"git+https://github.com/ar-io/ar-io-anchor.git","directory":"packages/vercel"},"homepage":"https://github.com/ar-io/ar-io-anchor/tree/main/packages/vercel","publishConfig":{"access":"public"},"keywords":["ar.io","arweave","vercel","ai-sdk","ai","llm","provenance","audit-trail","anchoring"],"gitHead":"f47f769b080b7d87a59f2ab9b6dcbb9eb25661f6","_id":"@ar.io/anchor-vercel@0.2.0","bugs":{"url":"https://github.com/ar-io/ar-io-anchor/issues"},"_nodeVersion":"22.23.0","_npmVersion":"11.18.0","dist":{"integrity":"sha512-eN4Fyu504Bf7bVkdU1JsWr2S/qt45970LkKRiiVFRmYjFqUce3GSvlVQSDGPLBZ0HKWwht3Gr2Xo+gMs1n3DWQ==","shasum":"51bc2a8fc8364647953d09f42a345dc6735ae473","tarball":"https://registry.npmjs.org/@ar.io/anchor-vercel/-/anchor-vercel-0.2.0.tgz","fileCount":8,"unpackedSize":42263,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ar.io%2fanchor-vercel@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDS89zauE/9UhRCwWGuid393sjqqu0OTWpml9SyXk9JXgIgfPOsB2Y0I3BvD1c5mf6IDWJz7Vq1Jk/dYESnvz3Sf9M="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a6a4ee6c-042f-4803-a7f9-7de70277873e"}},"directories":{},"maintainers":[{"name":"vilenarios","email":"info@ardrive.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/anchor-vercel_0.2.0_1782831956079_0.2536429021800308"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-16T16:14:59.015Z","modified":"2026-06-30T15:05:56.616Z","0.1.0":"2026-06-16T16:14:59.369Z","0.2.0":"2026-06-30T15:05:56.257Z"},"bugs":{"url":"https://github.com/ar-io/ar-io-anchor/issues"},"license":"MIT","homepage":"https://github.com/ar-io/ar-io-anchor/tree/main/packages/vercel","keywords":["ar.io","arweave","vercel","ai-sdk","ai","llm","provenance","audit-trail","anchoring"],"repository":{"type":"git","url":"git+https://github.com/ar-io/ar-io-anchor.git","directory":"packages/vercel"},"description":"Anchor your Vercel AI SDK calls as they run: one language-model middleware turns every generate/stream into a Merkle-batched, individually inclusion-proofed provenance record on ar.io — prompts and outputs are hashed locally and never uploaded.","maintainers":[{"name":"vilenarios","email":"info@ardrive.io"}],"readme":"# @ar.io/anchor-vercel\n\nAnchor your AI SDK calls as they run. Add one language-model middleware, and every `generateText` / `streamText` becomes a tamper-evident provenance record:\n\n1. calls are **Merkle-batched on the hot path** — a whole request's calls are ONE write to Arweave (via [Turbo](https://ardrive.io/turbo), ar.io's upload service), not one per call,\n2. every call still gets its **own standalone inclusion proof**, verifiable offline against the batch checkpoint,\n3. prompts, settings, and outputs are **hashed locally and never uploaded** — the on-chain envelope carries only the hash (`ario.events/v1`, Minimal disclosure).\n\n```bash\nnpm install @ar.io/anchor-vercel @ar.io/anchor ai\n```\n\n```ts\nimport { createAnchorer } from \"@ar.io/anchor\";\nimport { anchorMiddleware } from \"@ar.io/anchor-vercel\";\nimport { generateText, wrapLanguageModel } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\"; // your model provider — install whichever you use\n\nconst provenance = anchorMiddleware(createAnchorer()); // dev mode: zero config\n\nconst model = wrapLanguageModel({ model: openai(\"gpt-4o\"), middleware: provenance });\n\nawait generateText({ model, prompt: \"Summarize the Q2 incident reports\" });\n\n// End of request / run / process: flush and collect the proofs.\nconst receipts = await provenance.close();\nfor (const r of receipts) {\n  console.log(r.envelope.event_id, \"→ checkpoint\", r.checkpointTxId, `leaf ${r.leafIndex}/${r.leafCount}`);\n  // r.recordBytes is YOUR copy of what the hash commits to — retain it.\n}\n```\n\nProduction refuses auto-generated secrets — `createAnchorer({ environment: \"production\", signer, wallet })` per [`@ar.io/anchor`](https://github.com/ar-io/ar-io-anchor/tree/main/packages/anchor)'s structural gate. Dev proofs are permanently marked `environment: \"dev\"` inside the signed bytes.\n\n## Grouping calls into a chain\n\nThe Vercel AI SDK middleware wraps the **model**, not the application, so — unlike [`@ar.io/anchor-langchain`](https://github.com/ar-io/ar-io-anchor/tree/main/packages/langchain), whose callbacks give a run *tree* — events here form a **flat chain** (`seq` + `prev_event_id`, committed in each record's metadata). You choose what groups them:\n\n- **Correlation id (recommended for multi-call requests):** pass an id via `providerOptions.ario.chainKey`, and every call sharing it links in order — your request id, conversation id, or agent-loop id.\n\n  ```ts\n  await generateText({\n    model,\n    prompt,\n    providerOptions: { ario: { chainKey: requestId } },\n  });\n  ```\n\n- **Session fallback (zero-config):** with no id, all calls through one middleware instance link in emission order under a per-instance `session:<uuid>` chain.\n\nEither way it's a flat sequence, not a tree: each record points at its predecessor inside individually signed, inclusion-proofed bytes, so a dropped event dangles, a reordered one disagrees on `seq`, and an edited one breaks its hash — **deletion-evident and reorder-evident** for the calls present.\n\n## Event vocabulary\n\n`vercel_ai.generate_start/_end/_error` and `vercel_ai.stream_start/_end/_error` — one event type per anchored operation (exported as `EVENT_TYPES`). Each operation gets exactly one terminal event: `_end` on success, `_error` on failure. For streams, a provider failure arrives in-band as an `error` part and anchors `stream_error`; chunks pass through untouched. A hard transport abort (the stream rejects with no error part) anchors neither terminal event — the `stream_start` stands and its missing completion is itself the signal (its chain pointer dangles).\n\n## Controlling what the hash commits to\n\nNothing leaves your process either way — but the committed record is what you retain and what an auditor asks for. `mapPayload` runs before the hash is computed:\n\n```ts\nconst provenance = anchorMiddleware(anchorer, {\n  batch: { maxEvents: 64, flushOnIdle: 2_000 },     // batching knobs (first trigger wins)\n  mapPayload: (e) => {\n    if (e.type === \"vercel_ai.generate_start\") return null; // skip entirely\n    return { ...e.payload, prompt: undefined };             // or redact fields\n  },\n});\n```\n\nSkipped events consume no sequence number — the committed chain stays gapless.\n\n## Verifying\n\nCollect the receipts, serialize them into ONE signed, portable `trace-bundle.json`, and hand it to an auditor — they verify the whole thing (every event's signature + payload binding + Merkle inclusion, offline) with **one command** and the read-only [`@ar.io/proof`](https://www.npmjs.com/package/@ar.io/proof) (no write SDK in the trust path):\n\n```ts\nconst receipts = await provenance.close();\nconst bundle = await ario.bundle(receipts); // signed with the anchorer's own key — zero ceremony\nawait fs.writeFile(\"trace-bundle.json\", JSON.stringify(bundle, null, 2));\n```\n\n> Want the auditor to read the actual calls — the raw prompt/response bytes, not just verify their hashes? Pass `ario.bundle(receipts, { disclose })` (keyed by `eventId`) to embed selected events' bytes inside the signed bundle — opt-in, default off, on-chain footprint unchanged. See [disclosure in the core README](https://github.com/ar-io/ar-io-anchor/blob/main/packages/anchor/README.md#optionally-include-the-raw-logs-opt-in-default-off).\n\n```bash\nnpx @ar.io/proof verify trace-bundle.json\n# optionally re-fetch each checkpoint on-chain to confirm it's anchored:\nnpx @ar.io/proof verify trace-bundle.json https://arweave.net,https://permagate.io\n```\n\nThe whole story is five steps: anchor → `await provenance.close()` → `await ario.bundle(receipts)` → write `trace-bundle.json` → `npx @ar.io/proof verify trace-bundle.json`. Need an explicit key or to override the issuer/gateway? The advanced form is `toEvidenceBundle(receipts, { signer, issuer })` from `@ar.io/anchor`.\n\nIt prints a per-event + rollup verdict and exits on a pinned code (`0` verified · `1` failed · `2` malformed · `3` gateway-unavailable); the producer's asserted verdict is shown but never trusted (the verdict is recomputed from the body). A **withheld** record surfaces as semantics-undetermined (`~`), not a failure.\n\n> **Live:** the bundle emit (`ario.bundle()` / `toEvidenceBundle`) ships in `@ar.io/anchor` ≥ 0.1.3 and the `npx @ar.io/proof verify` CLI in `@ar.io/proof` ≥ 0.2.2. The `@ar.io/proof` primitives below remain available for manual/advanced verification.\n\nA single receipt also verifies by hand against the read-only kernel (`@ar.io/proof` `^0.2.0`, the full-family verifier):\n\n```ts\nimport { verifyEnvelope, verifyInclusion, hexToBytes } from \"@ar.io/proof\";\n\n// Supply the retained record bytes and the envelope verifies green end-to-end.\nconst result = await verifyEnvelope(r.envelope, { payloadBytes: r.recordBytes });\nresult.ok;            // true — signature + payload binding\nconst inclusionOk = await verifyInclusion(\n  hexToBytes(r.leafHash), r.leafIndex, r.leafCount,\n  r.auditPath.map(hexToBytes), hexToBytes(r.root),\n);\n```\n\n**Without the record** (external commitment), `verifyEnvelope(r.envelope)` confirms the signature but reports **`payloadHashOk: null`** — *semantics-undetermined*, **not** a failure. Treat `null` as \"supply the record to complete the proof,\" never as a pass and never as a tamper; a genuinely tampered record returns `payloadHashOk: false` with `ok: false`. The checkpoint is fetched through any [ar.io gateway](https://gateways.ar.io) (`r.gatewayUrl`) and re-verified the same way — the gateway is delivery, never trust.\n\n## Semantics\n\n- **Hot path is synchronous.** Each call is one in-memory `batch.add()`; signing and the single upload happen at window flush. A model call never waits on the network for anchoring.\n- **Errors are observed, never swallowed.** A failed call anchors a `*_error` event and the original error re-throws to your code unchanged.\n- **Lifecycle is explicit.** `await provenance.close()` flushes and resolves all receipts; there are no hidden process-exit hooks. Long-lived middleware can `flush()` between requests.\n- **Provenance never crashes the call.** A payload that fails to serialize is reported via `warn` and skipped — the model call still runs and returns.\n- **Bounded memory on long-lived servers.** One middleware instance batches across requests (keep it long-lived to amortize writes), and it tracks a little chain state per distinct `chainKey`. That map is a bounded LRU (`maxTrackedChains`, default 10,000) — a correlation id evicted after long inactivity simply restarts at `seq 0` if it ever returns, so per-request ids never accumulate without bound.\n- **Retention is yours.** External commitment means the receipt's `recordBytes` are the only copy of what the hash commits to. Store them — an envelope without its record proves a commitment existed, not what it said.\n- Provenance, not endorsement: a verified history says *what happened* — never \"safe\" or \"approved\".\n\n## License\n\nMIT. The framework is a peer dependency; this package depends only on [`@ar.io/anchor`](https://github.com/ar-io/ar-io-anchor/tree/main/packages/anchor).\n","readmeFilename":"README.md"}