refactor(@omniroute/opencode-provider): rewrite for schema correctness + publishability

The 1.0.0 release of the package was broken end-to-end:

  1. index.js re-exported from "./index.ts" — Node can't import .ts at runtime,
     so any consumer who `npm install`ed the package got ERR_UNKNOWN_FILE_EXTENSION.
  2. The emitted provider shape did not match the OpenCode schema
     (https://opencode.ai/config.json). It used a custom `{id, name, npm, options, auth}`
     instead of the schema's `{npm: "@ai-sdk/openai-compatible", name, options, models}`.
  3. README told users to pass `baseURL: "http://localhost:20128/v1"` but the code
     appended `/v1` again — every request would 404 at `/v1/v1/...`.
  4. No build step, no LICENSE file, no repository/author/engines fields, no tests.

This rewrite:

- Moves source under `src/`, adds a tsup build emitting CJS + ESM + .d.ts.
- `createOmniRouteProvider` now returns a schema-valid entry with
  `npm: "@ai-sdk/openai-compatible"` + `models: Record<string, { name }>`.
- Adds `buildOmniRouteOpenCodeConfig` for full-document scaffolding.
- `normalizeBaseURL` deduplicates trailing `/` and `/v1`, accepts both forms,
  and rejects malformed URLs and empty inputs.
- 13 unit tests covering URL normalisation, input validation, default model
  catalog, custom models + labels, dedup/trim behaviour, and JSON round-trip.
- Adds LICENSE, full package.json (repository, engines, scripts, exports),
  .gitignore, .npmignore, tsconfig.json, and a comprehensive README.
- Resets version to 0.1.0 to signal the pre-1.0 reset (1.0.0 was never on npm).

Documentation:

- New `docs/frameworks/OPENCODE.md` covering both integration paths (CLI vs npm),
  URL normalisation, auth modes, troubleshooting, and runtime flow.
- README.md links the package and points to the new doc.
- CHANGELOG entry under Unreleased > Changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
diegosouzapw
2026-05-14 16:58:33 -03:00
parent d9b85704e4
commit 4b1e57443a
17 changed files with 2702 additions and 87 deletions

View File

@@ -0,0 +1,4 @@
node_modules
dist
*.log
.DS_Store

View File

@@ -0,0 +1,7 @@
src
tests
tsconfig.json
tsup.config.ts
node_modules
.DS_Store
*.log

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 OmniRoute contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,45 +1,138 @@
# @omniroute/opencode-provider
Provider plugin for connecting [OpenCode](https://github.com/anomalyco/opencode) to [OmniRoute](https://github.com/diegosouzapw/OmniRoute).
Helper for connecting [OpenCode](https://opencode.ai) to a running [OmniRoute](https://github.com/diegosouzapw/OmniRoute) AI gateway.
The package emits a **schema-valid entry** for `opencode.json` (`https://opencode.ai/config.json`) that delegates the actual runtime to [`@ai-sdk/openai-compatible`](https://www.npmjs.com/package/@ai-sdk/openai-compatible). It does not ship any new HTTP client — OmniRoute already exposes an OpenAI-compatible surface, and OpenCode already speaks it through the AI SDK.
> Pre-1.0. The API may still change. See `CHANGELOG` in the OmniRoute repo for breaking notes.
## Installation
```bash
npm install @omniroute/opencode-provider
npm install --save-dev @omniroute/opencode-provider
# or
pnpm add -D @omniroute/opencode-provider
```
## Usage
You also need OpenCode's own runtime dep, but that's a transitive concern — OpenCode itself ships with `@ai-sdk/openai-compatible`. This package only **generates configuration**.
```javascript
import { createOmniRouteProvider } from "@omniroute/opencode-provider";
## Quick start
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128/v1",
apiKey: "your-omniroute-api-key",
### 1. Scaffold a fresh `opencode.json`
```ts
import { writeFileSync } from "node:fs";
import { buildOmniRouteOpenCodeConfig } from "@omniroute/opencode-provider";
const config = buildOmniRouteOpenCodeConfig({
baseURL: "http://localhost:20128", // or your OmniRoute deployment URL
apiKey: process.env.OMNIROUTE_API_KEY ?? "sk_omniroute",
});
writeFileSync("opencode.json", JSON.stringify(config, null, 2));
```
Then configure OpenCode to use the provider:
The resulting `opencode.json`:
```jsonc
// OpenCode settings
{
"provider": provider
"$schema": "https://opencode.ai/config.json",
"provider": {
"omniroute": {
"npm": "@ai-sdk/openai-compatible",
"name": "OmniRoute",
"options": {
"baseURL": "http://localhost:20128/v1",
"apiKey": "sk_omniroute",
},
"models": {
"claude-opus-4-5-thinking": { "name": "claude-opus-4-5-thinking" },
"claude-sonnet-4-5-thinking": { "name": "claude-sonnet-4-5-thinking" },
"gemini-3.1-pro-high": { "name": "gemini-3.1-pro-high" },
"gemini-3-flash": { "name": "gemini-3-flash" },
},
},
},
}
```
### 2. Merge into an existing `opencode.json`
```ts
import { createOmniRouteProvider } from "@omniroute/opencode-provider";
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: process.env.OMNIROUTE_API_KEY!,
});
// Place `provider` under provider.omniroute in your opencode.json
```
If you already have an `opencode.json` on disk and want a non-destructive merge from the OmniRoute side, use `omniroute config opencode` from the CLI (ships with the main OmniRoute install) — it preserves comments and unrelated keys.
## API
### `createOmniRouteProvider(options)`
### `createOmniRouteProvider(options): OpenCodeProviderEntry`
Creates an OpenCode-compatible provider object that routes requests through OmniRoute.
Returns the value to place under `provider.omniroute` inside `opencode.json`.
**Options:**
| Option | Type | Required | Description |
| ------------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `baseURL` | `string` | Yes | OmniRoute base URL. Accepts `http://host:port` **or** `http://host:port/v1`. Trailing slashes are tolerated. |
| `apiKey` | `string` | Yes | OmniRoute API key. Use `sk_omniroute` for local installs that have `REQUIRE_API_KEY=false`. |
| `displayName` | `string` | No | Custom name shown in the OpenCode UI. Default: `"OmniRoute"`. |
| `models` | `string[]` | No | Override the surfaced model catalog. Default: 4 curated models — see `OMNIROUTE_DEFAULT_OPENCODE_MODELS`. |
| `modelLabels` | `Record<string,string>` | No | Human-readable labels keyed by model id. |
| Option | Type | Required | Description |
| --------- | -------- | -------- | ---------------------------------------------------------- |
| `baseURL` | `string` | Yes | OmniRoute API base URL (e.g., `http://localhost:20128/v1`) |
| `apiKey` | `string` | Yes | OmniRoute API key |
| `model` | `string` | No | Model identifier (default: `"opencode"`) |
Throws on empty/invalid input — `baseURL` must be a real URL, `apiKey` must be a non-empty string.
**Returns:** An OpenCode-compatible provider object with `id`, `name`, `npm`, `options`, and `auth` fields.
### `buildOmniRouteOpenCodeConfig(options): OpenCodeConfigDocument`
Same options as above, but returns a full document with `$schema` and the `provider.omniroute` wrapper, ready to write to `opencode.json`.
### `normalizeBaseURL(input): string`
Exported for completeness. Strips trailing `/`, deduplicates a trailing `/v1`, and re-appends exactly one `/v1`. Throws on empty / non-URL input.
### Constants
- `OMNIROUTE_PROVIDER_KEY``"omniroute"` (the key used under `provider.*`).
- `OMNIROUTE_PROVIDER_NPM``"@ai-sdk/openai-compatible"` (the runtime delegate).
- `OPENCODE_CONFIG_SCHEMA``"https://opencode.ai/config.json"`.
- `OMNIROUTE_DEFAULT_OPENCODE_MODELS` — readonly list of 4 default model ids.
## Custom model catalog
```ts
import { createOmniRouteProvider } from "@omniroute/opencode-provider";
createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
models: ["auto", "claude-opus-4-7", "gpt-5.5"],
modelLabels: {
auto: "Auto-Combo (recommended)",
"claude-opus-4-7": "Claude Opus 4.7",
"gpt-5.5": "GPT-5.5",
},
});
```
Duplicates and empty strings are dropped automatically, and order is preserved.
## Troubleshooting
- **Requests 404 with `/v1/v1/...`** — you're on an old version (≤1.0.0). Update to `≥0.1.0` of this re-released package. The new build normalises `baseURL` automatically.
- **`401 Invalid API key`** — your OmniRoute instance has `REQUIRE_API_KEY=true` but the key you supplied doesn't exist there. Create one via the dashboard or set `REQUIRE_API_KEY=false` and use `sk_omniroute`.
- **OpenCode complains the provider has no models** — supply an explicit `models` list; the default 4 may be hidden by your provider visibility settings.
## Related
- [OmniRoute](https://github.com/diegosouzapw/OmniRoute) — the AI gateway this plugin targets.
- [OpenCode](https://opencode.ai) — the agentic CLI consumer.
- [`@ai-sdk/openai-compatible`](https://www.npmjs.com/package/@ai-sdk/openai-compatible) — the runtime delegate that actually speaks HTTP.
## License
MIT — see [`LICENSE`](./LICENSE).

View File

@@ -1,3 +0,0 @@
import OmniRouteProvider from "./index.js";
export { OmniRouteProvider };
export default OmniRouteProvider;

View File

@@ -1 +0,0 @@
export { createOmniRouteProvider, default as default } from "./index.ts";

View File

@@ -1,54 +0,0 @@
/**
* OpenCode provider plugin for OmniRoute AI Gateway
*
* Usage:
* import { createOmniRouteProvider } from "@omniroute/opencode-provider";
* const provider = createOmniRouteProvider({
* baseURL: "http://localhost:20128/v1",
* apiKey: "your-api-key",
* });
*
* Then add to OpenCode settings:
* { "provider": provider }
*/
export interface OmniRouteProviderOptions {
baseURL: string;
apiKey: string;
model?: string;
}
export interface OmniRouteProvider {
id: string;
name: string;
npm: string;
options: Record<string, unknown>;
auth: { type: string; apiKey: string };
}
export function createOmniRouteProvider(options: OmniRouteProviderOptions): OmniRouteProvider {
if (!options.baseURL) {
throw new Error("baseURL is required");
}
if (!options.apiKey) {
throw new Error("apiKey is required");
}
const baseURL = options.baseURL.replace(/\/+$/, "");
return {
id: "omniroute",
name: "OmniRoute AI Gateway",
npm: "@omniroute/opencode-provider",
options: {
baseURL: `${baseURL}/v1`,
model: options.model || "opencode",
},
auth: {
type: "apiKey",
apiKey: options.apiKey,
},
};
}
export default createOmniRouteProvider;

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,59 @@
{
"name": "@omniroute/opencode-provider",
"version": "1.0.0",
"description": "OpenCode provider plugin for OmniRoute AI Gateway",
"version": "0.1.0",
"description": "OpenCode provider helper for the OmniRoute AI Gateway. Generates a schema-valid provider entry for opencode.json that delegates the runtime to @ai-sdk/openai-compatible.",
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"index.js",
"index.d.ts",
"README.md"
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsup",
"clean": "rm -rf dist",
"test": "node --import tsx/esm --test tests/**/*.test.ts",
"prepublishOnly": "npm run clean && npm run build && npm test"
},
"keywords": [
"omniroute",
"opencode",
"provider"
"opencode-ai",
"ai-sdk",
"openai-compatible",
"provider",
"ai-gateway",
"llm-router"
],
"author": "OmniRoute contributors",
"license": "MIT",
"peerDependencies": {}
"repository": {
"type": "git",
"url": "git+https://github.com/diegosouzapw/OmniRoute.git",
"directory": "@omniroute/opencode-provider"
},
"bugs": {
"url": "https://github.com/diegosouzapw/OmniRoute/issues"
},
"homepage": "https://github.com/diegosouzapw/OmniRoute/tree/main/%40omniroute/opencode-provider#readme",
"engines": {
"node": ">=20.20.2"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"tsup": "^8.5.0",
"tsx": "^4.20.0",
"typescript": "^5.9.0"
}
}

View File

@@ -0,0 +1,160 @@
/**
* OpenCode provider plugin for OmniRoute AI Gateway.
*
* Generates an OpenCode-compatible provider object that points to a running
* OmniRoute instance. The output follows the OpenCode config schema
* (https://opencode.ai/config.json) and delegates the runtime to
* `@ai-sdk/openai-compatible` so OpenCode can drive any OmniRoute-exposed
* model through its standard OpenAI-compatible client.
*
* Two ways to consume the helper:
*
* 1. As code, when you build your own opencode.json programmatically:
*
* ```ts
* import { buildOmniRouteOpenCodeConfig } from "@omniroute/opencode-provider";
* const config = buildOmniRouteOpenCodeConfig({
* baseURL: "http://localhost:20128",
* apiKey: "sk_omniroute",
* });
* // config -> { $schema, provider: { omniroute: { npm, name, options, models } } }
* ```
*
* 2. As a single-provider entry to merge into an existing opencode.json:
*
* ```ts
* import { createOmniRouteProvider } from "@omniroute/opencode-provider";
* const provider = createOmniRouteProvider({ baseURL, apiKey });
* // provider -> the value to place under provider.omniroute in opencode.json
* ```
*
* Note: `baseURL` accepts both `http://host:port` and `http://host:port/v1`.
* The helper normalises trailing slashes / `/v1` so you never get `/v1/v1`.
*/
export const OMNIROUTE_PROVIDER_KEY = "omniroute" as const;
export const OMNIROUTE_PROVIDER_NPM = "@ai-sdk/openai-compatible" as const;
export const OPENCODE_CONFIG_SCHEMA = "https://opencode.ai/config.json" as const;
/**
* Default catalog of models surfaced to OpenCode when the caller does not
* supply an explicit `models` list. Mirrors the curated set used by the
* OmniRoute dashboard's "OpenCode" config generator.
*/
export const OMNIROUTE_DEFAULT_OPENCODE_MODELS = [
"claude-opus-4-5-thinking",
"claude-sonnet-4-5-thinking",
"gemini-3.1-pro-high",
"gemini-3-flash",
] as const;
export interface OmniRouteProviderOptions {
/** OmniRoute base URL, with or without trailing `/v1`. Required. */
baseURL: string;
/** OmniRoute API key. Required. Use `sk_omniroute` for local instances without REQUIRE_API_KEY. */
apiKey: string;
/** Override the display name shown in OpenCode. Default: `"OmniRoute"`. */
displayName?: string;
/** Override the model catalog. Defaults to `OMNIROUTE_DEFAULT_OPENCODE_MODELS`. */
models?: readonly string[];
/** Optional human-readable labels keyed by model id. */
modelLabels?: Record<string, string>;
}
export interface OpenCodeProviderEntry {
/** Identifier of the OpenCode runtime package that will speak to OmniRoute. */
npm: typeof OMNIROUTE_PROVIDER_NPM;
/** Display name in the OpenCode UI. */
name: string;
/** Options forwarded to `@ai-sdk/openai-compatible`. */
options: {
baseURL: string;
apiKey: string;
};
/** Model catalog surfaced to OpenCode. */
models: Record<string, { name: string }>;
}
export interface OpenCodeConfigDocument {
$schema: typeof OPENCODE_CONFIG_SCHEMA;
provider: {
[OMNIROUTE_PROVIDER_KEY]: OpenCodeProviderEntry;
};
}
function requireNonEmpty(value: unknown, field: string): string {
if (typeof value !== "string") {
throw new TypeError(`@omniroute/opencode-provider: ${field} must be a string`);
}
const trimmed = value.trim();
if (!trimmed) {
throw new Error(`@omniroute/opencode-provider: ${field} is required and cannot be empty`);
}
return trimmed;
}
/**
* Normalise the user-supplied baseURL so the final `options.baseURL` always
* ends in exactly one `/v1`. Accepts both `http://host` and `http://host/v1`.
*/
export function normalizeBaseURL(rawBaseURL: string): string {
const trimmed = requireNonEmpty(rawBaseURL, "baseURL");
try {
// Reject malformed URLs early.
new URL(trimmed);
} catch {
throw new Error(
`@omniroute/opencode-provider: baseURL is not a valid URL: ${JSON.stringify(rawBaseURL)}`
);
}
return trimmed.replace(/\/+$/, "").replace(/\/v1$/, "") + "/v1";
}
/**
* Build the `provider.omniroute` entry for an OpenCode config document.
* The returned object is JSON-serialisable and safe to embed verbatim.
*/
export function createOmniRouteProvider(options: OmniRouteProviderOptions): OpenCodeProviderEntry {
const baseURL = normalizeBaseURL(options.baseURL);
const apiKey = requireNonEmpty(options.apiKey, "apiKey");
const modelList =
options.models && options.models.length > 0
? [...options.models]
: [...OMNIROUTE_DEFAULT_OPENCODE_MODELS];
const labels = options.modelLabels ?? {};
const models: Record<string, { name: string }> = {};
const seen = new Set<string>();
for (const raw of modelList) {
const id = typeof raw === "string" ? raw.trim() : "";
if (!id || seen.has(id)) continue;
seen.add(id);
const label = typeof labels[id] === "string" && labels[id].trim() ? labels[id].trim() : id;
models[id] = { name: label };
}
return {
npm: OMNIROUTE_PROVIDER_NPM,
name: options.displayName?.trim() || "OmniRoute",
options: { baseURL, apiKey },
models,
};
}
/**
* Build a full OpenCode config document (with `$schema` + `provider.omniroute`).
* Useful when scaffolding a fresh `opencode.json`.
*/
export function buildOmniRouteOpenCodeConfig(
options: OmniRouteProviderOptions
): OpenCodeConfigDocument {
return {
$schema: OPENCODE_CONFIG_SCHEMA,
provider: {
[OMNIROUTE_PROVIDER_KEY]: createOmniRouteProvider(options),
},
};
}
export default createOmniRouteProvider;

View File

@@ -0,0 +1,121 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
buildOmniRouteOpenCodeConfig,
createOmniRouteProvider,
normalizeBaseURL,
OMNIROUTE_DEFAULT_OPENCODE_MODELS,
OMNIROUTE_PROVIDER_NPM,
OPENCODE_CONFIG_SCHEMA,
} from "../src/index.ts";
test("normalizeBaseURL preserves a bare host:port", () => {
assert.equal(normalizeBaseURL("http://localhost:20128"), "http://localhost:20128/v1");
});
test("normalizeBaseURL strips trailing slashes", () => {
assert.equal(normalizeBaseURL("http://localhost:20128////"), "http://localhost:20128/v1");
});
test("normalizeBaseURL deduplicates an existing /v1 suffix", () => {
assert.equal(normalizeBaseURL("http://localhost:20128/v1"), "http://localhost:20128/v1");
assert.equal(normalizeBaseURL("http://localhost:20128/v1/"), "http://localhost:20128/v1");
});
test("normalizeBaseURL rejects empty input", () => {
assert.throws(() => normalizeBaseURL(" "), /baseURL is required/);
});
test("normalizeBaseURL rejects malformed URLs", () => {
assert.throws(() => normalizeBaseURL("not a url"), /not a valid URL/);
});
test("createOmniRouteProvider validates required fields", () => {
assert.throws(
() => createOmniRouteProvider({ baseURL: "", apiKey: "x" } as never),
/baseURL is required/
);
assert.throws(
() => createOmniRouteProvider({ baseURL: "http://x", apiKey: "" } as never),
/apiKey is required/
);
});
test("createOmniRouteProvider produces the OpenCode-compatible shape", () => {
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
});
assert.equal(provider.npm, OMNIROUTE_PROVIDER_NPM);
assert.equal(provider.name, "OmniRoute");
assert.equal(provider.options.baseURL, "http://localhost:20128/v1");
assert.equal(provider.options.apiKey, "sk_omniroute");
assert.equal(typeof provider.models, "object");
});
test("createOmniRouteProvider seeds the default model catalog", () => {
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
});
const modelIds = Object.keys(provider.models).sort();
const defaultIds = [...OMNIROUTE_DEFAULT_OPENCODE_MODELS].sort();
assert.deepEqual(modelIds, defaultIds);
for (const id of defaultIds) {
assert.equal(provider.models[id]?.name, id);
}
});
test("createOmniRouteProvider honours a custom models list and labels", () => {
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
models: ["auto", "claude-opus-4-7"],
modelLabels: { auto: "Auto-Combo", "claude-opus-4-7": "Opus 4.7" },
});
assert.deepEqual(Object.keys(provider.models), ["auto", "claude-opus-4-7"]);
assert.equal(provider.models.auto.name, "Auto-Combo");
assert.equal(provider.models["claude-opus-4-7"].name, "Opus 4.7");
});
test("createOmniRouteProvider deduplicates and trims model ids", () => {
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
models: [" auto ", "auto", "", "claude-opus-4-7"],
});
assert.deepEqual(Object.keys(provider.models), ["auto", "claude-opus-4-7"]);
});
test("createOmniRouteProvider honours displayName override", () => {
const provider = createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
displayName: "Local OmniRoute",
});
assert.equal(provider.name, "Local OmniRoute");
});
test("buildOmniRouteOpenCodeConfig wraps the provider with the OpenCode schema", () => {
const doc = buildOmniRouteOpenCodeConfig({
baseURL: "http://localhost:20128/v1",
apiKey: "sk_omniroute",
});
assert.equal(doc.$schema, OPENCODE_CONFIG_SCHEMA);
assert.equal(typeof doc.provider.omniroute, "object");
assert.equal(doc.provider.omniroute.options.baseURL, "http://localhost:20128/v1");
});
test("config document is JSON-serialisable", () => {
const doc = buildOmniRouteOpenCodeConfig({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
});
const round = JSON.parse(JSON.stringify(doc));
assert.deepEqual(round, doc);
});

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2022"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"isolatedModules": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": false,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*.ts"],
"exclude": ["dist", "node_modules", "tests"]
}

View File

@@ -0,0 +1,18 @@
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm", "cjs"],
dts: true,
clean: true,
sourcemap: false,
splitting: false,
treeshake: true,
target: "node20",
outDir: "dist",
minify: false,
});
// CJS consumers should prefer named imports (`require(pkg).createOmniRouteProvider`).
// The `default` export is also exposed for ESM ergonomics, which makes tsup warn
// about mixed exports — that's expected and harmless for this package.