{"_id":"@codasignal/routo","_rev":"5-d76fc05f92324bdd4194ae3e882418a0","name":"@codasignal/routo","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.1":{"name":"@codasignal/routo","version":"0.1.1","license":"MIT","_id":"@codasignal/routo@0.1.1","maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"homepage":"https://github.com/CodaSignal/routo.io#readme","bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"dist":{"shasum":"7b66f5a59c82d15aea6173084287b7f45146bd17","tarball":"https://registry.npmjs.org/@codasignal/routo/-/routo-0.1.1.tgz","fileCount":5,"integrity":"sha512-yW0SQseJqGqr6V/ylJ5oU6T0uvLF38tL3hmSp9AmYxOKwCkVrBPhTOzUpsx+dNfTmhpXw0+RZzRiZ4Ye/ERqWg==","signatures":[{"sig":"MEYCIQD+F+/NG5c1fVDYfpSL7OlMbwYwFZ7qrEE5jKKpdX1WoQIhANZMw574TuhZGxioSHAJxuJXqZC/XIYJpYTOa4x5fNJO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15959},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","test:watch":"vitest","check-types":"tsc --noEmit"},"_npmUser":{"name":"falconiererb","email":"hello@codasignal.com"},"repository":{"url":"git+https://github.com/CodaSignal/routo.io.git","type":"git","directory":"packages/sdk"},"_npmVersion":"10.8.2","description":"TypeScript SDK for the Routo link management API","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^3.1.1","typescript":"^5.9.2"},"_npmOperationalInternal":{"tmp":"tmp/routo_0.1.1_1776968248932_0.14789474227085764","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@codasignal/routo","version":"0.1.2","keywords":["api","deep-links","link-management","routo","sdk"],"license":"MIT","_id":"@codasignal/routo@0.1.2","maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"homepage":"https://routo.io","bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"dist":{"shasum":"ee5de0df2fbee870d4c8d9b9cda3bfd2cb4a3445","tarball":"https://registry.npmjs.org/@codasignal/routo/-/routo-0.1.2.tgz","fileCount":6,"integrity":"sha512-pehdWKwR7f0wamIbYuNngknZDzNpX35uRGA8g6jMZrznFmK4adMuQbVOANXeBnDNcnwscAyWMXNF/prFzjmDYw==","signatures":[{"sig":"MEUCIQCUQCv7WO2a0BUQzKonJURIT4kYAoYltKngsqtmulgRrwIgbu5dj4nLH285fguDd4yvZo5bVS4lBIRRDVHcFfFQ7lA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":18173},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","test:watch":"vitest","check-types":"tsc --noEmit"},"_npmUser":{"name":"falconiererb","email":"hello@codasignal.com"},"repository":{"url":"git+https://github.com/CodaSignal/routo.io.git","type":"git","directory":"packages/sdk"},"_npmVersion":"10.8.2","description":"TypeScript SDK for the Routo link management API","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^3.1.1","typescript":"^5.9.2"},"_npmOperationalInternal":{"tmp":"tmp/routo_0.1.2_1776968507184_0.8772597257631856","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@codasignal/routo","version":"0.2.0","keywords":["api","deep-links","link-management","routo","sdk"],"license":"MIT","_id":"@codasignal/routo@0.2.0","maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"homepage":"https://routo.io","bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"dist":{"shasum":"6fe336cf8d99b744559ce37415e643733553747f","tarball":"https://registry.npmjs.org/@codasignal/routo/-/routo-0.2.0.tgz","fileCount":6,"integrity":"sha512-D0n1n8pG/6Z8qEoc102T11CEbFXnKA6k4fMcsVAMHYrLdgpf/GaOeOMHCkMLmAymKnQ10RnW3fzUq9iMz3D/+A==","signatures":[{"sig":"MEUCIQDbt+CkRXUenetqo3RAqOmmnuAygR42mpP/EJsvGtKrvgIgbUK5933VdT6BzKo4PF5J5OnQ10+v97GLa4UZoKvv6xw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79439},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","test:watch":"vitest","check-types":"tsc --noEmit"},"_npmUser":{"name":"falconiererb","email":"hello@codasignal.com"},"repository":{"url":"git+https://github.com/CodaSignal/routo.io.git","type":"git","directory":"packages/sdk"},"_npmVersion":"10.8.2","description":"TypeScript SDK for the Routo link management API","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^3.1.1","typescript":"^5.9.2"},"_npmOperationalInternal":{"tmp":"tmp/routo_0.2.0_1778879994700_0.5660167917060532","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@codasignal/routo","version":"0.3.0","keywords":["api","deep-links","link-management","routo","sdk"],"license":"Apache-2.0","_id":"@codasignal/routo@0.3.0","maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"homepage":"https://routo.io","bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"dist":{"shasum":"f80222ae7d89cc4a28a70a385c5281b4167ed456","tarball":"https://registry.npmjs.org/@codasignal/routo/-/routo-0.3.0.tgz","fileCount":6,"integrity":"sha512-AOnrQInUuFloZa5lwAsjqfyVVLCikSnxb2WG2N/XtnmEKV9QRt5NDAxJdu9xw0Zzv+TkHsn2CxmQDKQMOs7AVQ==","signatures":[{"sig":"MEYCIQCCvy8dMbRtvffNUZe30bd8KFvCxkClad+FFtCF90d3VAIhAMAiqoWsYcc5gzOVv0Faxujl6ojrCrCk3emDy9j4XYsU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88812},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","test:watch":"vitest","check-types":"tsc --noEmit"},"_npmUser":{"name":"falconiererb","email":"hello@codasignal.com"},"repository":{"url":"git+https://github.com/CodaSignal/routo.io.git","type":"git","directory":"packages/sdk"},"_npmVersion":"10.8.2","description":"TypeScript SDK for the Routo link management API","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^3.1.1","typescript":"^5.9.2"},"_npmOperationalInternal":{"tmp":"tmp/routo_0.3.0_1786511853109_0.450678213598531","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@codasignal/routo","version":"1.0.0","description":"TypeScript SDK for the Routo link management API","keywords":["api","deep-links","link-management","routo","sdk"],"homepage":"https://routo.io","license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/CodaSignal/routo.io.git","directory":"packages/sdk"},"type":"module","sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./package.json":"./package.json"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","check-types":"tsc --noEmit"},"devDependencies":{"tsup":"^8.0.0","typescript":"^5.9.2","vitest":"^3.1.1"},"engines":{"node":">=20"},"gitHead":"7d9b5fbafbddd04a9863beac622016bd6c9fb66a","_id":"@codasignal/routo@1.0.0","bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-EoKaMV7EEPGx1GKRaUmrblgnkx6AV++7/cL+IVOgfzJbyEmEaFRo9Z9MiahShhB+SI+rz8CaeE3G/seMo7nSIA==","shasum":"bd63ee4c514a9e0749fb01eb05a199506ad1f1f0","tarball":"https://registry.npmjs.org/@codasignal/routo/-/routo-1.0.0.tgz","fileCount":9,"unpackedSize":383804,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDNAxmWie5Bc9S1Gh9/Xrc+/gmEIR+lHIH+ZkQZm1hVoAIhAJJ21xO5qxgxuROZjOs1jYJAj4ORUvkukFq2HEHd/QXP"}]},"_npmUser":{"name":"falconiererb","email":"hello@codasignal.com"},"directories":{},"maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/routo_1.0.0_1787038192224_0.7403787428892195"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-23T18:17:28.819Z","modified":"2026-08-18T07:29:52.534Z","0.1.1":"2026-04-23T18:17:29.085Z","0.1.2":"2026-04-23T18:21:47.332Z","0.2.0":"2026-05-15T21:19:54.858Z","0.3.0":"2026-08-12T05:17:33.257Z","1.0.0":"2026-08-18T07:29:52.346Z"},"bugs":{"url":"https://github.com/CodaSignal/routo.io/issues"},"license":"Apache-2.0","homepage":"https://routo.io","keywords":["api","deep-links","link-management","routo","sdk"],"repository":{"type":"git","url":"git+https://github.com/CodaSignal/routo.io.git","directory":"packages/sdk"},"description":"TypeScript SDK for the Routo link management API","maintainers":[{"name":"falconiererb","email":"hello@codasignal.com"}],"readme":"# @codasignal/routo\n\nTypeScript SDK for the [Routo](https://routo.io) link management API.\n\nEvery request shape, response type, and resource method in this package is **generated from the API's\nown router**. They cannot describe an endpoint the API does not have.\n\n## Install\n\n```bash\nnpm install @codasignal/routo\n# or\nbun add @codasignal/routo\n```\n\nRequires Node ≥20, or any modern browser/Cloudflare Workers/Bun/Deno runtime that ships `fetch`.\n\n## Quickstart\n\n```typescript\nimport { Routo } from \"@codasignal/routo\";\n\nconst routo = new Routo(process.env.ROUTO_API_KEY!);\n\nconst link = await routo.links.create({\n  url: \"https://example.com/products/42\",\n  projectId: \"proj_abc\",\n});\n\nconsole.log(link.id, link.path);\n```\n\nThat is the whole minimum. `path` is minted for you, `name` defaults to the destination's host, and a\nlink with no platform configuration resolves to `url` on iOS, Android, and web alike — you never have\nto describe both platforms to create one.\n\nIn Node, `new Routo()` with no arguments reads `ROUTO_API_KEY` from `process.env`.\n\n## Resources\n\n| Resource         | Methods                                                              |\n| ---------------- | -------------------------------------------------------------------- |\n| `links`          | `create`, `createDynalinks`, `list`, `update`, `delete`               |\n| `links.variants` | `create`, `list`, `update`, `delete`                                  |\n| `analytics`      | `get`, `aggregate`, `aggregateUnique`, `breakdown`, `variantPerformance` |\n| `console`        | `get`                                                                 |\n| `customDomains`  | `create`, `list`, `get`, `update`, `delete`, `verify`                 |\n| `projectApps`    | `create`, `list`, `listByProject`, `update`, `delete`                 |\n| `projects`       | `list`, `get`                                                         |\n| `organizations`  | `list`, `current`                                                     |\n| `auth`           | `me`                                                                  |\n\nA test asserts this table matches the generated client, so it cannot fall behind the API.\n\nPath parameters are positional; everything else travels in one object:\n\n```typescript\nawait routo.links.update(linkId, { url: \"https://example.com/new\", projectId });\nawait routo.links.variants.create(linkId, { name: \"B\", url: \"https://example.com/b\", weight: 50 });\nawait routo.customDomains.verify(domainId);\n```\n\n## Listing\n\n`list` returns a plain array for exactly the page you ask for. `limit` and `offset` are both\n**required**: the API caps `limit` at 100 and returns no total, so an omitted `limit` would silently\nhand you 50 rows that look like the whole set.\n\n```typescript\nconst page = await routo.links.list({ projectId: \"p1\", limit: 100, offset: 0 });\n\n// Walk everything explicitly.\nfor (let offset = 0; ; offset += 100) {\n  const batch = await routo.links.list({ projectId: \"p1\", limit: 100, offset });\n  batch.forEach(process);\n  if (batch.length < 100) break;\n}\n```\n\n## Errors\n\n```typescript\nimport { RoutoValidationError, RoutoRateLimitError } from \"@codasignal/routo\";\n\ntry {\n  await routo.links.create({ url: \"\", projectId: \"\" });\n} catch (err) {\n  if (err instanceof RoutoValidationError) {\n    for (const fe of err.fieldErrors) console.error(`${fe.path}: ${fe.message}`);\n  } else if (err instanceof RoutoRateLimitError) {\n    console.error(`rate limited, retry in ${err.retryAfterMs}ms`);\n  } else {\n    throw err;\n  }\n}\n```\n\n| Class                  | Status   | Notes                                 |\n| ---------------------- | -------- | ------------------------------------- |\n| `RoutoValidationError` | 400      | exposes `fieldErrors[]`               |\n| `RoutoAuthError`       | 401, 403 | `code` is `unauthorized`/`forbidden`  |\n| `RoutoNotFoundError`   | 404      |                                       |\n| `RoutoRateLimitError`  | 429      | exposes `retryAfterMs`                |\n| `RoutoServerError`     | 5xx      | retryable                             |\n| `RoutoAbortError`      | n/a      | from caller-provided `signal`         |\n| `RoutoTimeoutError`    | n/a      | from `timeoutMs`                      |\n| `RoutoNetworkError`    | n/a      | wraps the underlying error in `cause` |\n\n## Retries and Idempotency\n\nNetwork failures, 408, 429, and 5xx responses are retried automatically up to `maxRetries`\n(default 2). For `POST` / `PATCH` requests the SDK generates an `Idempotency-Key` on the first attempt\nand reuses it across retries. You can pass your own:\n\n```typescript\nawait routo.links.create(params, { idempotencyKey: \"create-link-42\" });\n```\n\n## Observability\n\nLifecycle hooks are best-effort: a hook that throws is swallowed, so logging can never fail a request.\n\n```typescript\nconst routo = new Routo(apiKey, {\n  onRequest: ({ method, url }) => log.debug(`→ ${method} ${url}`),\n  onResponse: ({ status, durationMs }) => metrics.timing(\"routo.request\", durationMs, { status }),\n  onRetry: ({ attempt, delayMs, error }) => log.warn(`retry ${attempt} in ${delayMs}ms`, error),\n});\n```\n\n## AbortSignal & Timeouts\n\n```typescript\nconst ctrl = new AbortController();\nsetTimeout(() => ctrl.abort(), 5_000);\nawait routo.links.list({ projectId: \"p1\", limit: 50, offset: 0 }, { signal: ctrl.signal });\n\n// per-call timeout\nawait routo.analytics.get(range, { timeoutMs: 5_000 });\n```\n\n## Edge runtime notes\n\nThe SDK is pure-fetch and ships a single ESM+CJS build. It runs unmodified in:\n\n- Cloudflare Workers (use `wrangler dev`)\n- Vercel Edge Functions\n- Bun / Deno\n- React Native (Hermes ≥0.74)\n\nNo Node-specific imports.\n\n## Examples\n\nSee `examples/` in the repository:\n\n- `node-quickstart.ts`\n- `cf-worker.ts`\n- `next-route-handler.ts`\n- `listing.ts`\n- `abort-and-timeout.ts`\n- `retry-and-idempotency.ts`\n\n## Migrating to 1.0\n\nSee `CHANGELOG.md`. The short version: resource methods take path parameters positionally, `list`\nreturns an array instead of a `Page`, and creating a link no longer requires `name`, `path`, or the\nthree nullable objects.\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}