summaryrefslogtreecommitdiffhomepage
path: root/js
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-05-18 22:30:41 -0400
committerDax Raad <[email protected]>2025-05-26 12:40:17 -0400
commit99af6146d5def31c59993636d60eb75a483a283b (patch)
treeeb57ed227c15cf9be54bc9f231c83895d812f881 /js
parent020e0ca039287b73fa33041fbd1bb214e6ccb396 (diff)
downloadopencode-99af6146d5def31c59993636d60eb75a483a283b.tar.gz
opencode-99af6146d5def31c59993636d60eb75a483a283b.zip
openapi
Diffstat (limited to 'js')
-rw-r--r--js/bun.lock31
-rw-r--r--js/openapi.json90
-rw-r--r--js/package.json5
-rw-r--r--js/src/app/config.ts2
-rw-r--r--js/src/bus/index.ts2
-rw-r--r--js/src/id/id.ts2
-rw-r--r--js/src/index.ts35
-rw-r--r--js/src/server/server.ts60
-rw-r--r--js/src/session/session.ts22
-rw-r--r--js/src/storage/storage.ts2
10 files changed, 220 insertions, 31 deletions
diff --git a/js/bun.lock b/js/bun.lock
index ba45595a4..e6d8f9074 100644
--- a/js/bun.lock
+++ b/js/bun.lock
@@ -9,8 +9,11 @@
"@flystorage/local-fs": "^1.1.0",
"@hono/zod-validator": "^0.5.0",
"ai": "^5.0.0-alpha.2",
+ "clipanion": "^4.0.0-rc.4",
"hono": "^4.7.10",
- "zod": "^3.25.0-beta.20250518T002810",
+ "hono-openapi": "^0.4.8",
+ "zod": "^3.24.4",
+ "zod-openapi": "^4.2.4",
},
"devDependencies": {
"@tsconfig/bun": "^1.0.7",
@@ -34,6 +37,8 @@
"@alcalzone/ansi-tokenize": ["@alcalzone/[email protected]", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw=="],
+ "@apidevtools/json-schema-ref-parser": ["@apidevtools/[email protected]", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ=="],
+
"@flystorage/dynamic-import": ["@flystorage/[email protected]", "", {}, "sha512-CIbIUrBdaPFyKnkVBaqzksvzNtsMSXITR/G/6zlil3MBnPFq2LX+X4Mv5p2XOmv/3OulFs/ff2SNb+5dc2Twtg=="],
"@flystorage/file-storage": ["@flystorage/[email protected]", "", {}, "sha512-25Gd5EsXDmhHrK5orpRuVqebQms1Cm9m5ACMZ0sVDX+Sbl1V0G88CbcWt7mEoWRYLvQ1U072htqg6Sav76ZlVA=="],
@@ -42,6 +47,8 @@
"@hono/zod-validator": ["@hono/[email protected]", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-ds5bW6DCgAnNHP33E3ieSbaZFd5dkV52ZjyaXtGoR06APFrCtzAsKZxTHwOrJNBdXsi0e5wNwo5L4nVEVnJUdg=="],
+ "@jsdevtools/ono": ["@jsdevtools/[email protected]", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="],
+
"@opentelemetry/api": ["@opentelemetry/[email protected]", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@standard-schema/spec": ["@standard-schema/[email protected]", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
@@ -54,6 +61,8 @@
"@types/bun": ["@types/[email protected]", "", { "dependencies": { "bun-types": "1.2.13" } }, "sha512-u6vXep/i9VBxoJl3GjZsl/BFIsvML8DfVDO0RYLEwtSZSp981kEO1V5NwRcO1CPJ7AmvpbnDCiMKo3JvbDEjAg=="],
+ "@types/json-schema": ["@types/[email protected]", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
+
"@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="],
"@types/prop-types": ["@types/[email protected]", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="],
@@ -68,6 +77,8 @@
"ansi-styles": ["[email protected]", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
+ "argparse": ["[email protected]", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+
"auto-bind": ["[email protected]", "", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="],
"bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-rRjA1T6n7wto4gxhAO/ErZEtOXyEZEmnIHQfl0Dt1QQSB4QV0iP6BZ9/YB5fZaHFQ2dwHFrmPaRQ9GGMX01k9Q=="],
@@ -80,6 +91,10 @@
"cli-truncate": ["[email protected]", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
+ "clipanion": ["[email protected]", "", { "dependencies": { "typanion": "^3.8.0" } }, "sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q=="],
+
+ "clone": ["[email protected]", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
+
"code-excerpt": ["[email protected]", "", { "dependencies": { "convert-to-spaces": "^2.0.1" } }, "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA=="],
"convert-to-spaces": ["[email protected]", "", {}, "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ=="],
@@ -104,6 +119,8 @@
"hono": ["[email protected]", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="],
+ "hono-openapi": ["[email protected]", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA=="],
+
"ieee754": ["[email protected]", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"indent-string": ["[email protected]", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
@@ -118,8 +135,12 @@
"js-tokens": ["[email protected]", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
+ "js-yaml": ["[email protected]", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
+
"json-schema": ["[email protected]", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
+ "json-schema-walker": ["[email protected]", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.1.0", "clone": "^2.1.2" } }, "sha512-nXN2cMky0Iw7Af28w061hmxaPDaML5/bQD9nwm1lOoIKEGjHcRGxqWe4MfrkYThYAPjSUhmsp4bJNoLAyVn9Xw=="],
+
"loose-envify": ["[email protected]", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"mime-db": ["[email protected]", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
@@ -132,6 +153,8 @@
"onetime": ["[email protected]", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
+ "openapi-types": ["[email protected]", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
+
"patch-console": ["[email protected]", "", {}, "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA=="],
"peek-readable": ["[email protected]", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
@@ -158,6 +181,8 @@
"token-types": ["[email protected]", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="],
+ "typanion": ["[email protected]", "", {}, "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug=="],
+
"type-fest": ["[email protected]", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
@@ -174,7 +199,9 @@
"yoga-layout": ["[email protected]", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="],
- "zod": ["[email protected]", "", {}, "sha512-3/aIqMbUXG9EjTelJkDcWd+izJP5MxFgQEMSYI8n41pwYhRDYYxy2dnbkgfNcnLbFZ9uByZn9XXqHTh05QHqSQ=="],
+ "zod": ["[email protected]", "", {}, "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg=="],
+
+ "zod-openapi": ["[email protected]", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-tsrQpbpqFCXqVXUzi3TPwFhuMtLN3oNZobOtYnK6/5VkXsNdnIgyNr4r8no4wmYluaxzN3F7iS+8xCW8BmMQ8g=="],
"zod-to-json-schema": ["[email protected]", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
diff --git a/js/openapi.json b/js/openapi.json
new file mode 100644
index 000000000..8dbe78550
--- /dev/null
+++ b/js/openapi.json
@@ -0,0 +1,90 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "opencode",
+ "description": "opencode api",
+ "version": "1.0.0"
+ },
+ "paths": {
+ "/session_create": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successfully created session",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ "title": {
+ "type": "string"
+ },
+ "tokens": {
+ "type": "object",
+ "properties": {
+ "input": {
+ "type": "number"
+ },
+ "output": {
+ "type": "number"
+ },
+ "reasoning": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "input",
+ "output",
+ "reasoning"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "title",
+ "tokens"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "operationId": "postSession_create",
+ "parameters": [],
+ "description": "Create a new session"
+ }
+ },
+ "/session_chat": {
+ "post": {
+ "responses": {},
+ "operationId": "postSession_chat",
+ "parameters": [],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string"
+ },
+ "parts": {}
+ },
+ "required": [
+ "sessionID"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {}
+ }
+} \ No newline at end of file
diff --git a/js/package.json b/js/package.json
index 03b9ad035..63429b846 100644
--- a/js/package.json
+++ b/js/package.json
@@ -19,7 +19,10 @@
"@flystorage/local-fs": "^1.1.0",
"@hono/zod-validator": "^0.5.0",
"ai": "^5.0.0-alpha.2",
+ "clipanion": "^4.0.0-rc.4",
"hono": "^4.7.10",
- "zod": "^3.25.0-beta.20250518T002810"
+ "hono-openapi": "^0.4.8",
+ "zod": "^3.24.4",
+ "zod-openapi": "^4.2.4"
}
}
diff --git a/js/src/app/config.ts b/js/src/app/config.ts
index 84960db61..947298c67 100644
--- a/js/src/app/config.ts
+++ b/js/src/app/config.ts
@@ -1,6 +1,6 @@
import path from "node:path";
import { Log } from "../util/log";
-import { z } from "zod/v4";
+import { z } from "zod";
export namespace Config {
const log = Log.create({ service: "config" });
diff --git a/js/src/bus/index.ts b/js/src/bus/index.ts
index 5359debd9..4f3b40041 100644
--- a/js/src/bus/index.ts
+++ b/js/src/bus/index.ts
@@ -1,4 +1,4 @@
-import type { z, ZodSchema } from "zod/v4";
+import type { z, ZodSchema } from "zod";
import { App } from "../app";
import { Log } from "../util/log";
diff --git a/js/src/id/id.ts b/js/src/id/id.ts
index 39ee5326f..96ea870a1 100644
--- a/js/src/id/id.ts
+++ b/js/src/id/id.ts
@@ -1,4 +1,4 @@
-import { z } from "zod/v4";
+import { z } from "zod";
import { randomBytes } from "crypto";
export namespace Identifier {
diff --git a/js/src/index.ts b/js/src/index.ts
index 8f98310be..10b3fef32 100644
--- a/js/src/index.ts
+++ b/js/src/index.ts
@@ -1,11 +1,34 @@
import { App } from "./app";
-import process from "node:process";
import { Server } from "./server/server";
+import { Cli, Command, runExit } from "clipanion";
-const app = await App.create({
- directory: process.cwd(),
+const cli = new Cli({
+ binaryLabel: `opencode`,
+ binaryName: `opencode`,
+ binaryVersion: `1.0.0`,
});
-App.provide(app, async () => {
- const server = Server.listen();
-});
+cli.register(
+ class Run extends Command {
+ async execute() {
+ const app = await App.create({
+ directory: process.cwd(),
+ });
+
+ await App.provide(app, async () => {
+ const server = Server.listen();
+ });
+ }
+ },
+);
+cli.register(
+ class OpenApi extends Command {
+ static paths = [["openapi"]];
+ async execute() {
+ const specs = await Server.openapi();
+ this.context.stdout.write(JSON.stringify(specs, null, 2));
+ }
+ },
+);
+const [_bun, _app, ...args] = process.argv;
+cli.runExit(args);
diff --git a/js/src/server/server.ts b/js/src/server/server.ts
index 7ed67057c..5d9333e45 100644
--- a/js/src/server/server.ts
+++ b/js/src/server/server.ts
@@ -1,10 +1,10 @@
import { Log } from "../util/log";
import { Bus } from "../bus";
-
+import { describeRoute, generateSpecs, openAPISpecs } from "hono-openapi";
import { Hono } from "hono";
import { streamSSE } from "hono/streaming";
import { Session } from "../session/session";
-import { zValidator } from "@hono/zod-validator";
+import { resolver, validator as zValidator } from "hono-openapi/zod";
import { z } from "zod";
export namespace Server {
@@ -14,7 +14,21 @@ export namespace Server {
export type App = ReturnType<typeof app>;
function app() {
- return new Hono()
+ const app = new Hono();
+
+ const result = app
+ .get(
+ "/openapi",
+ openAPISpecs(app, {
+ documentation: {
+ info: {
+ title: "opencode",
+ version: "1.0.0",
+ description: "opencode api",
+ },
+ },
+ }),
+ )
.get("/event", async (c) => {
log.info("event connected");
return streamSSE(c, async (stream) => {
@@ -32,10 +46,26 @@ export namespace Server {
});
});
})
- .post("/session_create", async (c) => {
- const session = await Session.create();
- return c.json(session);
- })
+ .post(
+ "/session_create",
+ describeRoute({
+ description: "Create a new session",
+ responses: {
+ 200: {
+ description: "Successfully created session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
+ },
+ },
+ },
+ }),
+ async (c) => {
+ const session = await Session.create();
+ return c.json(session);
+ },
+ )
.post(
"/session_chat",
zValidator(
@@ -51,6 +81,22 @@ export namespace Server {
return c.json(msg);
},
);
+
+ return result;
+ }
+
+ export async function openapi() {
+ const a = app();
+ const result = await generateSpecs(a, {
+ documentation: {
+ info: {
+ title: "opencode",
+ version: "1.0.0",
+ description: "opencode api",
+ },
+ },
+ });
+ return result;
}
export function listen() {
diff --git a/js/src/session/session.ts b/js/src/session/session.ts
index fb45f0e59..e86048b1c 100644
--- a/js/src/session/session.ts
+++ b/js/src/session/session.ts
@@ -1,5 +1,4 @@
import path from "path";
-import { z } from "zod/v3";
import { App } from "../app/";
import { Identifier } from "../id/id";
import { LLM } from "../llm/llm";
@@ -8,26 +7,27 @@ import { Log } from "../util/log";
import {
convertToModelMessages,
streamText,
- tool,
type TextUIPart,
type ToolInvocationUIPart,
type UIDataTypes,
type UIMessage,
type UIMessagePart,
} from "ai";
+import { z } from "zod";
export namespace Session {
const log = Log.create({ service: "session" });
- export interface Info {
- id: string;
- title: string;
- tokens: {
- input: number;
- output: number;
- reasoning: number;
- };
- }
+ export const Info = z.object({
+ id: Identifier.schema("session"),
+ title: z.string(),
+ tokens: z.object({
+ input: z.number(),
+ output: z.number(),
+ reasoning: z.number(),
+ }),
+ });
+ export type Info = z.output<typeof Info>;
export type Message = UIMessage<{ sessionID: string }>;
diff --git a/js/src/storage/storage.ts b/js/src/storage/storage.ts
index 50364beeb..c24666c9f 100644
--- a/js/src/storage/storage.ts
+++ b/js/src/storage/storage.ts
@@ -5,7 +5,7 @@ import { Log } from "../util/log";
import { App } from "../app";
import { AppPath } from "../app/path";
import { Bus } from "../bus";
-import z from "zod/v4";
+import z from "zod";
export namespace Storage {
const log = Log.create({ service: "storage" });