diff --git a/apps/content/.vitepress/config.ts b/apps/content/.vitepress/config.ts index 5e498aaee..c28224286 100644 --- a/apps/content/.vitepress/config.ts +++ b/apps/content/.vitepress/config.ts @@ -173,6 +173,7 @@ export default defineConfig({ collapsed: true, items: [ { text: 'Pinia Colada', link: '/docs/pinia-colada' }, + { text: 'Hey API', link: '/docs/hey-api' }, { text: 'NestJS', link: '/docs/openapi/nest/implement-contract' }, { text: 'Playgrounds', link: '/docs/playgrounds' }, { text: 'Comparison', link: '/docs/comparison' }, diff --git a/apps/content/docs/hey-api.md b/apps/content/docs/hey-api.md new file mode 100644 index 000000000..a3c450a71 --- /dev/null +++ b/apps/content/docs/hey-api.md @@ -0,0 +1,71 @@ +--- +title: Hey API Integration +description: Easily convert a Hey API generated client into an oRPC client to take full advantage of the oRPC ecosystem. +--- + +# Hey API Integration + +Easily convert a [Hey API](https://heyapi.dev/) generated client into an oRPC client to take full advantage of the oRPC ecosystem. + +## Installation + +::: code-group + +```sh [npm] +npm install @orpc/hey-api@latest +``` + +```sh [yarn] +yarn add @orpc/hey-api@latest +``` + +```sh [pnpm] +pnpm add @orpc/hey-api@latest +``` + +```sh [bun] +bun add @orpc/hey-api@latest +``` + +```sh [deno] +deno install npm:@orpc/hey-api@latest +``` + +::: + +## Generating an Hey API Client + +To generate a Hey API client, run the following command: + +```sh +npx @hey-api/openapi-ts \ + -i https://get.heyapi.dev/hey-api/backend \ + -o src/client \ + -c @hey-api/client-fetch +``` + +This command uses the OpenAPI spec at `https://get.heyapi.dev/hey-api/backend` and outputs the generated client into the `src/client` directory. +And make sure you have `@hey-api/client-fetch` installed. + +::: info +For more information on Hey API, please refer to the [official documentation](https://heyapi.dev/). +::: + +## Converting to an oRPC Client + +Once the client is generated, convert it to an oRPC client using the `toORPCClient` function: + +```ts +import { experimental_toORPCClient } from '@orpc/hey-api' +import * as sdk from 'src/client/sdk.gen' + +export const client = experimental_toORPCClient(sdk) + +const { body } = await client.listPlanets() +``` + +This `client` now behaves like any standard oRPC [server-side client](/docs/client/server-side) or [client-side client](/docs/client/client-side), allowing you to use it with any oRPC-compatible library. + +## Error Handling + +Internally, oRPC passes the `throwOnError` option to the Hey API client. If the original Hey API client throws an error, oRPC will forward it as is without modification ensuring consistent error handling. diff --git a/eslint.config.js b/eslint.config.js index d61b665c3..32758f8e1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,6 +3,7 @@ import pluginBan from 'eslint-plugin-ban' export default antfu({ formatters: true, + ignores: ['packages/hey-api/tests/client/**'], }, { plugins: { ban: pluginBan }, rules: { diff --git a/package.json b/package.json index 0562c9676..5a565a8fb 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "eslint-plugin-format": "^1.0.0", "jsdom": "^26.0.0", "lint-staged": "^16.0.0", + "msw": "^2.8.4", "simple-git-hooks": "^2.11.1", "typescript": "^5.8.3", "unbuild": "^3.5.0", diff --git a/packages/hey-api/.gitignore b/packages/hey-api/.gitignore new file mode 100644 index 000000000..f3620b55e --- /dev/null +++ b/packages/hey-api/.gitignore @@ -0,0 +1,26 @@ +# Hidden folders and files +.* +!.gitignore +!.*.example + +# Common generated folders +logs/ +node_modules/ +out/ +dist/ +dist-ssr/ +build/ +coverage/ +temp/ + +# Common generated files +*.log +*.log.* +*.tsbuildinfo +*.vitest-temp.json +vite.config.ts.timestamp-* +vitest.config.ts.timestamp-* + +# Common manual ignore files +*.local +*.pem \ No newline at end of file diff --git a/packages/hey-api/README.md b/packages/hey-api/README.md new file mode 100644 index 000000000..4d2448bb5 --- /dev/null +++ b/packages/hey-api/README.md @@ -0,0 +1,78 @@ +
+ oRPC logo +
+ +

+ +
+ + codecov + + + weekly downloads + + + MIT License + + + Discord + +
+ +

Typesafe APIs Made Simple 🪄

+ +**oRPC is a powerful combination of RPC and OpenAPI**, makes it easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards + +--- + +## Highlights + +- **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server. +- **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard. +- **📝 Contract-First Development**: Optionally define your API contract before implementation. +- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte), Pinia Colada, and more. +- **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms. +- **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators. +- **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more. +- **⏱️ Lazy Router**: Enhance cold start times with our lazy routing feature. +- **📡 SSE & Streaming**: Enjoy full type-safe support for SSE and streaming. +- **🌍 Multi-Runtime Support**: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond. +- **🔌 Extendability**: Easily extend functionality with plugins, middleware, and interceptors. +- **🛡️ Reliability**: Well-tested, TypeScript-based, production-ready, and MIT licensed. + +## Documentation + +You can find the full documentation [here](https://orpc.unnoq.com). + +## Packages + +- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract. +- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract. +- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety. +- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with NestJS. +- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions. +- [@orpc/react-query](https://www.npmjs.com/package/@orpc/react-query): Integration with [React Query](https://tanstack.com/query/latest/docs/framework/react/overview). +- [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview). +- [@orpc/solid-query](https://www.npmjs.com/package/@orpc/solid-query): Integration with [Solid Query](https://tanstack.com/query/latest/docs/framework/solid/overview). +- [@orpc/svelte-query](https://www.npmjs.com/package/@orpc/svelte-query): Integration with [Svelte Query](https://tanstack.com/query/latest/docs/framework/svelte/overview). +- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/). +- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests. +- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet. +- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/). +- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/). + +## `@orpc/hey-api` + +Integration with [Hey API](https://heyapi.dev/). + +## Sponsors + +

+ + + +

+ +## License + +Distributed under the MIT License. See [LICENSE](https://github.com/unnoq/orpc/blob/main/LICENSE) for more information. diff --git a/packages/hey-api/package.json b/packages/hey-api/package.json new file mode 100644 index 000000000..70e34e6b0 --- /dev/null +++ b/packages/hey-api/package.json @@ -0,0 +1,49 @@ +{ + "name": "@orpc/hey-api", + "type": "module", + "version": "0.0.0", + "license": "MIT", + "homepage": "https://orpc.unnoq.com", + "repository": { + "type": "git", + "url": "git+https://github.com/unnoq/orpc.git", + "directory": "packages/hey-api" + }, + "keywords": [ + "unnoq", + "orpc", + "Hey API" + ], + "publishConfig": { + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + } + }, + "exports": { + ".": "./src/index.ts" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "unbuild", + "build:watch": "pnpm run build --watch", + "type:check": "tsc -b", + "prepare": "openapi-ts -i ./tests/spec.json -o ./tests/client -c @hey-api/client-fetch" + }, + "peerDependencies": { + "@hey-api/client-fetch": "*" + }, + "dependencies": { + "@orpc/client": "workspace:*", + "@orpc/shared": "workspace:*" + }, + "devDependencies": { + "@hey-api/client-fetch": "^0.10.1", + "@hey-api/openapi-ts": "^0.67.6" + } +} diff --git a/packages/hey-api/src/index.ts b/packages/hey-api/src/index.ts new file mode 100644 index 000000000..80fdd1cd6 --- /dev/null +++ b/packages/hey-api/src/index.ts @@ -0,0 +1 @@ +export * from './to-orpc-client' diff --git a/packages/hey-api/src/to-orpc-client.test-d.ts b/packages/hey-api/src/to-orpc-client.test-d.ts new file mode 100644 index 000000000..4202df9a5 --- /dev/null +++ b/packages/hey-api/src/to-orpc-client.test-d.ts @@ -0,0 +1,47 @@ +import type { NestedClient } from '../../client/src/types' +import type { Planet } from '../tests/client/types.gen' +import * as sdk from '../tests/client/sdk.gen' +import { experimental_toORPCClient } from './to-orpc-client' + +describe('toORPCClient', () => { + const client = experimental_toORPCClient({ + ...sdk, + somethingElse: 123, + }) + + const c = sdk.listPlanets() + + it('satisfies nested client', () => { + const _b: NestedClient> = client + }) + + it('inputs', async () => { + client.listPlanets() + + client.listPlanets({ + query: { + limit: 10, + offset: 0, + }, + }) + + client.listPlanets({ + query: { + // @ts-expect-error - invalid type + limit: 'invalid', + }, + }) + + client.getPlanet({ path: { planetId: 'earth' } }) + // @ts-expect-error - path is required + client.getPlanet() + // @ts-expect-error - invalid type + client.getPlanet({ path: { planetId: 123 } }) + }) + + it('outputs', async () => { + expectTypeOf(await client.listPlanets()).toEqualTypeOf<{ body: Planet[], request: Request, response: Response }>() + expectTypeOf(await client.getPlanet({ path: { planetId: 'earth' } })).toEqualTypeOf<{ body: Planet, request: Request, response: Response }>() + expectTypeOf(await client.createPlanet({ body: { name: 'Earth' } })).toEqualTypeOf<{ body: Planet, request: Request, response: Response }>() + }) +}) diff --git a/packages/hey-api/src/to-orpc-client.test.ts b/packages/hey-api/src/to-orpc-client.test.ts new file mode 100644 index 000000000..472fd6ac9 --- /dev/null +++ b/packages/hey-api/src/to-orpc-client.test.ts @@ -0,0 +1,159 @@ +import { http, HttpResponse } from 'msw' +import { setupServer } from 'msw/node' +import { client } from '../tests/client/client.gen' +import * as sdk from '../tests/client/sdk.gen' +import { experimental_toORPCClient } from './to-orpc-client' + +client.setConfig({ + baseUrl: 'https://example.com', +}) + +const server = setupServer( + http.get('https://example.com/planets', (req) => { + if (req.request.url.includes('throwOnError=1')) { + return HttpResponse.json(null, { status: 500 }) + } + + return HttpResponse.json([{ id: 'earth', name: 'Earth' }], { + headers: { + 'X-Rate-Limit': '10', + 'Last-Event-ID': req.request.headers.get('Last-Event-ID') ?? 'EMPTY', + }, + }) + }), + http.post('https://example.com/planets', async (req) => { + const body = await req.request.json() as any + return HttpResponse.json({ id: body.name, name: body.name }) + }), + http.get('https://example.com/planets/:planetId', (req) => { + return HttpResponse.json({ id: req.params.planetId, name: req.params.planetId }) + }), +) + +beforeAll(() => server.listen({ onUnhandledRequest: 'error' })) + +afterEach(() => server.resetHandlers()) + +afterAll(() => server.close()) + +describe('toORPCClient', () => { + const client = experimental_toORPCClient({ + ...sdk, + somethingElse: 123, + }) + + it('should ignore non-function properties', () => { + expect(client.somethingElse).toBeUndefined() + }) + + it('works', async () => { + const result = await client.listPlanets() + expect(result).toEqual({ + body: [{ id: 'earth', name: 'Earth' }], + request: expect.any(Request), + response: expect.any(Response), + }) + }) + + it('with lastEventId', async () => { + const result = await client.listPlanets({ + headers: { + 'x-something': 'value', + 'last-event-id': '123', + }, + }, { lastEventId: '456' }) + + expect(result.request.headers.get('x-something')).toBe('value') + expect(result.request.headers.get('last-event-id')).toBe('456') + expect(result.response.headers.get('last-event-id')).toBe('456') + }) + + it('with query', async () => { + const result = await client.listPlanets({ + query: { + limit: 10, + offset: 0, + }, + }) + + expect(result.request.url).toBe('https://example.com/planets?limit=10&offset=0') + expect(result.body).toEqual([{ id: 'earth', name: 'Earth' }]) + }) + + it('with params', async () => { + const result = await client.getPlanet({ + path: { planetId: 'earth' }, + }) + + expect(result.request.url).toBe('https://example.com/planets/earth') + expect(result.body).toEqual({ id: 'earth', name: 'earth' }) + }) + + it('with body', async () => { + const result = await client.createPlanet({ + body: { name: 'Bob' }, + }) + + expect(result.body).toEqual({ id: 'Bob', name: 'Bob' }) + }) + + describe('abort signal', () => { + it('case 1', async () => { + const controller1 = new AbortController() + const controller2 = new AbortController() + + const result = await client.createPlanet({ + body: { name: 'Bob' }, + signal: controller1.signal, + }, { signal: controller2.signal }) + + expect(result.request.signal.aborted).toEqual(false) + controller1.abort() + expect(result.request.signal.aborted).toEqual(true) + }) + + it('case 2', async () => { + const controller1 = new AbortController() + const controller2 = new AbortController() + + const result = await client.createPlanet({ + body: { name: 'Bob' }, + signal: controller1.signal, + }, { signal: controller2.signal }) + + expect(result.request.signal.aborted).toEqual(false) + controller2.abort() + expect(result.request.signal.aborted).toEqual(true) + }) + + it('case 3', async () => { + const controller1 = new AbortController() + const controller2 = new AbortController() + controller1.abort() + + await expect( + client.createPlanet({ + body: { name: 'Bob' }, + signal: controller1.signal, + }, { signal: controller2.signal }), + ).rejects.toThrowError('This operation was aborted') + }) + + it('case 4', async () => { + const controller1 = new AbortController() + const controller2 = new AbortController() + controller2.abort() + + await expect( + client.createPlanet({ + body: { name: 'Bob' }, + signal: controller1.signal, + }, { signal: controller2.signal }), + ).rejects.toThrowError('This operation was aborted') + }) + }) + + it('throws on error', async () => { + await expect(client.listPlanets({ query: { throwOnError: 1 } as any })).rejects.toThrowError() + }) +}) diff --git a/packages/hey-api/src/to-orpc-client.ts b/packages/hey-api/src/to-orpc-client.ts new file mode 100644 index 000000000..09b7a0c7b --- /dev/null +++ b/packages/hey-api/src/to-orpc-client.ts @@ -0,0 +1,50 @@ +import type { RequestResult } from '@hey-api/client-fetch' +import type { Client, ThrowableError } from '@orpc/client' + +export type experimental_ToORPCClientResult> = { + [K in keyof T]: T[K] extends (options: infer UInput extends Record | undefined) => RequestResult + ? Client, UInput, { body: Exclude, request: Request, response: Response }, ThrowableError> + : never +} + +export function experimental_toORPCClient>(sdk: T): experimental_ToORPCClientResult { + const client = {} as Record, undefined | Record, any, any>> + + for (const key in sdk) { + const fn = sdk[key] + + if (!fn || typeof fn !== 'function') { + continue + } + + client[key] = async (input, options) => { + const controller = new AbortController() + + if (input?.signal?.aborted || options?.signal?.aborted) { + controller.abort() + } + else { + input?.signal?.addEventListener('abort', () => controller.abort()) + options?.signal?.addEventListener('abort', () => controller.abort()) + } + + const result = await fn({ + ...input, + signal: controller.signal, + headers: { + ...input?.headers, + ...typeof options?.lastEventId === 'string' ? { 'last-event-id': options.lastEventId } : {}, + }, + throwOnError: true, + }) + + return { + body: result.data, + request: result.request, + response: result.response, + } + } + } + + return client as experimental_ToORPCClientResult +} diff --git a/packages/hey-api/tests/client/client.gen.ts b/packages/hey-api/tests/client/client.gen.ts new file mode 100644 index 000000000..6759c1f28 --- /dev/null +++ b/packages/hey-api/tests/client/client.gen.ts @@ -0,0 +1,16 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { ClientOptions } from './types.gen'; +import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch'; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = (override?: Config) => Config & T>; + +export const client = createClient(createConfig()); \ No newline at end of file diff --git a/packages/hey-api/tests/client/index.ts b/packages/hey-api/tests/client/index.ts new file mode 100644 index 000000000..e64537d21 --- /dev/null +++ b/packages/hey-api/tests/client/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts +export * from './types.gen'; +export * from './sdk.gen'; \ No newline at end of file diff --git a/packages/hey-api/tests/client/sdk.gen.ts b/packages/hey-api/tests/client/sdk.gen.ts new file mode 100644 index 000000000..5fd0499e4 --- /dev/null +++ b/packages/hey-api/tests/client/sdk.gen.ts @@ -0,0 +1,44 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch'; +import type { ListPlanetsData, ListPlanetsResponse, CreatePlanetData, CreatePlanetResponse, GetPlanetData, GetPlanetResponse } from './types.gen'; +import { client as _heyApiClient } from './client.gen'; + +export type Options = ClientOptions & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; +}; + +export const listPlanets = (options?: Options) => { + return (options?.client ?? _heyApiClient).get({ + url: '/planets', + ...options + }); +}; + +export const createPlanet = (options: Options) => { + return (options.client ?? _heyApiClient).post({ + url: '/planets', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } + }); +}; + +export const getPlanet = (options: Options) => { + return (options.client ?? _heyApiClient).get({ + url: '/planets/{planetId}', + ...options + }); +}; \ No newline at end of file diff --git a/packages/hey-api/tests/client/types.gen.ts b/packages/hey-api/tests/client/types.gen.ts new file mode 100644 index 000000000..9f6b41ee4 --- /dev/null +++ b/packages/hey-api/tests/client/types.gen.ts @@ -0,0 +1,67 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Planet = { + id: string; + name: string; +}; + +export type NewPlanet = { + name: string; +}; + +export type ListPlanetsData = { + body?: never; + path?: never; + query?: { + limit?: number; + offset?: number; + }; + url: '/planets'; +}; + +export type ListPlanetsResponses = { + /** + * A list of planets + */ + 200: Array; +}; + +export type ListPlanetsResponse = ListPlanetsResponses[keyof ListPlanetsResponses]; + +export type CreatePlanetData = { + body: NewPlanet; + path?: never; + query?: never; + url: '/planets'; +}; + +export type CreatePlanetResponses = { + /** + * A created planet + */ + 201: Planet; +}; + +export type CreatePlanetResponse = CreatePlanetResponses[keyof CreatePlanetResponses]; + +export type GetPlanetData = { + body?: never; + path: { + planetId: string; + }; + query?: never; + url: '/planets/{planetId}'; +}; + +export type GetPlanetResponses = { + /** + * A planet + */ + 200: Planet; +}; + +export type GetPlanetResponse = GetPlanetResponses[keyof GetPlanetResponses]; + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; \ No newline at end of file diff --git a/packages/hey-api/tests/spec.json b/packages/hey-api/tests/spec.json new file mode 100644 index 000000000..9fa3a9852 --- /dev/null +++ b/packages/hey-api/tests/spec.json @@ -0,0 +1,133 @@ +{ + "openapi": "3.1.1", + "info": { + "title": "Hey API Test", + "version": "1.0.0" + }, + "paths": { + "/planets": { + "get": { + "operationId": "listPlanets", + "parameters": [ + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "A list of planets", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Planet" + } + } + } + }, + "headers": { + "X-Rate-Limit": { + "schema": { + "type": "integer" + }, + "required": true + } + } + } + } + }, + "post": { + "operationId": "createPlanet", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPlanet" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "A created planet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Planet" + } + } + } + } + } + } + }, + "/planets/{planetId}": { + "get": { + "operationId": "getPlanet", + "parameters": [ + { + "name": "planetId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "A planet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Planet" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Planet": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["id", "name"] + }, + "NewPlanet": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": ["name"] + } + } + } +} diff --git a/packages/hey-api/tsconfig.json b/packages/hey-api/tsconfig.json new file mode 100644 index 000000000..076e6f9ef --- /dev/null +++ b/packages/hey-api/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.lib.json", + "references": [ + { "path": "../client" }, + { "path": "../shared" } + ], + "include": ["src"], + "exclude": [ + "**/*.test.*", + "**/*.test-d.ts", + "**/*.bench.*", + "**/__tests__/**", + "**/__mocks__/**", + "**/__snapshots__/**" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ff4c3c81..bae685a20 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: lint-staged: specifier: ^16.0.0 version: 16.0.0 + msw: + specifier: ^2.8.4 + version: 2.8.4(@types/node@22.15.21)(typescript@5.8.3) simple-git-hooks: specifier: ^2.11.1 version: 2.13.0 @@ -70,7 +73,7 @@ importers: version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0)) vitest: specifier: ^3.0.4 - version: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) + version: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) apps/content: devDependencies: @@ -218,6 +221,22 @@ importers: specifier: ^3.25.11 version: 3.25.23 + packages/hey-api: + dependencies: + '@orpc/client': + specifier: workspace:* + version: link:../client + '@orpc/shared': + specifier: workspace:* + version: link:../shared + devDependencies: + '@hey-api/client-fetch': + specifier: ^0.10.1 + version: 0.10.1(@hey-api/openapi-ts@0.67.6(magicast@0.3.5)(typescript@5.8.3)) + '@hey-api/openapi-ts': + specifier: ^0.67.6 + version: 0.67.6(magicast@0.3.5)(typescript@5.8.3) + packages/nest: dependencies: '@orpc/client': @@ -1576,6 +1595,15 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@bundled-es-modules/cookie@2.0.1': + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + + '@bundled-es-modules/tough-cookie@0.1.6': + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + '@capsizecss/unpack@2.4.0': resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==} @@ -2627,6 +2655,22 @@ packages: '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + '@hey-api/client-fetch@0.10.1': + resolution: {integrity: sha512-C1XZEnzvOIdXppvMcnO8/V/RpcORxA4rh+5qjuMcItkV++hv7aBz7tSLd0z+bSLFUwttec077WT/nPS+oO4BiA==} + peerDependencies: + '@hey-api/openapi-ts': < 2 + + '@hey-api/json-schema-ref-parser@1.0.6': + resolution: {integrity: sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w==} + engines: {node: '>= 16'} + + '@hey-api/openapi-ts@0.67.6': + resolution: {integrity: sha512-ywZggKKYieVjM6O6T60/Bl+QBRvhcKAov8dAIQor7reyKpFbEn3Ws+9WKoXR8QUuXN8AR8nMFjOuYPer5db/dg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} + hasBin: true + peerDependencies: + typescript: ^5.5.3 + '@hono/node-server@1.14.2': resolution: {integrity: sha512-GHjpOeHYbr9d1vkID2sNUYkl5IxumyhDrUJB7wBp7jvqYwPFt+oNKsAPBRcdSbV7kIrXhouLE199ks1QcK4r7A==} engines: {node: '>=18.14.1'} @@ -3052,6 +3096,9 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@kwsites/file-exists@1.1.1': resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} @@ -3079,6 +3126,10 @@ packages: engines: {node: '>=18'} hasBin: true + '@mswjs/interceptors@0.37.6': + resolution: {integrity: sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==} + engines: {node: '>=18'} + '@napi-rs/nice-android-arm-eabi@1.0.1': resolution: {integrity: sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==} engines: {node: '>= 10'} @@ -3421,6 +3472,15 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} @@ -4747,12 +4807,18 @@ packages: '@types/serve-static@1.15.7': resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + '@types/statuses@2.0.5': + resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} + '@types/superagent@8.1.9': resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} @@ -5874,6 +5940,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@2.0.1: + resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + c12@3.0.4: resolution: {integrity: sha512-t5FaZTYbbCtvxuZq9xxIruYydrAGsJ+8UdP0pZzMiK2xl/gNiSOy0OxhLzHUEEb0m1QXYqfzfvyIFEmz/g9lqg==} peerDependencies: @@ -6141,6 +6215,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@13.0.0: + resolution: {integrity: sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==} + engines: {node: '>=18'} + commander@13.1.0: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} @@ -7633,6 +7711,10 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + giget@1.2.5: + resolution: {integrity: sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==} + hasBin: true + giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true @@ -7748,6 +7830,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gray-matter@4.0.3: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} @@ -7768,6 +7854,11 @@ packages: h3@1.15.3: resolution: {integrity: sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ==} + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -7828,6 +7919,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -8119,6 +8213,9 @@ packages: is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-npm@6.0.0: resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9056,6 +9153,16 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.8.4: + resolution: {integrity: sha512-GLU8gx0o7RBG/3x/eTnnLd5S5ZInxXRRRMN8GJwaPZ4jpJTxzQfWGvwr90e8L5dkKJnz+gT4gQYCprLy/c4kVw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -9314,6 +9421,11 @@ packages: nwsapi@2.2.20: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} + nypm@0.5.4: + resolution: {integrity: sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + nypm@0.6.0: resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} engines: {node: ^14.16.0 || >=16.10.0} @@ -9433,6 +9545,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + oxc-parser@0.71.0: resolution: {integrity: sha512-RXmu7qi+67RJ8E5UhKZJdliTI+AqD3gncsJecjujcYvjsCZV9KNIfu42fQAnAfLaYZuzOMRdUYh7LzV3F1C0Gw==} engines: {node: '>=14.0.0'} @@ -10148,6 +10263,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + publish-browser-extension@3.0.0: resolution: {integrity: sha512-gwjH8mIepNqID2VqKIxzT6lmtvkcc5tcWYzrGSUdkeUFFFSHhGp9xx01EZ7j8wPq50dDe0XU5VNbHMAqr6wWAA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -10175,6 +10293,9 @@ packages: quansync@0.2.10: resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -10964,6 +11085,9 @@ packages: streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -11327,6 +11451,10 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -11485,6 +11613,11 @@ packages: ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} @@ -11613,6 +11746,10 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -11738,6 +11875,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + urlpattern-polyfill@10.1.0: resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} @@ -12349,6 +12489,9 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -13213,6 +13356,19 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@bundled-es-modules/cookie@2.0.1': + dependencies: + cookie: 0.7.2 + + '@bundled-es-modules/statuses@1.0.1': + dependencies: + statuses: 2.0.1 + + '@bundled-es-modules/tough-cookie@0.1.6': + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 + '@capsizecss/unpack@2.4.0(encoding@0.1.13)': dependencies: blob-to-buffer: 1.2.9 @@ -14007,6 +14163,27 @@ snapshots: '@gar/promisify@1.1.3': {} + '@hey-api/client-fetch@0.10.1(@hey-api/openapi-ts@0.67.6(magicast@0.3.5)(typescript@5.8.3))': + dependencies: + '@hey-api/openapi-ts': 0.67.6(magicast@0.3.5)(typescript@5.8.3) + + '@hey-api/json-schema-ref-parser@1.0.6': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + lodash: 4.17.21 + + '@hey-api/openapi-ts@0.67.6(magicast@0.3.5)(typescript@5.8.3)': + dependencies: + '@hey-api/json-schema-ref-parser': 1.0.6 + c12: 2.0.1(magicast@0.3.5) + commander: 13.0.0 + handlebars: 4.7.8 + typescript: 5.8.3 + transitivePeerDependencies: + - magicast + '@hono/node-server@1.14.2(hono@4.7.6)': dependencies: hono: 4.7.6 @@ -14379,6 +14556,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jsdevtools/ono@7.1.3': {} + '@kwsites/file-exists@1.1.1': dependencies: debug: 4.4.1 @@ -14430,6 +14609,15 @@ snapshots: - encoding - supports-color + '@mswjs/interceptors@0.37.6': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/nice-android-arm-eabi@1.0.1': optional: true @@ -15013,6 +15201,15 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@oslojs/encoding@1.1.0': {} '@oxc-parser/binding-darwin-arm64@0.71.0': @@ -16538,7 +16735,7 @@ snapshots: svelte: 5.33.1 optionalDependencies: vite: 6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)': dependencies: @@ -16761,6 +16958,8 @@ snapshots: '@types/node': 22.15.21 '@types/send': 0.17.4 + '@types/statuses@2.0.5': {} + '@types/superagent@8.1.9': dependencies: '@types/cookiejar': 2.1.5 @@ -16773,6 +16972,8 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/tough-cookie@4.0.5': {} + '@types/triple-beam@1.3.5': {} '@types/unist@2.0.11': {} @@ -17161,7 +17362,7 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -17171,7 +17372,7 @@ snapshots: eslint: 9.27.0(jiti@2.4.2) optionalDependencies: typescript: 5.8.3 - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -17182,12 +17383,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.4(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0))': + '@vitest/mocker@3.1.4(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.1.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: + msw: 2.8.4(@types/node@22.15.21)(typescript@5.8.3) vite: 6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) '@vitest/pretty-format@3.1.4': @@ -17218,7 +17420,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.13 tinyrainbow: 2.0.0 - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0) '@vitest/utils@3.1.4': dependencies: @@ -18361,6 +18563,23 @@ snapshots: bytes@3.1.2: {} + c12@2.0.1(magicast@0.3.5): + dependencies: + chokidar: 4.0.3 + confbox: 0.1.8 + defu: 6.1.4 + dotenv: 16.5.0 + giget: 1.2.5 + jiti: 2.4.2 + mlly: 1.7.4 + ohash: 1.1.6 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.1 + rc9: 2.1.2 + optionalDependencies: + magicast: 0.3.5 + c12@3.0.4(magicast@0.3.5): dependencies: chokidar: 4.0.3 @@ -18658,6 +18877,8 @@ snapshots: commander@10.0.1: {} + commander@13.0.0: {} + commander@13.1.0: {} commander@2.20.3: {} @@ -20460,6 +20681,16 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + giget@1.2.5: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.6 + nypm: 0.5.4 + pathe: 2.0.3 + tar: 6.2.1 + giget@2.0.0: dependencies: citty: 0.1.6 @@ -20619,6 +20850,8 @@ snapshots: graphemer@1.4.0: {} + graphql@16.11.0: {} + gray-matter@4.0.3: dependencies: js-yaml: 3.14.1 @@ -20669,6 +20902,15 @@ snapshots: ufo: 1.6.1 uncrypto: 0.1.3 + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + has-flag@4.0.0: {} has-own-prop@2.0.0: {} @@ -20779,6 +21021,8 @@ snapshots: he@1.2.0: {} + headers-polyfill@4.0.3: {} + highlight.js@10.7.3: {} hono@4.7.6: {} @@ -21045,6 +21289,8 @@ snapshots: is-module@1.0.0: {} + is-node-process@1.2.0: {} + is-npm@6.0.0: {} is-number@7.0.0: {} @@ -22124,6 +22370,31 @@ snapshots: ms@2.1.3: {} + msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.9(@types/node@22.15.21) + '@mswjs/interceptors': 0.37.6 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + graphql: 16.11.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.41.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - '@types/node' + muggle-string@0.4.1: {} multer@1.4.5-lts.2: @@ -22655,6 +22926,15 @@ snapshots: nwsapi@2.2.20: {} + nypm@0.5.4: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 1.3.1 + tinyexec: 0.3.2 + ufo: 1.6.1 + nypm@0.6.0: dependencies: citty: 0.1.6 @@ -22814,6 +23094,8 @@ snapshots: os-tmpdir@1.0.2: {} + outvariant@1.4.3: {} + oxc-parser@0.71.0: dependencies: '@oxc-project/types': 0.71.0 @@ -23489,6 +23771,10 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + psl@1.15.0: + dependencies: + punycode: 2.3.1 + publish-browser-extension@3.0.0: dependencies: cac: 6.7.14 @@ -23528,6 +23814,8 @@ snapshots: quansync@0.2.10: {} + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} @@ -24565,6 +24853,8 @@ snapshots: optionalDependencies: bare-events: 2.5.4 + strict-event-emitter@0.5.1: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -24954,6 +25244,13 @@ snapshots: totalist@3.0.1: {} + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -25104,6 +25401,9 @@ snapshots: ufo@1.6.1: {} + uglify-js@3.19.3: + optional: true + uhyphen@0.2.0: {} uid@2.0.2: @@ -25313,6 +25613,8 @@ snapshots: universalify@0.1.2: {} + universalify@0.2.0: {} + universalify@2.0.1: {} unixify@1.0.0: @@ -25445,6 +25747,11 @@ snapshots: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + urlpattern-polyfill@10.1.0: {} urlpattern-polyfill@8.0.2: {} @@ -25882,10 +26189,10 @@ snapshots: - typescript - universal-cookie - vitest@3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0): + vitest@3.1.4(@types/debug@4.1.12)(@types/node@22.15.21)(@vitest/ui@3.1.4)(jiti@2.4.2)(jsdom@26.1.0)(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0): dependencies: '@vitest/expect': 3.1.4 - '@vitest/mocker': 3.1.4(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0)) + '@vitest/mocker': 3.1.4(msw@2.8.4(@types/node@22.15.21)(typescript@5.8.3))(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.0)) '@vitest/pretty-format': 3.1.4 '@vitest/runner': 3.1.4 '@vitest/snapshot': 3.1.4 @@ -26282,6 +26589,8 @@ snapshots: word-wrap@1.2.5: {} + wordwrap@1.0.0: {} + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0