inkan

@inkanjs/vite

Your inkan API inside the Vite dev server: one port, reloaded on every save.

Your inkan API inside the Vite dev server: the frontend and the API on one port, no proxy and no CORS, and the API reloaded on every save. Works for every Vite project: Vue, React, Svelte, Solid, plain TypeScript.

npm install @vxnsin/inkan
npm install -D @inkanjs/vite
// vite.config.ts
import {  } from "vite";
import  from "@inkanjs/vite";

export default ({
  : [({ : "src/server/app.ts" })], // prefix: "/api" by default
});

The app keeps its routes, and its docs, document and inspector, under the prefix:

// src/server/app.ts
import { ,  } from "@vxnsin/inkan";

const  = ().("/teas", () => listTeas());

export const  = ({ : "/api/docs", : "/api/openapi.json", : "/api/_inkan" })
  .("/api", );

.(); // for production; under Vite it stays quiet

npm run dev and the frontend calls fetch("/api/teas") on its own origin. Vite's start says where the rest is:

  ➜  Local:   http://localhost:5173/
  ➜  API docs:  http://localhost:5173/api/docs
  ➜  Inspector: http://localhost:5173/api/_inkan

Change anything the app imports and the next request runs on the new code. The app that is replaced gets its onClose hooks and the fresh one its onListen hooks, as with a restart, so a database pool or a timer does not pile up with every save. An app that does not load (a syntax error, a plugin that fails) shows in Vite's overlay in the browser, not only in the terminal.

vite preview

vite preview serves the API next to the built frontend, so the build is tried as a whole. Node loads the entry itself there, without Vite's module graph (TypeScript works, Node 22.18+ strips the types). For a server you build on its own, point preview at its output:

({ : "src/server/app.ts", : "dist-server/app.js" }); // or preview: false
optiondefault
entry"src/server/app.ts"the file that exports the app, export const app or export default
prefix"/api"the paths that belong to the API, one or a list
previewthe entrythe file vite preview loads, or false
bannertruethe docs and inspector links when Vite starts

In production the app runs as itself: app.listen(), app.fetch on Bun, Deno or serverless, or an adapter.

Pair it with the typed client and every call in the frontend is checked against the API by the compiler (it sees the routes of a chain and of mount):

import {  } from "@vxnsin/inkan/client";
import type {  } from "../server/app";

const  = <typeof >(.);

On this page