chore(deps): upgrade oRPC to v2 (2.0.0-beta.42)

- Pin all @orpc/* catalog entries to 2.0.0-beta.42; @sofa/api now depends on @orpc/openapi
- Contract routes move from .route() to .meta(openapi(...)); schemas gain meta ids so the
  OpenAPI document hoists them as named components; publicInfo overrides document-level security
- OpenAPI generator/handler use v2 APIs (converters, base, spec plugin option, OpenAPI 3.1.1 output)
- Add restoreRootFileType routing interceptor so root-level File inputs (avatar upload, backup
  restore) keep their MIME type under Bun.serve
- Web/native links use origin + path url; native error classification derives HTTP status from
  COMMON_ERROR_STATUS_MAP / MalformedResponseError since ORPCError.status is gone
- router-auth test reads v2 orderedMiddlewares; regenerated docs/public/openapi.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jakeandClaude Opus 5.5 committed 2026-10-05 23:08:12 -04:00
1 parent 8da4cbbe52
commit c51a668ace
22 files changed
+2880 -3971

No files matched your search

+17 -1
View File
@@ -1,4 +1,4 @@
import { ORPCError } from "@orpc/client";
import { MalformedResponseError, ORPCError } from "@orpc/client";
import { describe, expect, test, vi } from "vitest";
vi.mock("@sofa/i18n", () => ({
@@ -31,6 +31,22 @@ describe("error classification", () => {
expect(isClientError(new ORPCError("INTERNAL_SERVER_ERROR"))).toBe(false);
expect(isClientError(new Error("Network request failed"))).toBe(false);
});
const malformed = (status: number) =>
new ORPCError("MALFORMED_ORPC_RESPONSE", {
cause: new MalformedResponseError({ response: { status, headers: {}, body: undefined } }),
});
test("classifies non-oRPC responses by their HTTP status", () => {
expect(isUnauthorizedError(malformed(401))).toBe(true);
expect(isClientError(malformed(404))).toBe(true);
expect(isClientError(malformed(502))).toBe(false);
});
test("unknown error codes are not client errors", () => {
expect(isClientError(new ORPCError("NOT_FOUND"))).toBe(true);
expect(isClientError(new ORPCError("SOMETHING_CUSTOM"))).toBe(false);
});
});
describe("getErrorMessage", () => {
+16 -3
View File
@@ -1,13 +1,26 @@
import { ORPCError } from "@orpc/client";
import { COMMON_ERROR_STATUS_MAP, MalformedResponseError, ORPCError } from "@orpc/client";
export { getAppErrorCode, getAuthErrorMessage, getErrorMessage } from "@sofa/i18n/errors";
/**
* HTTP status behind an oRPC error. oRPC v2 errors carry no `status`: well-formed errors map their
* code through oRPC's standard table, and non-oRPC responses (a proxy's 401, or an older Sofa
* server whose error format differs) surface as `MALFORMED_ORPC_RESPONSE` with the raw response
* on `cause`.
*/
function getErrorStatus(error: ORPCError<string, unknown>): number | undefined {
if (error.cause instanceof MalformedResponseError) return error.cause.response.status;
return (COMMON_ERROR_STATUS_MAP as Record<string, number | undefined>)[error.code];
}
/** True when an oRPC call failed because the server no longer accepts the session. */
export function isUnauthorizedError(error: unknown): boolean {
return error instanceof ORPCError && (error.code === "UNAUTHORIZED" || error.status === 401);
return error instanceof ORPCError && getErrorStatus(error) === 401;
}
/** True for 4xx oRPC errors — retrying them can't succeed. */
export function isClientError(error: unknown): boolean {
return error instanceof ORPCError && error.status >= 400 && error.status < 500;
if (!(error instanceof ORPCError)) return false;
const status = getErrorStatus(error);
return status !== undefined && status >= 400 && status < 500;
}
+6 -4
View File
@@ -1,13 +1,15 @@
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/fetch";
import type { ContractRouterClient } from "@orpc/contract";
import type { RouterContractClient } from "@orpc/contract";
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
import { authClient, getServerUrl, serverFetch } from "@/lib/server";
import type { contract } from "@sofa/api/contract";
export const link = new RPCLink({
url: () => `${getServerUrl()}/rpc`,
// The server URL may carry a path prefix (reverse proxy); the link concatenates origin + url.
origin: () => getServerUrl(),
url: "/rpc",
fetch: (url, options) =>
serverFetch(url, {
...options,
@@ -20,12 +22,12 @@ export const link = new RPCLink({
const headers = new Map<string, string>();
const cookies = await authClient.getCookie();
if (cookies) {
headers.set("Cookie", cookies);
headers.set("cookie", cookies);
}
return Object.fromEntries(headers);
},
});
export const client: ContractRouterClient<typeof contract> = createORPCClient(link);
export const client: RouterContractClient<typeof contract> = createORPCClient(link);
export const orpc = createTanstackQueryUtils(client);
+2
View File
@@ -3,11 +3,13 @@ import { RPCHandler } from "@orpc/server/fetch";
import { createLogger } from "@sofa/logger";
import { restoreRootFileType } from "./restore-file-type";
import { router } from "./router";
const log = createLogger("orpc");
export const handler = new RPCHandler(router, {
routingInterceptors: [restoreRootFileType()],
interceptors: [
onError((error) => {
log.error("oRPC error", error);
+33 -40
View File
@@ -1,47 +1,40 @@
import { oo } from "@orpc/openapi";
import { os as baseOs, ORPCError } from "@orpc/server";
import { auth } from "@sofa/auth/server";
const base = baseOs.$context<{ headers: Headers }>();
export const authed = oo.spec(
base.middleware(async ({ context, next }) => {
const sessionData = await auth.api.getSession({
headers: context.headers,
});
if (!sessionData?.session || !sessionData?.user) {
throw new ORPCError("UNAUTHORIZED");
}
return next({
context: {
user: sessionData.user,
session: sessionData.session,
},
});
}),
{ security: [{ session: [] }] },
);
export const authed = base.middleware(async ({ context, next }) => {
const sessionData = await auth.api.getSession({
headers: context.headers,
});
if (!sessionData?.session || !sessionData?.user) {
throw new ORPCError("UNAUTHORIZED");
}
return next({
context: {
user: sessionData.user,
session: sessionData.session,
},
});
});
export const admin = oo.spec(
base.middleware(async ({ context, next }) => {
const sessionData = await auth.api.getSession({
headers: context.headers,
// Bypass the 5-minute cookie cache so role changes take effect immediately.
query: { disableCookieCache: true },
});
if (!sessionData?.session || !sessionData?.user) {
throw new ORPCError("UNAUTHORIZED");
}
if (sessionData.user.role !== "admin") {
throw new ORPCError("FORBIDDEN");
}
return next({
context: {
user: sessionData.user,
session: sessionData.session,
},
});
}),
{ security: [{ session: [] }] },
);
export const admin = base.middleware(async ({ context, next }) => {
const sessionData = await auth.api.getSession({
headers: context.headers,
// Bypass the 5-minute cookie cache so role changes take effect immediately.
query: { disableCookieCache: true },
});
if (!sessionData?.session || !sessionData?.user) {
throw new ORPCError("UNAUTHORIZED");
}
if (sessionData.user.role !== "admin") {
throw new ORPCError("FORBIDDEN");
}
return next({
context: {
user: sessionData.user,
session: sessionData.session,
},
});
});
+13 -90
View File
@@ -1,15 +1,14 @@
import { SmartCoercionPlugin } from "@orpc/json-schema";
import { SmartCoercionHandlerPlugin } from "@orpc/json-schema";
import { OpenAPIHandler } from "@orpc/openapi/fetch";
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
import { OpenAPIReferenceHandlerPlugin } from "@orpc/openapi/plugins";
import { onError } from "@orpc/server";
import { createLogger } from "@sofa/logger";
import { generateOpenApiSpec, openApiTags, schemaConverters } from "./openapi-spec";
import { restoreRootFileType } from "./restore-file-type";
import { implementedRouter } from "./router";
const TRAILING_SLASH_RE = /\/$/;
const log = createLogger("openapi");
const isSecure = (process.env.BETTER_AUTH_URL ?? "").startsWith("https://");
@@ -17,99 +16,23 @@ const sessionCookieName = isSecure
? "__Secure-better-auth.session_token"
: "better-auth.session_token";
function escapeHtml(value: string): string {
return value
.replaceAll("&", "&amp;")
.replaceAll('"', "&quot;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
}
export const openApiHandler = new OpenAPIHandler(implementedRouter, {
plugins: [
new SmartCoercionPlugin({ schemaConverters }),
new OpenAPIReferencePlugin({
schemaConverters,
specGenerateOptions: {
info: {
new SmartCoercionHandlerPlugin({ converters: schemaConverters }),
new OpenAPIReferenceHandlerPlugin({
docsTitle: "Sofa API",
spec: () =>
generateOpenApiSpec({
title: "Sofa API",
version: process.env.APP_VERSION || "0.0.0",
},
servers: [{ url: "/api/v1" }],
tags: [...openApiTags],
components: {
securitySchemes: {
session: {
type: "apiKey",
name: sessionCookieName,
in: "cookie",
description: "Better Auth session cookie",
},
},
},
},
// Load the spec from /spec.json so the docs use the normalized document
// rather than the plugin's raw generator output.
renderDocsHtml: (specUrl, title, head, scriptUrl, config) => {
const scalarConfig = {
url: specUrl,
...(typeof config === "object" && config !== null ? config : {}),
};
return `
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>${escapeHtml(title)}</title>
${head}
</head>
<body>
<div id="app" data-config="${escapeHtml(JSON.stringify(scalarConfig))}"></div>
<script src="${escapeHtml(scriptUrl)}"></script>
<script>
Scalar.createApiReference('#app', JSON.parse(document.getElementById('app').dataset.config))
</script>
</body>
</html>
`;
},
servers: [{ url: "/api/v1" }],
sessionCookieName,
tags: [...openApiTags],
}),
}),
],
routingInterceptors: [restoreRootFileType()],
interceptors: [
async (options) => {
const requestPathname = options.request.url.pathname.replace(TRAILING_SLASH_RE, "") || "/";
const prefix = options.prefix?.replace(TRAILING_SLASH_RE, "") || "";
const specPath = `${prefix}/spec.json`.replace(TRAILING_SLASH_RE, "") || "/";
if (options.request.method !== "GET" || requestPathname !== specPath) {
return options.next();
}
const spec = await generateOpenApiSpec({
title: "Sofa API",
version: process.env.APP_VERSION || "0.0.0",
servers: [{ url: prefix || "/api/v1" }],
sessionCookieName,
tags: [...openApiTags],
});
return {
matched: true,
response: {
status: 200,
headers: {
"content-type": "application/json",
},
body: new File([JSON.stringify(spec)], "spec.json", {
type: "application/json",
}),
},
};
},
onError((error) => {
log.error("OpenAPI error", error);
}),
+32 -51
View File
@@ -1,21 +1,9 @@
import { OpenAPIGenerator, type OpenAPIGeneratorGenerateOptions } from "@orpc/openapi";
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
import {
BackupSchema,
CastMemberSchema,
EpisodeSchema,
IntegrationEventSchema,
IntegrationSchema,
JobSchema,
PersonCreditSchema,
PersonSchema,
RecommendationItemSchema,
ResolvedTitleSchema,
SeasonSchema,
SystemHealthSchema,
TmdbBrowseItem,
} from "@sofa/api/schemas";
OpenAPIGenerator,
type OpenAPIDocument,
type OpenAPIGeneratorGenerateOptions,
} from "@orpc/openapi";
import { ZodToJsonSchemaConverter } from "@orpc/zod";
import { implementedRouter } from "./router";
@@ -33,12 +21,16 @@ export const openApiTags = [
] as const;
const generator = new OpenAPIGenerator({
schemaConverters,
converters: schemaConverters,
});
const httpMethods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"] as const;
type OpenApiSpec = Awaited<ReturnType<OpenAPIGenerator["generate"]>>;
// oRPC v2 defaults to OpenAPI 3.2; keep emitting 3.1 like v1 did so the committed docs spec and
// its renderers (fumadocs-openapi, Scalar) see the same dialect.
const OPENAPI_VERSION = "3.1.1";
type OpenApiSpec = OpenAPIDocument<typeof OPENAPI_VERSION>;
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -173,13 +165,16 @@ export function normalizeOpenApiSpec<T extends OpenApiSpec>(spec: T): T {
}
}
// ResponsesObject allows `x-*` extension keys, so its values are typed loosely.
for (const response of Object.values(operation.responses ?? {})) {
if (!response || !("content" in response)) continue;
if (!isRecord(response) || !isRecord(response.content)) continue;
const nextContent = normalizeContent(response.content);
const nextContent = normalizeContent(
response.content as Record<string, { schema?: unknown }>,
);
if (nextContent) {
response.content = nextContent as typeof response.content;
response.content = nextContent;
} else {
delete response.content;
}
@@ -193,39 +188,25 @@ export function normalizeOpenApiSpec<T extends OpenApiSpec>(spec: T): T {
export async function generateOpenApiSpec(options: {
title: string;
version: string;
servers: OpenAPIGeneratorGenerateOptions["servers"];
servers: NonNullable<OpenAPIGeneratorGenerateOptions<typeof OPENAPI_VERSION>["base"]>["servers"];
sessionCookieName: string;
tags?: Array<{ name: string; description?: string }>;
}): Promise<OpenApiSpec> {
const spec = await generator.generate(implementedRouter, {
info: {
title: options.title,
version: options.version,
},
servers: options.servers,
tags: options.tags,
commonSchemas: {
Title: { schema: ResolvedTitleSchema },
Person: { schema: PersonSchema },
PersonCredit: { schema: PersonCreditSchema },
Episode: { schema: EpisodeSchema },
Season: { schema: SeasonSchema },
CastMember: { schema: CastMemberSchema },
BrowseItem: { schema: TmdbBrowseItem },
Recommendation: { schema: RecommendationItemSchema },
Integration: { schema: IntegrationSchema },
IntegrationEvent: { schema: IntegrationEventSchema },
Backup: { schema: BackupSchema },
Job: { schema: JobSchema },
SystemHealth: { schema: SystemHealthSchema },
},
components: {
securitySchemes: {
session: {
type: "apiKey",
name: options.sessionCookieName,
in: "cookie",
description: "Better Auth session cookie",
version: OPENAPI_VERSION,
base: {
info: { title: options.title, version: options.version },
servers: options.servers,
tags: options.tags,
security: [{ session: [] }],
components: {
securitySchemes: {
session: {
type: "apiKey",
name: options.sessionCookieName,
in: "cookie",
description: "Better Auth session cookie",
},
},
},
},
+31
View File
@@ -0,0 +1,31 @@
import type { Context } from "@orpc/server";
import type { StandardHandlerRoutingInterceptor } from "@orpc/server/standard";
/**
* Restores the MIME type of a procedure input that is a bare `File` (avatar upload, backup restore).
*
* oRPC v2 sends such an input as the raw request body and rebuilds the `File` from
* `request.blob()`, whose type Bun.serve always reports as `text/plain;charset=utf-8`. Without this,
* `z.file().mime([...])` rejects every upload. Files nested in an object arrive as multipart form
* data and keep their type, so only a root-level `File` body is re-typed.
*/
export function restoreRootFileType<T extends Context>(): StandardHandlerRoutingInterceptor<T> {
return (options) => {
const contentType = options.request.headers["content-type"];
if (typeof contentType !== "string") return options.next();
const resolveBody = options.request.resolveBody;
return options.next({
...options,
request: {
...options.request,
resolveBody: async (hint) => {
const body = await resolveBody(hint);
return body instanceof File && body.type !== contentType
? new File([body], body.name, { type: contentType, lastModified: body.lastModified })
: body;
},
},
});
};
}
@@ -0,0 +1,50 @@
import { describe, expect, test } from "vitest";
import { restoreRootFileType } from "../src/orpc/restore-file-type";
async function resolveThroughInterceptor(
headers: Record<string, string | undefined>,
body: unknown,
): Promise<unknown> {
let resolved: unknown;
await restoreRootFileType()({
request: { url: "/rpc/x", method: "POST", headers, resolveBody: async () => body },
next: async (options?: { request: { resolveBody: () => Promise<unknown> } }) => {
resolved = await (
options ?? { request: { resolveBody: async () => body } }
).request.resolveBody();
return { matched: false };
},
} as never);
return resolved;
}
describe("restoreRootFileType", () => {
test("re-types a root-level File from the Content-Type header", async () => {
const wrong = new File([new Uint8Array([1, 2, 3])], "a.png", {
type: "text/plain;charset=utf-8",
});
const result = await resolveThroughInterceptor({ "content-type": "image/png" }, wrong);
expect(result).toBeInstanceOf(File);
expect((result as File).type).toBe("image/png");
expect((result as File).name).toBe("a.png");
expect((result as File).size).toBe(3);
});
test("leaves non-File bodies untouched", async () => {
const json = { a: 1 };
expect(await resolveThroughInterceptor({ "content-type": "application/json" }, json)).toBe(
json,
);
});
test("leaves a File alone when the type already matches", async () => {
const file = new File(["x"], "a.png", { type: "image/png" });
expect(await resolveThroughInterceptor({ "content-type": "image/png" }, file)).toBe(file);
});
test("passes through when there is no Content-Type header", async () => {
const file = new File(["x"], "a.bin", { type: "" });
expect(await resolveThroughInterceptor({}, file)).toBe(file);
});
});
+8 -3
View File
@@ -1,4 +1,4 @@
import { isProcedure } from "@orpc/server";
import { Procedure } from "@orpc/server";
import { describe, expect, test } from "vitest";
import { admin, authed } from "../src/orpc/middleware";
@@ -11,8 +11,13 @@ function collectProcedures(
node: unknown,
path: string[] = [],
): { path: string; middlewares: readonly unknown[] }[] {
if (isProcedure(node)) {
return [{ path: path.join("."), middlewares: node["~orpc"].middlewares }];
if (node instanceof Procedure) {
return [
{
path: path.join("."),
middlewares: node["~orpc"].orderedMiddlewares.map((m) => m.middleware),
},
];
}
return Object.entries(node as Record<string, unknown>).flatMap(([key, child]) =>
collectProcedures(child, [...path, key]),
+5 -4
View File
@@ -1,7 +1,7 @@
import { msg } from "@lingui/core/macro";
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/fetch";
import type { ContractRouterClient } from "@orpc/contract";
import type { RouterContractClient } from "@orpc/contract";
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
import { QueryCache, QueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
@@ -30,10 +30,11 @@ export const queryClient = new QueryClient({
});
export const link = new RPCLink({
url: `${window.location.origin}/rpc`,
fetch: (input, init) => fetch(input, { ...init, credentials: "include" }),
// No `origin`: in the browser the link uses the current origin.
url: "/rpc",
fetch: (url, init) => fetch(url, { ...init, credentials: "include" }),
});
export const client: ContractRouterClient<typeof contract> = createORPCClient(link);
export const client: RouterContractClient<typeof contract> = createORPCClient(link);
export const orpc = createTanstackQueryUtils(client);
+1 -1
View File
@@ -15,7 +15,7 @@ export const Route = createFileRoute("/_app")({
let updateCheck = null;
if (session.user.role === "admin") {
try {
const settings = await client.admin.settings.get({});
const settings = await client.admin.settings.get();
updateCheck = settings.updateCheck;
} catch {
// Silently ignore — update check is non-critical
+1 -1
View File
@@ -5,7 +5,7 @@ import { client } from "@/lib/orpc/client";
export const Route = createFileRoute("/_auth/login")({
beforeLoad: async () => {
const publicInfo = await client.system.publicInfo({});
const publicInfo = await client.system.publicInfo();
if (publicInfo.userCount === 0) throw redirect({ to: "/register" });
return { publicInfo };
+1 -1
View File
@@ -7,7 +7,7 @@ import { client } from "@/lib/orpc/client";
export const Route = createFileRoute("/_auth/register")({
beforeLoad: async () => {
const publicInfo = await client.system.publicInfo({});
const publicInfo = await client.system.publicInfo();
return { publicInfo };
},
head: () => ({ meta: [{ title: "Create account — Sofa" }] }),
+1 -1
View File
@@ -8,7 +8,7 @@ export const Route = createFileRoute("/")({
beforeLoad: async () => {
const [{ data: session }, info] = await Promise.all([
authClient.getSession(),
client.system.publicInfo({}),
client.system.publicInfo(),
]);
if (session?.user) throw redirect({ to: "/dashboard" });
if (!info.tmdbConfigured) throw redirect({ to: "/setup" });
+1 -1
View File
@@ -28,7 +28,7 @@ const envSnippets = [
export const Route = createFileRoute("/setup")({
beforeLoad: async () => {
const info = await client.system.publicInfo({});
const info = await client.system.publicInfo();
if (info.tmdbConfigured) throw redirect({ to: "/" });
},
head: () => ({ meta: [{ title: "Setup — Sofa" }] }),
+36 -39
View File
@@ -211,6 +211,7 @@
"version": "0.2.0",
"dependencies": {
"@orpc/contract": "catalog:",
"@orpc/openapi": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
@@ -363,13 +364,13 @@
"@lingui/metro-transformer": "6.9.0",
"@lingui/react": "6.9.0",
"@lingui/vite-plugin": "6.9.0",
"@orpc/client": "1.15.4",
"@orpc/contract": "1.15.4",
"@orpc/json-schema": "1.15.4",
"@orpc/openapi": "1.15.4",
"@orpc/server": "1.15.4",
"@orpc/tanstack-query": "1.15.4",
"@orpc/zod": "1.15.4",
"@orpc/client": "2.0.0-beta.42",
"@orpc/contract": "2.0.0-beta.42",
"@orpc/json-schema": "2.0.0-beta.42",
"@orpc/openapi": "2.0.0-beta.42",
"@orpc/server": "2.0.0-beta.42",
"@orpc/tanstack-query": "2.0.0-beta.42",
"@orpc/zod": "2.0.0-beta.42",
"@tanstack/react-form": "1.33.5",
"@tanstack/react-query": "5.104.1",
"@types/bun": "1.4.2",
@@ -927,39 +928,27 @@
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@openapi-spec/downgrader": ["@openapi-spec/downgrader@0.3.0", "", { "dependencies": { "@openapi-spec/types": "^0.3.0" } }, "sha512-y4+CkV8chSbRKmR64+uGr0IjDjNUOQIdNMpCbSiD2JCc0a0HouUTXvgt+FO8/ktfaMaNz3ypqq4PmVfB3twx3w=="],
"@openapi-spec/types": ["@openapi-spec/types@0.3.0", "", {}, "sha512-r9Gufbaw9Cpb/rCiEsFdmdWdj41MzL4/y6dCJjwMQBUvQqj5X76WlbErDSwIHR3UsxCNQI2W20GsQ4eh3YXaMQ=="],
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
"@orpc/client": ["@orpc/client@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "@orpc/standard-server-fetch": "1.15.4", "@orpc/standard-server-peer": "1.15.4" } }, "sha512-8Iv2K8Rj8hf6xHCTxmQ+gxgiY6EATDossQk4gdt3oSbGVV0x2RSeLtRK9Zry+KVsmOqPJfnLahfRp7H2rQ/Vgg=="],
"@orpc/client": ["@orpc/client@2.0.0-beta.42", "", { "dependencies": { "@orpc/shared": "2.0.0-beta.42", "@standard-server/core": "~0.10.1", "@standard-server/fetch": "~0.10.1", "@standard-server/peer": "~0.10.1" } }, "sha512-5UVRiHw9UsOVsfK1EweJoOqDhnseIz1TG4U/pcGe/P6I/yBDafh+ijZ/ZaBrql2hC7PSgEwfCFljEG8IfxVGqA=="],
"@orpc/contract": ["@orpc/contract@1.15.4", "", { "dependencies": { "@orpc/client": "1.15.4", "@orpc/shared": "1.15.4", "@standard-schema/spec": "^1.1.0", "openapi-types": "^12.1.3" } }, "sha512-mxH+kuIsKz7BGsoqDHShnMjKG7GvCMGpvxTtJnkpbowIp2iBz8XiWosiWBybZcUl1Dy9W77TyOk6pNqG5I4D6w=="],
"@orpc/contract": ["@orpc/contract@2.0.0-beta.42", "", { "dependencies": { "@orpc/client": "2.0.0-beta.42", "@orpc/shared": "2.0.0-beta.42", "@standard-schema/spec": "^1.1.0" } }, "sha512-cLtAdjHGwGy2kNASBsdGKwlhFmRwqmlCOb9Avi6asFoV2fJH3Phht7QHa2/g61Yz1qF8IM6NgJ2+OA7iXRmU/g=="],
"@orpc/interop": ["@orpc/interop@1.15.4", "", {}, "sha512-ZCTNPenr1clZ2RBCJxsCsvS3eS8MJIDSx/LH1AIAKj9RjvfOXI/BnjHmgD4jUEIa6FcG+c2LV/1IXVJpC6NoTw=="],
"@orpc/json-schema": ["@orpc/json-schema@2.0.0-beta.42", "", { "dependencies": { "@openapi-spec/types": "~0.3.0", "@orpc/client": "2.0.0-beta.42", "@orpc/contract": "2.0.0-beta.42", "@orpc/server": "2.0.0-beta.42", "@orpc/shared": "2.0.0-beta.42", "@standard-schema/spec": "^1.1.0" } }, "sha512-iw/NsGLkTS3Blqb7TUzCSITaD6DMTuKIxMyoNT3TJBId3hC5JaEm4eiKktg4xA0zWn8NdUbOcsg+1E+l7b95fg=="],
"@orpc/json-schema": ["@orpc/json-schema@1.15.4", "", { "dependencies": { "@orpc/contract": "1.15.4", "@orpc/interop": "1.15.4", "@orpc/openapi": "1.15.4", "@orpc/server": "1.15.4", "@orpc/shared": "1.15.4", "json-schema-typed": "^8.0.2" } }, "sha512-UIPzRBWuSkWejOJwIAGFkW8H0iOvqobGJnVGRbpKOGAw1kiJW2EqHQ+2ZhE2o/cTi/A+HnQj0YG9tmrk5Vytnw=="],
"@orpc/openapi": ["@orpc/openapi@2.0.0-beta.42", "", { "dependencies": { "@openapi-spec/downgrader": "~0.3.0", "@openapi-spec/types": "~0.3.0", "@orpc/client": "2.0.0-beta.42", "@orpc/contract": "2.0.0-beta.42", "@orpc/json-schema": "2.0.0-beta.42", "@orpc/server": "2.0.0-beta.42", "@orpc/shared": "2.0.0-beta.42", "@standard-server/core": "~0.10.1", "@standard-server/fetch": "~0.10.1", "rou3": "^1.0.0" }, "peerDependencies": { "@scalar/api-reference": ">=1.57.2", "@types/swagger-ui": ">=5.32.0", "swagger-ui": ">=5.32.6" }, "optionalPeers": ["@scalar/api-reference", "@types/swagger-ui", "swagger-ui"] }, "sha512-u4DdwDVXvSQBDsA//IP6i+kHDUlu+6eNsI45+8YnXeGxm+4+/ePq24zZoOrZbafTM2pevXQO+aGD2wtFNdjK0w=="],
"@orpc/openapi": ["@orpc/openapi@1.15.4", "", { "dependencies": { "@orpc/client": "1.15.4", "@orpc/contract": "1.15.4", "@orpc/interop": "1.15.4", "@orpc/openapi-client": "1.15.4", "@orpc/server": "1.15.4", "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "json-schema-typed": "^8.0.2", "rou3": "^0.7.12" } }, "sha512-+J2skkYlqcB7O9nUJ9rhV1IvisimIwxyn21nAWP/jvSg5PN/klqSO2r6XkxiAaCukw/QE5BFMbN8c0ZdLrMEnw=="],
"@orpc/server": ["@orpc/server@2.0.0-beta.42", "", { "dependencies": { "@orpc/client": "2.0.0-beta.42", "@orpc/contract": "2.0.0-beta.42", "@orpc/shared": "2.0.0-beta.42", "@standard-server/aws-lambda": "~0.10.1", "@standard-server/core": "~0.10.1", "@standard-server/fastify": "~0.10.1", "@standard-server/fetch": "~0.10.1", "@standard-server/node": "~0.10.1", "@standard-server/peer": "~0.10.1", "cookie": "^2.0.1" }, "peerDependencies": { "crossws": ">=0.3.4", "fastify": ">=5.6.1" }, "optionalPeers": ["crossws", "fastify"] }, "sha512-gZXjfrKnYBNTgv70C3OB1ct04rbbMXOzX+sVx393YvcoEOjUr1cO8BwMBpIAQwaS42NKcoIjjo4zXF0dXOyb3Q=="],
"@orpc/openapi-client": ["@orpc/openapi-client@1.15.4", "", { "dependencies": { "@orpc/client": "1.15.4", "@orpc/contract": "1.15.4", "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4" } }, "sha512-z+8gRUp9bhVuA2tFlzJDCaUbLV/whZec25fmYb0VtP2N6iPfY0d7hYZvX47F/WrcuwaLCTqkbVAzK8Xb2cKF/w=="],
"@orpc/shared": ["@orpc/shared@2.0.0-beta.42", "", { "dependencies": { "@standard-server/shared": "~0.10.1", "radash": "^12.1.1", "type-fest": "^5.3.1" } }, "sha512-jPmLnx9ZD39bXOlbCTYdopz/xN9iqGVHZnlo3QDVruRLHN0dUDzcVyfJE38DaBCJs5A6tFYRJTG3BJlO5rM/kw=="],
"@orpc/server": ["@orpc/server@1.15.4", "", { "dependencies": { "@orpc/client": "1.15.4", "@orpc/contract": "1.15.4", "@orpc/interop": "1.15.4", "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "@orpc/standard-server-aws-lambda": "1.15.4", "@orpc/standard-server-fastify": "1.15.4", "@orpc/standard-server-fetch": "1.15.4", "@orpc/standard-server-node": "1.15.4", "@orpc/standard-server-peer": "1.15.4", "cookie": "^1.1.1" }, "peerDependencies": { "crossws": ">=0.3.4", "ws": ">=8.18.1" }, "optionalPeers": ["crossws", "ws"] }, "sha512-Ccs2Pdwql2XRtk7bzkiZohoYuUVNcffydbswhz75rdepCQt0HmKosfVhsqjAqCKDDB7c84ct7Q7c5Z/xQak7pQ=="],
"@orpc/tanstack-query": ["@orpc/tanstack-query@2.0.0-beta.42", "", { "dependencies": { "@orpc/client": "2.0.0-beta.42", "@orpc/contract": "2.0.0-beta.42", "@orpc/openapi": "2.0.0-beta.42", "@orpc/shared": "2.0.0-beta.42" }, "peerDependencies": { "@tanstack/query-core": ">=5.80.2" } }, "sha512-yLhmDw5Y5JR4mRrdq3J+vWnzF64g4eL63PqHDewvIPu240QQCxMeZLlKY1QPTdHZhE1ytwYnUu43Z+R2G8oCwQ=="],
"@orpc/shared": ["@orpc/shared@1.15.4", "", { "dependencies": { "radash": "^12.1.1", "type-fest": "^5.4.4" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-syNylxXmv1WnroSDUvtYjuvu0YMAYzkLTjFPa0CggnaF3DH2YmAnRS5GGGzSPRAbhMtRAXArIoM7GVrRNKHxng=="],
"@orpc/standard-server": ["@orpc/standard-server@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4" } }, "sha512-woaFpUJavYPiqRQ0Eh716jOHRZ7o84mPpmEPS79bBUJNDilGEj2OBSjbHV2ez4FYdVnEnlbg+rYy7sX3PwwENA=="],
"@orpc/standard-server-aws-lambda": ["@orpc/standard-server-aws-lambda@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "@orpc/standard-server-fetch": "1.15.4", "@orpc/standard-server-node": "1.15.4" } }, "sha512-Vq5nNhq/XSM3DPsI1MLEbMraP+++hb0btsS8IfdAj5eXTYvDzpTA5rZ+gMhhgnVuZvZcQbmBojTgtu41X8t4sA=="],
"@orpc/standard-server-fastify": ["@orpc/standard-server-fastify@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "@orpc/standard-server-node": "1.15.4" }, "peerDependencies": { "fastify": ">=5.6.1" }, "optionalPeers": ["fastify"] }, "sha512-OkBWAUQhtssTrfaV3FF8X/gdJL7otS1MvfTBuxKoRKpf6u7CQB9QpdY76OSg407N/hvN8wzSW2lSbhlKljOxkQ=="],
"@orpc/standard-server-fetch": ["@orpc/standard-server-fetch@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4" } }, "sha512-u6zQDx/tUgNUWDQstJMbWkCKsecp9j+4WHWoPmNNuk2PyRdD6FEmvJJs23CAKa5njKu2V8aMzuuL9AW3jechuw=="],
"@orpc/standard-server-node": ["@orpc/standard-server-node@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4", "@orpc/standard-server-fetch": "1.15.4" } }, "sha512-is6T03n1y6nx+g9ve0ip+F1BXbnR104r3NEGVUcGmkuLCqtxqbXCCjyzJTXWwGArTdEcxDOT4cW/zx/EORGN0g=="],
"@orpc/standard-server-peer": ["@orpc/standard-server-peer@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4", "@orpc/standard-server": "1.15.4" } }, "sha512-qWH7gf+8Iv2oXVIQZIQIvAyk2LYUHcj0CXF+AKF5WzHU22vJInD4FKbl8+UesVU+nT8O+BrVmOXzrQ40TqngpQ=="],
"@orpc/tanstack-query": ["@orpc/tanstack-query@1.15.4", "", { "dependencies": { "@orpc/shared": "1.15.4" }, "peerDependencies": { "@orpc/client": "1.15.4", "@tanstack/query-core": ">=5.80.2" } }, "sha512-oP4XuCI5AuelIhhv722sGXzZNYTH4Y6ueS4H4TtIICdG9Q6tJeiERqyEk0dm3ebh3yo+iM/NVmcRkpUrgzIZzw=="],
"@orpc/zod": ["@orpc/zod@1.15.4", "", { "dependencies": { "@orpc/json-schema": "1.15.4", "@orpc/openapi": "1.15.4", "@orpc/shared": "1.15.4", "escape-string-regexp": "^5.0.0", "wildcard-match": "^5.1.4" }, "peerDependencies": { "@orpc/contract": "1.15.4", "@orpc/server": "1.15.4", "zod": ">=3.25.0" } }, "sha512-k7W5yvagfcGztACr7qpB7Yyp3iMF9BzCJX9uDH9EEouuM2gt/WzsGtkDw//LTpPPsJQerltdKrdGfaWnbrGBhQ=="],
"@orpc/zod": ["@orpc/zod@2.0.0-beta.42", "", { "dependencies": { "@openapi-spec/types": "~0.3.0", "@orpc/json-schema": "2.0.0-beta.42" }, "peerDependencies": { "zod": ">=4.5.0" } }, "sha512-ajYbDjL0VavTSz1DGrJb/o1UrLiIvw3KGkIM45ZXKyX4bbpqnLYwurPfUA8DBP/C+UOliPqtt2x9Cf84nwA06g=="],
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.120.0", "", { "os": "android", "cpu": "arm" }, "sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg=="],
@@ -1303,6 +1292,20 @@
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@standard-server/aws-lambda": ["@standard-server/aws-lambda@0.10.1", "", { "dependencies": { "@standard-server/core": "0.10.1", "@standard-server/fetch": "0.10.1", "@standard-server/node": "0.10.1", "@standard-server/shared": "0.10.1" } }, "sha512-Rba4wyO9T0ta+Ze2Gu+c27vfzEjFKBqwUobtODvoo0ArZvcycY9Pr5Bf5iFcDX1NAWPFjnyEg5YQe2d+lJqu4g=="],
"@standard-server/core": ["@standard-server/core@0.10.1", "", { "dependencies": { "@standard-server/shared": "0.10.1" } }, "sha512-LtTjCg2x2FfbExGRdtu5J1biNVyNOfLs1/4zHAh/t0qZlbY+jIIbFYT5BPwbiYjF4o+Va5/JKjrA6uZeOQ184w=="],
"@standard-server/fastify": ["@standard-server/fastify@0.10.1", "", { "dependencies": { "@standard-server/core": "0.10.1", "@standard-server/node": "0.10.1" }, "peerDependencies": { "fastify": ">=5.6.1" }, "optionalPeers": ["fastify"] }, "sha512-8up+11uSaZRNlJ+ejyLPoxgAkftVeV1XCH+afmEbsaQ8YZlLGXQlf12mHFBoS+6Mr0NqtpYn4eBmC6yTnS7llw=="],
"@standard-server/fetch": ["@standard-server/fetch@0.10.1", "", { "dependencies": { "@standard-server/core": "0.10.1", "@standard-server/shared": "0.10.1" } }, "sha512-YK16ZUjJNRl7BZkqsA9dimTqNgjC/pfhXVcRcox22G1x4hrzTd993JLaQSduJ79g8hEyx0LuMCkjLavumwmonQ=="],
"@standard-server/node": ["@standard-server/node@0.10.1", "", { "dependencies": { "@standard-server/core": "0.10.1", "@standard-server/fetch": "0.10.1", "@standard-server/shared": "0.10.1" } }, "sha512-tVH85dY/qxflrqoGDXy/BiKmzw7w8ELif8yVbIx8XRGsc1qkTere51jsoJlx3tAQN/AC9SUoGjvgcVXVS6IwYw=="],
"@standard-server/peer": ["@standard-server/peer@0.10.1", "", { "dependencies": { "@standard-server/core": "0.10.1", "@standard-server/shared": "0.10.1" } }, "sha512-M1CXBNKMzCSTq33bNHxvUoGSwjjw6rqA+EJ1Cv6UJZSdAN9GoXQPVkmf1qmpPIDlc+0WhXHPoMbND1pqrblMog=="],
"@standard-server/shared": ["@standard-server/shared@0.10.1", "", {}, "sha512-8OhXcAY13iAtEzprBFDlfOvGVLCrNnf31oiPOJ/aZaR+i2BzT8U7qsUhYU5VPbD++KKfkzsJ7hN2kDlOxJ9C6w=="],
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
"@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="],
@@ -1757,7 +1760,7 @@
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
"cookie": ["cookie@2.0.1", "", {}, "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w=="],
"cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="],
@@ -2437,8 +2440,6 @@
"openapi-fetch": ["openapi-fetch@0.17.0", "", { "dependencies": { "openapi-typescript-helpers": "^0.1.0" } }, "sha512-PsbZR1wAPcG91eEthKhN+Zn92FMHxv+/faECIwjXdxfTODGSGegYv0sc1Olz+HYPvKOuoXfp+0pA2XVt2cI0Ig=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
"openapi-typescript-helpers": ["openapi-typescript-helpers@0.1.0", "", {}, "sha512-OKTGPthhivLw/fHz6c3OPtg72vi86qaMlqbJuVJ23qOvQ+53uw1n7HdmkJFibloF7QEjDrDkzJiOJuockM/ljw=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
@@ -2655,7 +2656,7 @@
"rolldown": ["rolldown@1.2.12", "", { "dependencies": { "@oxc-project/types": "=0.152.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.12", "@rolldown/binding-android-arm64": "1.2.12", "@rolldown/binding-darwin-arm64": "1.2.12", "@rolldown/binding-darwin-x64": "1.2.12", "@rolldown/binding-freebsd-x64": "1.2.12", "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", "@rolldown/binding-linux-arm64-gnu": "1.2.12", "@rolldown/binding-linux-arm64-musl": "1.2.12", "@rolldown/binding-linux-ppc64-gnu": "1.2.12", "@rolldown/binding-linux-s390x-gnu": "1.2.12", "@rolldown/binding-linux-x64-gnu": "1.2.12", "@rolldown/binding-linux-x64-musl": "1.2.12", "@rolldown/binding-openharmony-arm64": "1.2.12", "@rolldown/binding-win32-arm64-msvc": "1.2.12", "@rolldown/binding-win32-x64-msvc": "1.2.12" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ=="],
"rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="],
"rou3": ["rou3@1.0.0", "", {}, "sha512-ySeaQkSrua+ut9g+65I7FHqOFBaY8tV0FmccXItoq0q21se32Q3u4YiW7/RqXSosWgYJaaKwRHXy3BST9PeCNQ=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
@@ -2945,8 +2946,6 @@
"why-is-node-running": ["why-is-node-running@3.2.1", "", { "bin": { "why-is-node-running": "cli.js" } }, "sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ=="],
"wildcard-match": ["wildcard-match@5.1.4", "", {}, "sha512-wldeCaczs8XXq7hj+5d/F38JE2r7EXgb6WQDM84RVwxy81T/sxB5e9+uZLK9Q9oNz1mlvjut+QtvgaOQFPVq/g=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
@@ -3087,8 +3086,6 @@
"@modelcontextprotocol/sdk/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"@orpc/zod/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"@react-native/babel-preset/@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.86.0", "", { "dependencies": { "@babel/traverse": "^7.29.0", "@react-native/codegen": "0.86.0" } }, "sha512-qdsABWNW7uTll90l4Vh03gjeyu3WVDi2CyiiyvYGMRDcoYbjbQi6df3BMAm9lQI2yslZ1T14LlDDAsgTwNxplA=="],
"@react-native/codegen/@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="],
+2043 -3261
View File
File diff suppressed because it is too large. Load diff
+7 -7
View File
@@ -16,13 +16,13 @@
"@lingui/metro-transformer": "6.9.0",
"@lingui/react": "6.9.0",
"@lingui/vite-plugin": "6.9.0",
"@orpc/client": "1.15.4",
"@orpc/contract": "1.15.4",
"@orpc/json-schema": "1.15.4",
"@orpc/openapi": "1.15.4",
"@orpc/server": "1.15.4",
"@orpc/tanstack-query": "1.15.4",
"@orpc/zod": "1.15.4",
"@orpc/client": "2.0.0-beta.42",
"@orpc/contract": "2.0.0-beta.42",
"@orpc/json-schema": "2.0.0-beta.42",
"@orpc/openapi": "2.0.0-beta.42",
"@orpc/server": "2.0.0-beta.42",
"@orpc/tanstack-query": "2.0.0-beta.42",
"@orpc/zod": "2.0.0-beta.42",
"@tanstack/react-form": "1.33.5",
"@tanstack/react-query": "5.104.1",
"@types/bun": "1.4.2",
+1
View File
@@ -18,6 +18,7 @@
},
"dependencies": {
"@orpc/contract": "catalog:",
"@orpc/openapi": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
File diff suppressed because it is too large. Load diff
+13 -11
View File
@@ -369,7 +369,7 @@ export const EpisodeSchema = z
airDate: z.string().nullable().describe("Original air date (ISO 8601)"),
runtimeMinutes: z.number().nullable().describe("Episode runtime in minutes"),
})
.meta({ description: "A single TV episode" });
.meta({ id: "Episode", description: "A single TV episode" });
export const SeasonSchema = z
.object({
@@ -378,7 +378,7 @@ export const SeasonSchema = z
name: z.string().nullable().describe("Season name"),
episodes: z.array(EpisodeSchema).describe("Episodes in this season"),
})
.meta({ description: "A TV season with its episodes" });
.meta({ id: "Season", description: "A TV season with its episodes" });
export const AvailabilityOfferSchema = z
.object({
@@ -434,7 +434,7 @@ export const CastMemberSchema = z
.describe("ThumbHash blur placeholder for the profile photo"),
tmdbId: z.number().describe("TMDB person ID"),
})
.meta({ description: "A cast or crew member credit" });
.meta({ id: "CastMember", description: "A cast or crew member credit" });
export const ResolvedTitleSchema = z
.object({
@@ -466,7 +466,7 @@ export const ResolvedTitleSchema = z
trailerVideoKey: z.string().nullable().describe("YouTube video key for the trailer"),
genres: z.array(z.string()).describe("Genre names"),
})
.meta({ description: "A fully resolved movie or TV show from TMDB" });
.meta({ id: "Title", description: "A fully resolved movie or TV show from TMDB" });
export const PersonSchema = z
.object({
@@ -488,7 +488,7 @@ export const PersonSchema = z
.describe("Primary department (e.g. Acting, Directing)"),
imdbId: z.string().nullable().describe("IMDb person ID (e.g. nm0000123)"),
})
.meta({ description: "A person (actor, director, crew member) from TMDB" });
.meta({ id: "Person", description: "A person (actor, director, crew member) from TMDB" });
export const PersonCreditSchema = z
.object({
@@ -505,7 +505,7 @@ export const PersonCreditSchema = z
department: z.string().describe("Department (e.g. Acting, Directing)"),
job: z.string().nullable().describe("Job title (for crew credits)"),
})
.meta({ description: "A person's credit in a movie or TV show" });
.meta({ id: "PersonCredit", description: "A person's credit in a movie or TV show" });
/** Reusable TMDB browse result (trending / popular / discover items) */
export const TmdbBrowseItem = z
@@ -521,6 +521,7 @@ export const TmdbBrowseItem = z
voteAverage: z.number().nullable().describe("Average rating (0-10)"),
})
.meta({
id: "BrowseItem",
description: "A TMDB title card used in browse/trending/popular lists",
});
@@ -537,7 +538,7 @@ export const RecommendationItemSchema = z
firstAirDate: z.string().nullable().describe("First air date (ISO 8601)"),
voteAverage: z.number().nullable().describe("Average rating (0-10)"),
})
.meta({ description: "A recommended title" });
.meta({ id: "Recommendation", description: "A recommended title" });
const displayStatusEnum = z.enum(["in_watchlist", "watching", "caught_up", "completed"]);
@@ -913,7 +914,7 @@ export const JobSchema = z
isCurrentlyRunning: z.boolean().describe("Whether the job is currently executing"),
disabled: z.boolean().describe("Whether the job is disabled"),
})
.meta({ description: "Status of a background cron job" });
.meta({ id: "Job", description: "Status of a background cron job" });
export const SystemHealthSchema = z
.object({
@@ -977,6 +978,7 @@ export const SystemHealthSchema = z
checkedAt: z.string().describe("When this health check was performed (ISO 8601)"),
})
.meta({
id: "SystemHealth",
description:
"Comprehensive system health report covering database, TMDB, jobs, cache, backups, and environment",
});
@@ -1005,7 +1007,7 @@ export const IntegrationSchema = z
lastEventAt: z.string().nullable().describe("Last received event timestamp (ISO 8601)"),
createdAt: z.string().describe("When the integration was created (ISO 8601)"),
})
.meta({ description: "A media server integration configuration" });
.meta({ id: "Integration", description: "A media server integration configuration" });
export const IntegrationEventSchema = z
.object({
@@ -1016,7 +1018,7 @@ export const IntegrationEventSchema = z
status: z.enum(["success", "ignored", "error"]).describe("Event processing outcome"),
receivedAt: z.string().describe("When the event was received (ISO 8601)"),
})
.meta({ description: "A webhook or sync event from a media server" });
.meta({ id: "IntegrationEvent", description: "A webhook or sync event from a media server" });
export const IntegrationsListOutput = z
.object({
@@ -1045,7 +1047,7 @@ export const BackupSchema = z
.enum(["manual", "scheduled", "pre-restore"])
.describe("How the backup was created: manual, scheduled, or automatic pre-restore"),
})
.meta({ description: "A database backup file" });
.meta({ id: "Backup", description: "A database backup file" });
export const BackupsListOutput = z
.object({