{"_id":"@archal/vitest","_rev":"5-87f2d06280cc74c9ad84ed31f132e4d7","name":"@archal/vitest","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@archal/vitest","version":"0.1.0","license":"MIT","_id":"@archal/vitest@0.1.0","maintainers":[{"name":"aidantiruvan","email":"aidan@archal.ai"},{"name":"noahsong-sdg","email":"noah@archal.ai"}],"homepage":"https://github.com/Archal-Labs/archal#readme","bugs":{"url":"https://github.com/Archal-Labs/archal/issues"},"dist":{"shasum":"19e53d45e4bc88c34d3c5e5752e74a16b23d17cf","tarball":"https://registry.npmjs.org/@archal/vitest/-/vitest-0.1.0.tgz","fileCount":9,"integrity":"sha512-yD8IeRmMKUWv7bURdTP64V8/pHXw2xm8kO33wcPe5Rlg9puJbR2TxmZ2mzXkArI2NT9XxNzHEH+zYyoT5HYmlA==","signatures":[{"sig":"MEUCIQCx8ro5m15DAbyqNMMab60lwq9WqV17oDm06S1M4KTwgwIgPKQyqS5PkesrWq93Ou7VgpHG9VVpuqUxQLP/3tE8FMk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38988},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"fd78c2fc4e7c912f4270a76731ab3e86322b37c9","scripts":{"test":"vitest run --workspace vitest.workspace.ts","build":"tsup src/index.ts src/runtime/setup-files.ts src/runtime/hosted-session-reaper.ts --format esm --dts --external vitest --external vitest/config --external @archal/route-runtime-core","pretest":"pnpm --filter @archal/route-runtime-core build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"noahsong-sdg","email":"noah@archal.ai"},"deprecated":"Use the \"archal/vitest\" subpath instead: npm i archal && import from \"archal/vitest\".","repository":{"url":"git+https://github.com/Archal-Labs/archal.git","type":"git","directory":"packages/vitest"},"_npmVersion":"10.9.4","description":"Vitest integration for Archal digital twin testing","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@archal/route-runtime-core":"workspace:*"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","stripe":"^20.3.1","vitest":"^2.1.0","jira.js":"^5.3.1","googleapis":"^171.0.0","typescript":"^5.9.0","@types/node":"^25.3.3","@octokit/rest":"^22.0.1","@slack/web-api":"^7.12.0","@supabase/supabase-js":"^2.57.2"},"_npmOperationalInternal":{"tmp":"tmp/vitest_0.1.0_1775157340993_0.5715096026658506","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@archal/vitest","version":"0.1.1","license":"MIT","_id":"@archal/vitest@0.1.1","maintainers":[{"name":"aidantiruvan","email":"aidan@archal.ai"},{"name":"noahsong-sdg","email":"noah@archal.ai"}],"homepage":"https://github.com/Archal-Labs/archal#readme","bugs":{"url":"https://github.com/Archal-Labs/archal/issues"},"dist":{"shasum":"8bc1790d7814a597ce6f41a8b7882e6f3490cee7","tarball":"https://registry.npmjs.org/@archal/vitest/-/vitest-0.1.1.tgz","fileCount":10,"integrity":"sha512-fq0d92griJtVi1Qx1Hkae/qcAxd0S0Zt218DggDJANzmXFCm5VEQ2kz+o6MWCKdf/MajFf3l+6mCb2W0OQLQgQ==","signatures":[{"sig":"MEYCIQCYFKxnc3NLEbIhmcsjFl+EYCQQ/7V8i91pWIVYth/YZQIhAIzGGrwo1HEGUAfGBWTH7KeQMWzomHCklvKshobusZVb","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39404},"main":"dist/index.js","type":"module","_from":"file:archal-vitest-0.1.1.tgz","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"vitest run --workspace vitest.workspace.ts","build":"tsup src/index.ts src/runtime/setup-files.ts src/runtime/hosted-session-reaper.ts --format esm --dts --external vitest --external vitest/config --external @archal/route-runtime-core","pretest":"pnpm --filter @archal/route-runtime-core build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"noahsong-sdg","email":"noah@archal.ai"},"_resolved":"/private/var/folders/25/8ltryvd917dc97wt_95t4rx80000gn/T/4852abe3ba98cb0a46f051220cb83286/archal-vitest-0.1.1.tgz","_integrity":"sha512-fq0d92griJtVi1Qx1Hkae/qcAxd0S0Zt218DggDJANzmXFCm5VEQ2kz+o6MWCKdf/MajFf3l+6mCb2W0OQLQgQ==","repository":{"url":"git+https://github.com/Archal-Labs/archal.git","type":"git","directory":"packages/vitest"},"_npmVersion":"10.8.2","description":"Vitest integration for Archal digital twin testing","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@archal/route-runtime-core":"0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","stripe":"^20.3.1","vitest":"^2.1.0","jira.js":"^5.3.1","googleapis":"^171.0.0","typescript":"^5.9.0","@types/node":"^25.3.3","@octokit/rest":"^22.0.1","@slack/web-api":"^7.12.0","@supabase/supabase-js":"^2.57.2"},"_npmOperationalInternal":{"tmp":"tmp/vitest_0.1.1_1775157892948_0.7776477363320016","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Use the \"archal/vitest\" subpath instead: npm i archal && import from \"archal/vitest\"."},"0.1.2":{"name":"@archal/vitest","version":"0.1.2","license":"MIT","_id":"@archal/vitest@0.1.2","maintainers":[{"name":"aidantiruvan","email":"aidan@archal.ai"},{"name":"noahsong-sdg","email":"noah@archal.ai"}],"homepage":"https://github.com/Archal-Labs/archal#readme","bugs":{"url":"https://github.com/Archal-Labs/archal/issues"},"dist":{"shasum":"1f0f1e37a1f65866ac87b6e3df973e270295faee","tarball":"https://registry.npmjs.org/@archal/vitest/-/vitest-0.1.2.tgz","fileCount":12,"integrity":"sha512-HGqDqRbSBO6jQalJBAUgpmb6inXPaB7F2qd3jdFNgByWI+hzmripmdI/zGMnUfP7sKxJCm9VLyaNuNeFhERl8Q==","signatures":[{"sig":"MEQCIFUzyIsEdKWQ3bnbPT//ks5hMc2iSJilA6phdEiXBaNtAiBFLp9T4t8nwHWxEbZdSnEMcWlETFvvtatIQlhtvUkiGw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":159011},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"e8316e58c5725195c03622dcdaca94462d03c16d","scripts":{"test":"pnpm run test:raw","build":"pnpm run build:raw","prepack":"pnpm build","test:raw":"vitest run --workspace vitest.workspace.ts","build:raw":"tsup --config tsup.config.ts","typecheck":"pnpm run typecheck:raw","typecheck:raw":"tsc --noEmit","test:hosted-provider:raw":"vitest run --workspace vitest.workspace.ts --project hosted-provider"},"_npmUser":{"name":"noahsong-sdg","email":"noah@archal.ai"},"repository":{"url":"git+https://github.com/Archal-Labs/archal.git","type":"git","directory":"packages/vitest"},"_npmVersion":"10.8.2","description":"Hosted Archal route-mode support for Vitest","directories":{},"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","stripe":"^20.3.1","vitest":"^2.1.0","jira.js":"^5.3.1","googleapis":"^171.0.0","typescript":"^5.9.0","@types/node":"^25.3.3","@octokit/rest":"^22.0.1","@slack/web-api":"^7.12.0","@archal/runtime":"workspace:*","@archal/node-auth":"workspace:*","@supabase/supabase-js":"^2.57.2","@archal/route-runtime-core":"workspace:*"},"peerDependencies":{"vitest":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/vitest_0.1.2_1775582894532_0.26600126883006214","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Use the \"archal/vitest\" subpath instead: npm i archal && import from \"archal/vitest\"."}},"time":{"created":"2026-04-02T19:15:40.872Z","modified":"2026-05-20T03:52:36.120Z","0.1.0":"2026-04-02T19:15:41.213Z","0.1.1":"2026-04-02T19:24:53.094Z","0.1.2":"2026-04-07T17:28:14.683Z"},"bugs":{"url":"https://github.com/Archal-Labs/archal/issues"},"license":"MIT","homepage":"https://github.com/Archal-Labs/archal#readme","repository":{"url":"git+https://github.com/Archal-Labs/archal.git","type":"git","directory":"packages/vitest"},"description":"Hosted Archal route-mode support for Vitest","maintainers":[{"name":"aidantiruvan","email":"aidan@archal.ai"},{"name":"noahsong-sdg","email":"noah@archal.ai"}],"readme":"# `@archal/vitest`\n\nHosted route-mode bootstrap for Vitest.\n\nThis package is hosted-only. It does not boot local twins. It configures Vitest to start an Archal hosted session, install route-mode request rewriting, and expose the resolved hosted runtime state to tests.\n\n## Two Usage Patterns\n\nPick whichever matches your existing Vitest setup.\n\n### 1. Single `vitest.config.ts` (recommended for most projects)\n\n```ts\nimport { defineConfig } from 'vitest/config';\nimport { archalVitestConfig } from '@archal/vitest';\n\nexport default defineConfig({\n  test: archalVitestConfig({\n    services: {\n      stripe: { mode: 'route', seed: 'small-business' },\n      github: { mode: 'route', seed: 'small-project' },\n    },\n  }),\n});\n```\n\n`archalVitestConfig()` returns a complete Vitest test config — wire it into `defineConfig({ test: ... })` directly.\n\n### 2. `vitest.workspace.ts` (for multi-project monorepos)\n\n```ts\nimport { archalVitestProject } from '@archal/vitest';\n\nexport default [\n  archalVitestProject(\n    {\n      name: 'github-hosted-live',\n      services: {\n        github: { mode: 'route', seed: 'small-project' },\n        stripe: { mode: 'route' },\n      },\n    },\n    {\n      include: ['__tests__/hosted-live.test.ts'],\n    },\n  ),\n];\n```\n\n`archalVitestProject()` returns a workspace project definition — use it inside the array exported from `vitest.workspace.ts`. **Do not** wrap it in `defineConfig({ test: archalVitestProject(...) })` — that pattern silently drops the setup files and lets requests hit real SaaS APIs. Use `archalVitestConfig()` instead for the single-config pattern.\n\n## Defaults Applied Automatically\n\nBoth helpers apply the same defaults so a developer's first run works without extra tuning:\n\n- `hookTimeout: 120_000` and `testTimeout: 120_000` — ECS Fargate cold-start for twins can take 30s+, which exceeds Vitest's 10s/5s defaults.\n- `exclude: ['**/node_modules/**', ...]` — prevents Vitest from walking into bundled Archal tests when installed as an npm dependency.\n- `setupFiles: [<route-mode bootstrap>]` — wires the hosted session provisioning and request interception.\n\nPass your own `hookTimeout`/`testTimeout`/`exclude`/`include` in the second argument to override these.\n\n## Reset Twin State Between Tests\n\nBy default, twin state accumulates across tests in a run. Use `resetArchalTwins()` in `beforeEach` to get a fresh world:\n\n```ts\nimport { beforeEach } from 'vitest';\nimport { resetArchalTwins } from '@archal/vitest';\n\nbeforeEach(async () => {\n  await resetArchalTwins();\n});\n```\n\nThis restores each twin to the post-seed state that was captured during session bootstrap — no re-provisioning, no cold start, just a clean state snapshot pushed back to each twin in parallel. Typical cost is a few hundred milliseconds.\n\n`resetArchalTwins()` also drains the twins' pending webhook queues so each test starts with no leftover deliveries from the previous one.\n\n## Webhook Testing\n\nTest your webhook handlers without needing a tunnel, public URL, or mock server. The hosted twin runs in AWS ECS and can't reach your localhost, so instead of the twin POSTing to you, your test pulls queued deliveries over the same session and invokes your handler directly.\n\n```ts\nimport { waitForArchalWebhook, listArchalWebhooks, clearArchalWebhooks } from '@archal/vitest';\n\nit('records subscription via webhook handler', async () => {\n  // 1. Register an endpoint so the twin knows to queue events\n  await stripe.webhookEndpoints.create({\n    url: 'http://test.local/wh',\n    enabled_events: ['customer.subscription.created'],\n  });\n\n  // 2. Fire the event via normal SDK calls\n  const customer = await stripe.customers.create({ email: 'a@b.com' });\n  const sub = await stripe.subscriptions.create({ customer: customer.id, items: [...] });\n\n  // 3. Pull the queued delivery; default timeout 2000ms, default consume:true\n  const event = await waitForArchalWebhook('stripe', 'customer.subscription.created');\n\n  // 4. Invoke your handler with the exact payload the twin queued\n  await handleStripeWebhook(event.body, event.headers['Stripe-Signature'], secret);\n});\n```\n\n**API**:\n- `waitForArchalWebhook(service, eventTypeOrMatcher, options?)` — polls the twin, returns first match within `timeout` (default 2000ms). With `consume: true` (default), drops the service's queue after matching so it can't be re-returned. Pass `consume: false` for sequence assertions.\n- `waitForArchalWebhook(service, { eventType, where, timeout, consume })` — the full options form. `where` is a predicate `(delivery) => boolean` applied after `eventType`.\n- `listArchalWebhooks(service)` — one-shot snapshot of currently queued deliveries. Does not consume.\n- `clearArchalWebhooks(service)` — manually drop the service's queue.\n\n**Supported services**:\n\n| Service | Webhook helper support |\n|---|---|\n| Stripe, GitHub, Slack | ✅ Full — signatures computed at queue time |\n| Jira, Linear | ✅ Via history buffer — survives their inline `flush()` |\n| Supabase | ❌ Database-triggered webhooks; test against real Postgres |\n| Google Workspace | ❌ Uses GCP Pub/Sub, not webhooks |\n\n**Signature verification**: `delivery.body` is the exact JSON string the twin would have POSTed; use it with `delivery.headers[SIGNATURE_HEADER]` and the endpoint's secret. Do NOT re-serialize `delivery.payload` — key order/spacing changes will break HMAC verification.\n\n**Parallel worker safety**: per-worker twin state isolation (shipped alongside this helper) gives each vitest worker its own webhook queue automatically. Worker A cannot consume worker B's deliveries when both workers use isolation-enabled twins. Twins without isolation (Supabase, Google Workspace, Telegram, Ramp, Browser) still share a queue across workers — for those, set `testIsolation: 'serial'` if you depend on event ordering.\n\n**Slack caveat**: Slack verifies signatures at the receiver (timestamp + body, not a sender-side header). `delivery.headers` from a Slack twin delivery won't include `X-Slack-Signature`; stub verification in tests or compute the header yourself.\n\n**Silence**: the webhook queue-drain that runs inside `resetArchalTwins()` is best-effort and doesn't log.\n\n## Session Reuse Across Runs\n\nThe integration computes a stable session key from `(projectName, services, seeds)` so that repeated `vitest run` invocations with the same configuration reuse an already-provisioned hosted session. First run pays the 30s cold-start cost; subsequent runs finish in ~2s until the session's 30-minute idle TTL expires or the configuration changes.\n\n## Inspecting Resolved Runtime\n\nUse `getInstalledArchalVitestSession()` inside a test to see what the backend actually resolved:\n\n```ts\nimport { getInstalledArchalVitestSession } from '@archal/vitest';\n\nconst session = getInstalledArchalVitestSession();\n\nconsole.log(session?.resolvedRuntime.resolvedServices);\nconsole.log(session?.resolvedRuntime.resolvedSeeds);\nconsole.log(session?.resolvedRuntime.manifestVersions);\nconsole.log(session?.resolvedRuntime.capabilityVersion);\nconsole.log(session?.resolvedRuntime.runtimeVersion);\n```\n\nThat makes seed resolution and backend/runtime drift visible in CI failures instead of hidden in client defaults.\n\nThe session object returned here is a **redacted snapshot** — it deliberately does not expose routed-request auth headers or other credentials. The route runtime injects auth internally when forwarding test requests to twins; userland code should never need the raw token.\n\n## Authentication\n\nThe integration needs an Archal token to provision twin sessions. In priority order:\n\n1. `ARCHAL_VITEST_TOKEN` env var\n2. `ARCHAL_TOKEN` env var\n3. Stored credentials from `archal login` in `~/.archal/credentials.json`\n\nWhen stored credentials are used, the adapter refreshes them automatically before hosted-session API calls and keeps the routed twin auth header current during long watch runs.\n\n## Credential Sandbox Under Tests\n\nWhen running under Vitest, Jest, or `node --test`, the credential store automatically redirects to a per-worker sandbox in the OS temp directory. On first access it copies your real `~/.archal/credentials.json` into the sandbox, so reads see valid credentials. **Any writes stay isolated from your real home directory** — tests cannot clobber your login.\n\nSet `ARCHAL_HOME` explicitly to opt out of the sandbox and point the credential store at a specific directory.\n\n## Environment\n\n- `ARCHAL_VITEST_TOKEN` or `ARCHAL_TOKEN`\n- `ARCHAL_HOME` — explicit credential directory (skips test sandbox)\n- `ARCHAL_VITEST_API_URL` — override hosted API endpoint\n- `ARCHAL_VITEST_SESSION_READY_TIMEOUT_MS` — override 5min default ready timeout\n\n## Packaging Status\n\nThe published artifact bundles its internal Archal runtime and auth helpers, so consumers do not need the Archal monorepo to install or use it.\n","readmeFilename":"README.md"}