fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3264 from hyoban/1-25-orpc

feat: `orpc` plugin

authored by

Lubos and committed by
GitHub
ad3163c2 d61d2b1e

+3845 -423
+5
.changeset/lazy-nails-give.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + **plugin(orpc)**: initial release
+1
dev/package.json
··· 13 13 "@hey-api/openapi-python": "workspace:*", 14 14 "@hey-api/openapi-ts": "workspace:*", 15 15 "@opencode-ai/sdk": "1.2.27", 16 + "@orpc/contract": "1.13.4", 16 17 "@pinia/colada": "0.19.1", 17 18 "@tanstack/angular-query-experimental": "5.90.25", 18 19 "@tanstack/preact-query": "5.93.0",
+5
dev/typescript/presets.ts
··· 30 30 }, 31 31 }, 32 32 ], 33 + rpc: () => [ 34 + /** RPC-style SDK with Zod validation */ 35 + 'orpc', 36 + 'zod', 37 + ], 33 38 sdk: () => [ 34 39 /** SDK with types */ 35 40 '@hey-api/typescript',
+6 -8
packages/codegen-core/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 9 + .env 10 + coverage 14 11 dist 15 - coverage 16 - .env 12 + 13 + # test files 14 + .gen
+4 -9
packages/openapi-python-tests/pydantic/v2/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+4 -9
packages/openapi-python-tests/sdks/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+1 -1
packages/openapi-python/src/plugins/@hey-api/client-core/utils.ts
··· 1 1 import type { Config } from '../../../config/types'; 2 - import type { PluginClientNames } from '../../../plugins/types'; 2 + import type { PluginClientNames } from '../../types'; 3 3 4 4 export function getClientPlugin( 5 5 config: Config,
+2 -2
packages/openapi-python/src/plugins/@hey-api/sdk/types.ts
··· 1 1 import type { DefinePlugin, OperationsStrategy, Plugin } from '@hey-api/shared'; 2 2 3 - import type { PluginClientNames } from '../../../plugins/types'; 4 - // import type { PluginClientNames, PluginValidatorNames } from '../../../plugins/types'; 3 + import type { PluginClientNames } from '../../types'; 4 + // import type { PluginClientNames, PluginValidatorNames } from '../../types'; 5 5 import type { ExamplesConfig, UserExamplesConfig } from './examples'; 6 6 import type { OperationsConfig, UserOperationsConfig } from './operations'; 7 7
+4 -9
packages/openapi-ts-tests/main/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen 20 15 test/generated 21 16 generated/
+9
packages/openapi-ts-tests/orpc/v1/.gitignore
··· 1 + .DS_Store 2 + .idea 3 + .tmp 4 + logs 5 + node_modules 6 + 7 + .env 8 + coverage 9 + dist
+108
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.0.x/custom-names/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { vCreatePostData, vCreatePostResponse, vCreateUserData, vCreateUserResponse, vDeleteUserData, vGetPostByIdData, vGetPostByIdResponse, vGetPostsData, vGetPostsResponse, vGetUserByIdData, vGetUserByIdResponse, vGetUsersData, vGetUsersResponse, vUpdateUserData, vUpdateUserResponse } from './valibot.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsersRpc = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(vGetUsersData).output(vGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUserRpc = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(vCreateUserData).output(vCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUserRpc = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(vDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserByIdRpc = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(vGetUserByIdData).output(vGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUserRpc = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(vUpdateUserData).output(vUpdateUserResponse); 64 + 65 + /** 66 + * Get all posts 67 + */ 68 + export const getPostsRpc = base.route({ 69 + method: 'GET', 70 + operationId: 'getPosts', 71 + path: '/posts', 72 + summary: 'Get all posts', 73 + tags: ['posts'] 74 + }).input(vGetPostsData).output(vGetPostsResponse); 75 + 76 + /** 77 + * Create a new post 78 + */ 79 + export const createPostRpc = base.route({ 80 + method: 'POST', 81 + operationId: 'createPost', 82 + path: '/posts', 83 + successStatus: 201, 84 + summary: 'Create a new post', 85 + tags: ['posts'] 86 + }).input(vCreatePostData).output(vCreatePostResponse); 87 + 88 + /** 89 + * Get a post by ID 90 + */ 91 + export const getPostByIdRpc = base.route({ 92 + method: 'GET', 93 + operationId: 'getPostById', 94 + path: '/posts/{postId}', 95 + summary: 'Get a post by ID', 96 + tags: ['posts'] 97 + }).input(vGetPostByIdData).output(vGetPostByIdResponse); 98 + 99 + export const rpcContract = { 100 + getUsersRpc, 101 + createUserRpc, 102 + deleteUserRpc, 103 + getUserByIdRpc, 104 + updateUserRpc, 105 + getPostsRpc, 106 + createPostRpc, 107 + getPostByIdRpc 108 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.0.x/custom-names/valibot.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as v from 'valibot'; 4 + 5 + export const vUser = v.object({ 6 + id: v.string(), 7 + email: v.pipe(v.string(), v.email()), 8 + name: v.string(), 9 + createdAt: v.optional(v.pipe(v.string(), v.isoTimestamp())) 10 + }); 11 + 12 + export const vCreateUserInput = v.object({ 13 + email: v.pipe(v.string(), v.email()), 14 + name: v.string(), 15 + password: v.optional(v.pipe(v.string(), v.minLength(8))) 16 + }); 17 + 18 + export const vUpdateUserInput = v.object({ 19 + email: v.optional(v.pipe(v.string(), v.email())), 20 + name: v.optional(v.string()) 21 + }); 22 + 23 + export const vPost = v.object({ 24 + id: v.string(), 25 + title: v.string(), 26 + content: v.string(), 27 + authorId: v.string(), 28 + status: v.optional(v.picklist([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ])), 33 + createdAt: v.optional(v.pipe(v.string(), v.isoTimestamp())) 34 + }); 35 + 36 + export const vCreatePostInput = v.object({ 37 + title: v.string(), 38 + content: v.string(), 39 + status: v.optional(v.picklist(['draft', 'published'])) 40 + }); 41 + 42 + export const vGetUsersData = v.object({ 43 + body: v.optional(v.never()), 44 + path: v.optional(v.never()), 45 + query: v.optional(v.object({ 46 + limit: v.optional(v.pipe(v.number(), v.integer()), 10), 47 + offset: v.optional(v.pipe(v.number(), v.integer()), 0) 48 + })) 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const vGetUsersResponse = v.array(vUser); 55 + 56 + export const vCreateUserData = v.object({ 57 + body: vCreateUserInput, 58 + path: v.optional(v.never()), 59 + query: v.optional(v.never()) 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const vCreateUserResponse = vUser; 66 + 67 + export const vDeleteUserData = v.object({ 68 + body: v.optional(v.never()), 69 + path: v.object({ 70 + userId: v.string() 71 + }), 72 + query: v.optional(v.never()), 73 + headers: v.optional(v.object({ 74 + 'X-Request-Id': v.optional(v.string()) 75 + })) 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const vDeleteUserResponse = v.void(); 82 + 83 + export const vGetUserByIdData = v.object({ 84 + body: v.optional(v.never()), 85 + path: v.object({ 86 + userId: v.string() 87 + }), 88 + query: v.optional(v.never()) 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const vGetUserByIdResponse = vUser; 95 + 96 + export const vUpdateUserData = v.object({ 97 + body: vUpdateUserInput, 98 + path: v.object({ 99 + userId: v.string() 100 + }), 101 + query: v.optional(v.never()) 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const vUpdateUserResponse = vUser; 108 + 109 + export const vGetPostsData = v.object({ 110 + body: v.optional(v.never()), 111 + path: v.optional(v.never()), 112 + query: v.optional(v.object({ 113 + authorId: v.optional(v.string()), 114 + status: v.optional(v.picklist([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ])) 119 + })) 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const vGetPostsResponse = v.array(vPost); 126 + 127 + export const vCreatePostData = v.object({ 128 + body: vCreatePostInput, 129 + path: v.optional(v.never()), 130 + query: v.optional(v.never()), 131 + headers: v.object({ 132 + 'X-Author-Id': v.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const vCreatePostResponse = vPost; 140 + 141 + export const vGetPostByIdData = v.object({ 142 + body: v.optional(v.never()), 143 + path: v.object({ 144 + postId: v.string() 145 + }), 146 + query: v.optional(v.object({ 147 + includeComments: v.optional(v.boolean(), false) 148 + })) 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const vGetPostByIdResponse = vPost;
+108
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.0.x/default/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + /** 66 + * Get all posts 67 + */ 68 + export const getPosts = base.route({ 69 + method: 'GET', 70 + operationId: 'getPosts', 71 + path: '/posts', 72 + summary: 'Get all posts', 73 + tags: ['posts'] 74 + }).input(zGetPostsData).output(zGetPostsResponse); 75 + 76 + /** 77 + * Create a new post 78 + */ 79 + export const createPost = base.route({ 80 + method: 'POST', 81 + operationId: 'createPost', 82 + path: '/posts', 83 + successStatus: 201, 84 + summary: 'Create a new post', 85 + tags: ['posts'] 86 + }).input(zCreatePostData).output(zCreatePostResponse); 87 + 88 + /** 89 + * Get a post by ID 90 + */ 91 + export const getPostById = base.route({ 92 + method: 'GET', 93 + operationId: 'getPostById', 94 + path: '/posts/{postId}', 95 + summary: 'Get a post by ID', 96 + tags: ['posts'] 97 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 + 99 + export const contract = { 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.0.x/default/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+111
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-custom-naming/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const GetUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const CreateUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const DeleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const GetUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const UpdateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + export const usersContracts = { 66 + GetUsers, 67 + CreateUser, 68 + DeleteUser, 69 + GetUserById, 70 + UpdateUser 71 + }; 72 + 73 + /** 74 + * Get all posts 75 + */ 76 + export const GetPosts = base.route({ 77 + method: 'GET', 78 + operationId: 'getPosts', 79 + path: '/posts', 80 + summary: 'Get all posts', 81 + tags: ['posts'] 82 + }).input(zGetPostsData).output(zGetPostsResponse); 83 + 84 + /** 85 + * Create a new post 86 + */ 87 + export const CreatePost = base.route({ 88 + method: 'POST', 89 + operationId: 'createPost', 90 + path: '/posts', 91 + successStatus: 201, 92 + summary: 'Create a new post', 93 + tags: ['posts'] 94 + }).input(zCreatePostData).output(zCreatePostResponse); 95 + 96 + /** 97 + * Get a post by ID 98 + */ 99 + export const GetPostById = base.route({ 100 + method: 'GET', 101 + operationId: 'getPostById', 102 + path: '/posts/{postId}', 103 + summary: 'Get a post by ID', 104 + tags: ['posts'] 105 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 106 + 107 + export const postsContracts = { 108 + GetPosts, 109 + CreatePost, 110 + GetPostById 111 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-custom-naming/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+111
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-nesting-id/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + export const users = { 66 + getUsers, 67 + createUser, 68 + deleteUser, 69 + getUserById, 70 + updateUser 71 + }; 72 + 73 + /** 74 + * Get all posts 75 + */ 76 + export const getPosts = base.route({ 77 + method: 'GET', 78 + operationId: 'getPosts', 79 + path: '/posts', 80 + summary: 'Get all posts', 81 + tags: ['posts'] 82 + }).input(zGetPostsData).output(zGetPostsResponse); 83 + 84 + /** 85 + * Create a new post 86 + */ 87 + export const createPost = base.route({ 88 + method: 'POST', 89 + operationId: 'createPost', 90 + path: '/posts', 91 + successStatus: 201, 92 + summary: 'Create a new post', 93 + tags: ['posts'] 94 + }).input(zCreatePostData).output(zCreatePostResponse); 95 + 96 + /** 97 + * Get a post by ID 98 + */ 99 + export const getPostById = base.route({ 100 + method: 'GET', 101 + operationId: 'getPostById', 102 + path: '/posts/{postId}', 103 + summary: 'Get a post by ID', 104 + tags: ['posts'] 105 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 106 + 107 + export const posts = { 108 + getPosts, 109 + createPost, 110 + getPostById 111 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-nesting-id/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+111
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-strategy-by-tags/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + export const users = { 66 + getUsers, 67 + createUser, 68 + deleteUser, 69 + getUserById, 70 + updateUser 71 + }; 72 + 73 + /** 74 + * Get all posts 75 + */ 76 + export const getPosts = base.route({ 77 + method: 'GET', 78 + operationId: 'getPosts', 79 + path: '/posts', 80 + summary: 'Get all posts', 81 + tags: ['posts'] 82 + }).input(zGetPostsData).output(zGetPostsResponse); 83 + 84 + /** 85 + * Create a new post 86 + */ 87 + export const createPost = base.route({ 88 + method: 'POST', 89 + operationId: 'createPost', 90 + path: '/posts', 91 + successStatus: 201, 92 + summary: 'Create a new post', 93 + tags: ['posts'] 94 + }).input(zCreatePostData).output(zCreatePostResponse); 95 + 96 + /** 97 + * Get a post by ID 98 + */ 99 + export const getPostById = base.route({ 100 + method: 'GET', 101 + operationId: 'getPostById', 102 + path: '/posts/{postId}', 103 + summary: 'Get a post by ID', 104 + tags: ['posts'] 105 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 106 + 107 + export const posts = { 108 + getPosts, 109 + createPost, 110 + getPostById 111 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-strategy-by-tags/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+108
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-strategy-single/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + /** 66 + * Get all posts 67 + */ 68 + export const getPosts = base.route({ 69 + method: 'GET', 70 + operationId: 'getPosts', 71 + path: '/posts', 72 + summary: 'Get all posts', 73 + tags: ['posts'] 74 + }).input(zGetPostsData).output(zGetPostsResponse); 75 + 76 + /** 77 + * Create a new post 78 + */ 79 + export const createPost = base.route({ 80 + method: 'POST', 81 + operationId: 'createPost', 82 + path: '/posts', 83 + successStatus: 201, 84 + summary: 'Create a new post', 85 + tags: ['posts'] 86 + }).input(zCreatePostData).output(zCreatePostResponse); 87 + 88 + /** 89 + * Get a post by ID 90 + */ 91 + export const getPostById = base.route({ 92 + method: 'GET', 93 + operationId: 'getPostById', 94 + path: '/posts/{postId}', 95 + summary: 'Get a post by ID', 96 + tags: ['posts'] 97 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 + 99 + export const api = { 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/contracts-strategy-single/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+108
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/custom-names/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { vCreatePostData, vCreatePostResponse, vCreateUserData, vCreateUserResponse, vDeleteUserData, vGetPostByIdData, vGetPostByIdResponse, vGetPostsData, vGetPostsResponse, vGetUserByIdData, vGetUserByIdResponse, vGetUsersData, vGetUsersResponse, vUpdateUserData, vUpdateUserResponse } from './valibot.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsersRpc = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(vGetUsersData).output(vGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUserRpc = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(vCreateUserData).output(vCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUserRpc = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(vDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserByIdRpc = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(vGetUserByIdData).output(vGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUserRpc = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(vUpdateUserData).output(vUpdateUserResponse); 64 + 65 + /** 66 + * Get all posts 67 + */ 68 + export const getPostsRpc = base.route({ 69 + method: 'GET', 70 + operationId: 'getPosts', 71 + path: '/posts', 72 + summary: 'Get all posts', 73 + tags: ['posts'] 74 + }).input(vGetPostsData).output(vGetPostsResponse); 75 + 76 + /** 77 + * Create a new post 78 + */ 79 + export const createPostRpc = base.route({ 80 + method: 'POST', 81 + operationId: 'createPost', 82 + path: '/posts', 83 + successStatus: 201, 84 + summary: 'Create a new post', 85 + tags: ['posts'] 86 + }).input(vCreatePostData).output(vCreatePostResponse); 87 + 88 + /** 89 + * Get a post by ID 90 + */ 91 + export const getPostByIdRpc = base.route({ 92 + method: 'GET', 93 + operationId: 'getPostById', 94 + path: '/posts/{postId}', 95 + summary: 'Get a post by ID', 96 + tags: ['posts'] 97 + }).input(vGetPostByIdData).output(vGetPostByIdResponse); 98 + 99 + export const rpcContract = { 100 + getUsersRpc, 101 + createUserRpc, 102 + deleteUserRpc, 103 + getUserByIdRpc, 104 + updateUserRpc, 105 + getPostsRpc, 106 + createPostRpc, 107 + getPostByIdRpc 108 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/custom-names/valibot.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as v from 'valibot'; 4 + 5 + export const vUser = v.object({ 6 + id: v.string(), 7 + email: v.pipe(v.string(), v.email()), 8 + name: v.string(), 9 + createdAt: v.optional(v.pipe(v.string(), v.isoTimestamp())) 10 + }); 11 + 12 + export const vCreateUserInput = v.object({ 13 + email: v.pipe(v.string(), v.email()), 14 + name: v.string(), 15 + password: v.optional(v.pipe(v.string(), v.minLength(8))) 16 + }); 17 + 18 + export const vUpdateUserInput = v.object({ 19 + email: v.optional(v.pipe(v.string(), v.email())), 20 + name: v.optional(v.string()) 21 + }); 22 + 23 + export const vPost = v.object({ 24 + id: v.string(), 25 + title: v.string(), 26 + content: v.string(), 27 + authorId: v.string(), 28 + status: v.optional(v.picklist([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ])), 33 + createdAt: v.optional(v.pipe(v.string(), v.isoTimestamp())) 34 + }); 35 + 36 + export const vCreatePostInput = v.object({ 37 + title: v.string(), 38 + content: v.string(), 39 + status: v.optional(v.picklist(['draft', 'published'])) 40 + }); 41 + 42 + export const vGetUsersData = v.object({ 43 + body: v.optional(v.never()), 44 + path: v.optional(v.never()), 45 + query: v.optional(v.object({ 46 + limit: v.optional(v.pipe(v.number(), v.integer()), 10), 47 + offset: v.optional(v.pipe(v.number(), v.integer()), 0) 48 + })) 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const vGetUsersResponse = v.array(vUser); 55 + 56 + export const vCreateUserData = v.object({ 57 + body: vCreateUserInput, 58 + path: v.optional(v.never()), 59 + query: v.optional(v.never()) 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const vCreateUserResponse = vUser; 66 + 67 + export const vDeleteUserData = v.object({ 68 + body: v.optional(v.never()), 69 + path: v.object({ 70 + userId: v.string() 71 + }), 72 + query: v.optional(v.never()), 73 + headers: v.optional(v.object({ 74 + 'X-Request-Id': v.optional(v.string()) 75 + })) 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const vDeleteUserResponse = v.void(); 82 + 83 + export const vGetUserByIdData = v.object({ 84 + body: v.optional(v.never()), 85 + path: v.object({ 86 + userId: v.string() 87 + }), 88 + query: v.optional(v.never()) 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const vGetUserByIdResponse = vUser; 95 + 96 + export const vUpdateUserData = v.object({ 97 + body: vUpdateUserInput, 98 + path: v.object({ 99 + userId: v.string() 100 + }), 101 + query: v.optional(v.never()) 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const vUpdateUserResponse = vUser; 108 + 109 + export const vGetPostsData = v.object({ 110 + body: v.optional(v.never()), 111 + path: v.optional(v.never()), 112 + query: v.optional(v.object({ 113 + authorId: v.optional(v.string()), 114 + status: v.optional(v.picklist([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ])) 119 + })) 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const vGetPostsResponse = v.array(vPost); 126 + 127 + export const vCreatePostData = v.object({ 128 + body: vCreatePostInput, 129 + path: v.optional(v.never()), 130 + query: v.optional(v.never()), 131 + headers: v.object({ 132 + 'X-Author-Id': v.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const vCreatePostResponse = vPost; 140 + 141 + export const vGetPostByIdData = v.object({ 142 + body: v.optional(v.never()), 143 + path: v.object({ 144 + postId: v.string() 145 + }), 146 + query: v.optional(v.object({ 147 + includeComments: v.optional(v.boolean(), false) 148 + })) 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const vGetPostByIdResponse = vPost;
+108
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/default/orpc.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { oc } from '@orpc/contract'; 4 + 5 + import { zCreatePostData, zCreatePostResponse, zCreateUserData, zCreateUserResponse, zDeleteUserData, zGetPostByIdData, zGetPostByIdResponse, zGetPostsData, zGetPostsResponse, zGetUserByIdData, zGetUserByIdResponse, zGetUsersData, zGetUsersResponse, zUpdateUserData, zUpdateUserResponse } from './zod.gen'; 6 + 7 + export const base = oc.$route({ inputStructure: 'detailed' }); 8 + 9 + /** 10 + * Get all users 11 + */ 12 + export const getUsers = base.route({ 13 + method: 'GET', 14 + operationId: 'getUsers', 15 + path: '/users', 16 + summary: 'Get all users', 17 + tags: ['users'] 18 + }).input(zGetUsersData).output(zGetUsersResponse); 19 + 20 + /** 21 + * Create a new user 22 + */ 23 + export const createUser = base.route({ 24 + method: 'POST', 25 + operationId: 'createUser', 26 + path: '/users', 27 + successStatus: 201, 28 + summary: 'Create a new user', 29 + tags: ['users'] 30 + }).input(zCreateUserData).output(zCreateUserResponse); 31 + 32 + /** 33 + * Delete a user 34 + */ 35 + export const deleteUser = base.route({ 36 + method: 'DELETE', 37 + operationId: 'deleteUser', 38 + path: '/users/{userId}', 39 + summary: 'Delete a user', 40 + tags: ['users'] 41 + }).input(zDeleteUserData); 42 + 43 + /** 44 + * Get a user by ID 45 + */ 46 + export const getUserById = base.route({ 47 + method: 'GET', 48 + operationId: 'getUserById', 49 + path: '/users/{userId}', 50 + summary: 'Get a user by ID', 51 + tags: ['users'] 52 + }).input(zGetUserByIdData).output(zGetUserByIdResponse); 53 + 54 + /** 55 + * Update a user 56 + */ 57 + export const updateUser = base.route({ 58 + method: 'PUT', 59 + operationId: 'updateUser', 60 + path: '/users/{userId}', 61 + summary: 'Update a user', 62 + tags: ['users'] 63 + }).input(zUpdateUserData).output(zUpdateUserResponse); 64 + 65 + /** 66 + * Get all posts 67 + */ 68 + export const getPosts = base.route({ 69 + method: 'GET', 70 + operationId: 'getPosts', 71 + path: '/posts', 72 + summary: 'Get all posts', 73 + tags: ['posts'] 74 + }).input(zGetPostsData).output(zGetPostsResponse); 75 + 76 + /** 77 + * Create a new post 78 + */ 79 + export const createPost = base.route({ 80 + method: 'POST', 81 + operationId: 'createPost', 82 + path: '/posts', 83 + successStatus: 201, 84 + summary: 'Create a new post', 85 + tags: ['posts'] 86 + }).input(zCreatePostData).output(zCreatePostResponse); 87 + 88 + /** 89 + * Get a post by ID 90 + */ 91 + export const getPostById = base.route({ 92 + method: 'GET', 93 + operationId: 'getPostById', 94 + path: '/posts/{postId}', 95 + summary: 'Get a post by ID', 96 + tags: ['posts'] 97 + }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 + 99 + export const contract = { 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 + };
+154
packages/openapi-ts-tests/orpc/v1/__snapshots__/3.1.x/default/zod.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import * as z from 'zod'; 4 + 5 + export const zUser = z.object({ 6 + id: z.string(), 7 + email: z.email(), 8 + name: z.string(), 9 + createdAt: z.iso.datetime().optional() 10 + }); 11 + 12 + export const zCreateUserInput = z.object({ 13 + email: z.email(), 14 + name: z.string(), 15 + password: z.string().min(8).optional() 16 + }); 17 + 18 + export const zUpdateUserInput = z.object({ 19 + email: z.email().optional(), 20 + name: z.string().optional() 21 + }); 22 + 23 + export const zPost = z.object({ 24 + id: z.string(), 25 + title: z.string(), 26 + content: z.string(), 27 + authorId: z.string(), 28 + status: z.enum([ 29 + 'draft', 30 + 'published', 31 + 'archived' 32 + ]).optional(), 33 + createdAt: z.iso.datetime().optional() 34 + }); 35 + 36 + export const zCreatePostInput = z.object({ 37 + title: z.string(), 38 + content: z.string(), 39 + status: z.enum(['draft', 'published']).optional() 40 + }); 41 + 42 + export const zGetUsersData = z.object({ 43 + body: z.never().optional(), 44 + path: z.never().optional(), 45 + query: z.object({ 46 + limit: z.int().optional().default(10), 47 + offset: z.int().optional().default(0) 48 + }).optional() 49 + }); 50 + 51 + /** 52 + * List of users 53 + */ 54 + export const zGetUsersResponse = z.array(zUser); 55 + 56 + export const zCreateUserData = z.object({ 57 + body: zCreateUserInput, 58 + path: z.never().optional(), 59 + query: z.never().optional() 60 + }); 61 + 62 + /** 63 + * User created 64 + */ 65 + export const zCreateUserResponse = zUser; 66 + 67 + export const zDeleteUserData = z.object({ 68 + body: z.never().optional(), 69 + path: z.object({ 70 + userId: z.string() 71 + }), 72 + query: z.never().optional(), 73 + headers: z.object({ 74 + 'X-Request-Id': z.string().optional() 75 + }).optional() 76 + }); 77 + 78 + /** 79 + * User deleted 80 + */ 81 + export const zDeleteUserResponse = z.void(); 82 + 83 + export const zGetUserByIdData = z.object({ 84 + body: z.never().optional(), 85 + path: z.object({ 86 + userId: z.string() 87 + }), 88 + query: z.never().optional() 89 + }); 90 + 91 + /** 92 + * User found 93 + */ 94 + export const zGetUserByIdResponse = zUser; 95 + 96 + export const zUpdateUserData = z.object({ 97 + body: zUpdateUserInput, 98 + path: z.object({ 99 + userId: z.string() 100 + }), 101 + query: z.never().optional() 102 + }); 103 + 104 + /** 105 + * User updated 106 + */ 107 + export const zUpdateUserResponse = zUser; 108 + 109 + export const zGetPostsData = z.object({ 110 + body: z.never().optional(), 111 + path: z.never().optional(), 112 + query: z.object({ 113 + authorId: z.string().optional(), 114 + status: z.enum([ 115 + 'draft', 116 + 'published', 117 + 'archived' 118 + ]).optional() 119 + }).optional() 120 + }); 121 + 122 + /** 123 + * List of posts 124 + */ 125 + export const zGetPostsResponse = z.array(zPost); 126 + 127 + export const zCreatePostData = z.object({ 128 + body: zCreatePostInput, 129 + path: z.never().optional(), 130 + query: z.never().optional(), 131 + headers: z.object({ 132 + 'X-Author-Id': z.string() 133 + }) 134 + }); 135 + 136 + /** 137 + * Post created 138 + */ 139 + export const zCreatePostResponse = zPost; 140 + 141 + export const zGetPostByIdData = z.object({ 142 + body: z.never().optional(), 143 + path: z.object({ 144 + postId: z.string() 145 + }), 146 + query: z.object({ 147 + includeComments: z.boolean().optional().default(false) 148 + }).optional() 149 + }); 150 + 151 + /** 152 + * Post found 153 + */ 154 + export const zGetPostByIdResponse = zPost;
+19
packages/openapi-ts-tests/orpc/v1/package.json
··· 1 + { 2 + "name": "@test/openapi-ts-orpc-v1", 3 + "version": "0.0.0", 4 + "private": true, 5 + "type": "module", 6 + "scripts": { 7 + "typecheck": "tsgo --noEmit" 8 + }, 9 + "devDependencies": { 10 + "@hey-api/openapi-ts": "workspace:*", 11 + "@orpc/contract": "1.13.4", 12 + "typescript": "5.9.3", 13 + "valibot": "1.2.0", 14 + "zod": "4.3.6" 15 + }, 16 + "engines": { 17 + "node": ">=20.19.0" 18 + } 19 + }
+60
packages/openapi-ts-tests/orpc/v1/test/3.0.x.test.ts
··· 1 + import fs from 'node:fs'; 2 + import path from 'node:path'; 3 + 4 + import { createClient } from '@hey-api/openapi-ts'; 5 + 6 + import { getFilePaths } from '../../../utils'; 7 + import { snapshotsDir, tmpDir } from './constants'; 8 + import { createOrpcConfig } from './utils'; 9 + 10 + const version = '3.0.x'; 11 + 12 + const outputDir = path.join(tmpDir, version); 13 + 14 + describe(`OpenAPI ${version}`, () => { 15 + const createConfig = createOrpcConfig({ openApiVersion: version, outputDir }); 16 + 17 + const scenarios = [ 18 + { 19 + config: createConfig({ 20 + input: 'orpc.yaml', 21 + output: 'default', 22 + plugins: ['orpc', 'zod'], 23 + }), 24 + description: 'generate oRPC contracts with Zod schemas', 25 + }, 26 + { 27 + config: createConfig({ 28 + input: 'orpc.yaml', 29 + output: 'custom-names', 30 + plugins: [ 31 + 'valibot', 32 + { 33 + contracts: { 34 + containerName: 'rpcContract', 35 + contractName: '{{name}}Rpc', 36 + }, 37 + name: 'orpc', 38 + }, 39 + ], 40 + }), 41 + description: 'generate oRPC contracts with custom names and Valibot schemas', 42 + }, 43 + ]; 44 + 45 + it.each(scenarios)('$description', async ({ config }) => { 46 + await createClient(config); 47 + 48 + const outputString = config.output as string; 49 + const filePaths = getFilePaths(outputString); 50 + 51 + await Promise.all( 52 + filePaths.map(async (filePath) => { 53 + const fileContent = fs.readFileSync(filePath, 'utf-8'); 54 + await expect(fileContent).toMatchFileSnapshot( 55 + path.join(snapshotsDir, version, filePath.slice(outputDir.length + 1)), 56 + ); 57 + }), 58 + ); 59 + }); 60 + });
+128
packages/openapi-ts-tests/orpc/v1/test/3.1.x.test.ts
··· 1 + import fs from 'node:fs'; 2 + import path from 'node:path'; 3 + 4 + import { createClient } from '@hey-api/openapi-ts'; 5 + 6 + import { getFilePaths } from '../../../utils'; 7 + import { snapshotsDir, tmpDir } from './constants'; 8 + import { createOrpcConfig } from './utils'; 9 + 10 + const version = '3.1.x'; 11 + 12 + const outputDir = path.join(tmpDir, version); 13 + 14 + describe(`OpenAPI ${version}`, () => { 15 + const createConfig = createOrpcConfig({ openApiVersion: version, outputDir }); 16 + 17 + const scenarios = [ 18 + { 19 + config: createConfig({ 20 + input: 'orpc.yaml', 21 + output: 'default', 22 + plugins: ['orpc', 'zod'], 23 + }), 24 + description: 'generate oRPC contracts with Zod schemas', 25 + }, 26 + { 27 + config: createConfig({ 28 + input: 'orpc.yaml', 29 + output: 'custom-names', 30 + plugins: [ 31 + 'valibot', 32 + { 33 + contracts: { 34 + containerName: 'rpcContract', 35 + contractName: '{{name}}Rpc', 36 + }, 37 + name: 'orpc', 38 + }, 39 + ], 40 + }), 41 + description: 'generate oRPC contracts with custom names and Valibot schemas', 42 + }, 43 + { 44 + config: createConfig({ 45 + input: 'orpc.yaml', 46 + output: 'contracts-strategy-by-tags', 47 + plugins: [ 48 + 'zod', 49 + { 50 + contracts: { 51 + strategy: 'byTags', 52 + }, 53 + name: 'orpc', 54 + }, 55 + ], 56 + }), 57 + description: 'generate oRPC contracts grouped by tags', 58 + }, 59 + { 60 + config: createConfig({ 61 + input: 'orpc.yaml', 62 + output: 'contracts-strategy-single', 63 + plugins: [ 64 + 'zod', 65 + { 66 + contracts: { 67 + containerName: 'api', 68 + strategy: 'single', 69 + }, 70 + name: 'orpc', 71 + }, 72 + ], 73 + }), 74 + description: 'generate oRPC contracts in a single container', 75 + }, 76 + { 77 + config: createConfig({ 78 + input: 'orpc.yaml', 79 + output: 'contracts-nesting-id', 80 + plugins: [ 81 + 'zod', 82 + { 83 + contracts: { 84 + nesting: 'id', 85 + strategy: 'byTags', 86 + }, 87 + name: 'orpc', 88 + }, 89 + ], 90 + }), 91 + description: 'generate oRPC contracts without operationId nesting', 92 + }, 93 + { 94 + config: createConfig({ 95 + input: 'orpc.yaml', 96 + output: 'contracts-custom-naming', 97 + plugins: [ 98 + 'zod', 99 + { 100 + contracts: { 101 + containerName: '{{name}}Contracts', 102 + contractName: { casing: 'PascalCase' }, 103 + segmentName: { casing: 'PascalCase' }, 104 + strategy: 'byTags', 105 + }, 106 + name: 'orpc', 107 + }, 108 + ], 109 + }), 110 + description: 'generate oRPC contracts with custom naming', 111 + }, 112 + ]; 113 + 114 + it.each(scenarios)('$description', async ({ config }) => { 115 + await createClient(config); 116 + 117 + const filePaths = getFilePaths(config.output as string); 118 + 119 + await Promise.all( 120 + filePaths.map(async (filePath) => { 121 + const fileContent = fs.readFileSync(filePath, 'utf-8'); 122 + await expect(fileContent).toMatchFileSnapshot( 123 + path.join(snapshotsDir, version, filePath.slice(outputDir.length + 1)), 124 + ); 125 + }), 126 + ); 127 + }); 128 + });
+4
packages/openapi-ts-tests/orpc/v1/test/constants.ts
··· 1 + import path from 'node:path'; 2 + 3 + export const snapshotsDir = path.join(__dirname, '..', '__snapshots__'); 4 + export const tmpDir = path.join(__dirname, '..', '.tmp');
+7
packages/openapi-ts-tests/orpc/v1/test/globalTeardown.ts
··· 1 + import fs from 'node:fs'; 2 + 3 + import { tmpDir } from './constants'; 4 + 5 + export function teardown() { 6 + fs.rmSync(tmpDir, { force: true, recursive: true }); 7 + }
+31
packages/openapi-ts-tests/orpc/v1/test/utils.ts
··· 1 + import path from 'node:path'; 2 + 3 + import type { UserConfig } from '@hey-api/openapi-ts'; 4 + 5 + import { getSpecsPath } from '../../../utils'; 6 + 7 + export const createOrpcConfig = 8 + ({ openApiVersion, outputDir }: { openApiVersion: string; outputDir: string }) => 9 + (userConfig: UserConfig) => { 10 + const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; 11 + const inputPath = path.join( 12 + getSpecsPath(), 13 + openApiVersion, 14 + typeof input === 'string' ? input : (input.path as string), 15 + ); 16 + const output = userConfig.output instanceof Array ? userConfig.output[0]! : userConfig.output; 17 + const outputPath = typeof output === 'string' ? output : (output?.path ?? ''); 18 + return { 19 + plugins: ['orpc'], 20 + ...userConfig, 21 + input: 22 + typeof userConfig.input === 'string' 23 + ? inputPath 24 + : { 25 + ...userConfig.input, 26 + path: inputPath, 27 + }, 28 + logs: { level: 'silent', path: './logs' }, 29 + output: path.join(outputDir, outputPath), 30 + } as UserConfig; 31 + };
+5
packages/openapi-ts-tests/orpc/v1/tsconfig.json
··· 1 + { 2 + "extends": "../../tsconfig.base.json", 3 + "include": ["test/**/*", "__snapshots__/**/*"], 4 + "references": [{ "path": "../../../openapi-ts" }] 5 + }
+10
packages/openapi-ts-tests/orpc/v1/turbo.json
··· 1 + { 2 + "$schema": "../../../../node_modules/turbo/schema.json", 3 + "extends": ["//"], 4 + "tasks": { 5 + "build": { 6 + "dependsOn": [], 7 + "outputs": ["dist/**"] 8 + } 9 + } 10 + }
+7
packages/openapi-ts-tests/orpc/v1/vitest.setup.ts
··· 1 + import { fileURLToPath } from 'node:url'; 2 + 3 + import { beforeAll } from 'vitest'; 4 + 5 + beforeAll(() => { 6 + process.chdir(fileURLToPath(new URL('.', import.meta.url))); 7 + });
+4 -9
packages/openapi-ts-tests/sdks/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+4 -9
packages/openapi-ts-tests/valibot/v1/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+4 -9
packages/openapi-ts-tests/zod/v3/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+4 -9
packages/openapi-ts-tests/zod/v4/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 14 - dist 9 + .env 15 10 coverage 16 - .env 11 + dist 17 12 18 13 # test files 19 - .gen/ 14 + .gen
+6
packages/openapi-ts/src/index.ts
··· 81 81 arktype: Plugins.Arktype.Types['Types']; 82 82 fastify: Plugins.Fastify.Types['Types']; 83 83 nestjs: Plugins.NestJs.Types['Types']; 84 + orpc: Plugins.Orpc.Types['Types']; 84 85 swr: Plugins.Swr.Types['Types']; 85 86 valibot: Plugins.Valibot.Types['Types']; 86 87 zod: Plugins.Zod.Types['Types']; ··· 142 143 import type { ArktypePlugin } from './plugins/arktype'; 143 144 import type { FastifyPlugin } from './plugins/fastify'; 144 145 import type { NestJsPlugin } from './plugins/nestjs'; 146 + import type { OrpcPlugin } from './plugins/orpc'; 145 147 import type { SwrPlugin } from './plugins/swr'; 146 148 import type { ValibotPlugin, ValibotResolvers } from './plugins/valibot'; 147 149 import type { ZodPlugin, ZodResolvers } from './plugins/zod'; ··· 264 266 265 267 export namespace NestJs { 266 268 export type Types = NestJsPlugin; 269 + } 270 + 271 + export namespace Orpc { 272 + export type Types = OrpcPlugin; 267 273 } 268 274 269 275 export namespace PiniaColada {
+1 -1
packages/openapi-ts/src/plugins/@hey-api/client-core/utils.ts
··· 1 1 import type { Config } from '../../../config/types'; 2 - import type { PluginClientNames } from '../../../plugins/types'; 2 + import type { PluginClientNames } from '../../types'; 3 3 4 4 export function getClientBaseUrlKey(config: Config) { 5 5 const client = getClientPlugin(config);
+2 -2
packages/openapi-ts/src/plugins/@hey-api/sdk/operations/config.ts
··· 1 1 import { log } from '@hey-api/codegen-core'; 2 - import type { OperationsStrategy, PluginContext } from '@hey-api/shared'; 2 + import type { PluginContext } from '@hey-api/shared'; 3 3 4 4 import type { UserConfig } from '../types'; 5 5 import type { OperationsConfig, UserOperationsConfig } from './types'; ··· 60 60 } 61 61 62 62 function normalizeConfig( 63 - input: OperationsStrategy | UserOperationsConfig | undefined, 63 + input: Config['operations'], 64 64 legacy: Partial<OperationsConfig>, 65 65 context: PluginContext, 66 66 ): OperationsConfig {
+11 -72
packages/openapi-ts/src/plugins/@hey-api/sdk/operations/types.ts
··· 16 16 * @default 'class' 17 17 */ 18 18 container?: 'class'; 19 - // * - `'object'` - Plain object literal 19 + // * - `'object'` - Object with properties 20 20 // container?: 'class' | 'object'; 21 21 /** 22 22 * Customize container names. ··· 102 102 } 103 103 104 104 export interface OperationsConfig { 105 - /** 106 - * Type of container for grouped operations. 107 - * 108 - * Ignored when `strategy` is `'flat'`. 109 - * 110 - * - `'class'` - Class with methods 111 - */ 105 + /** Type of container for grouped operations. */ 112 106 container: 'class'; 113 - // * - `'object'` - Plain object literal 107 + // * - `'object'` - Object with properties 114 108 // container: 'class' | 'object'; 115 - /** 116 - * Customize container names. 117 - * 118 - * For `'single'` strategy, this sets the root container name. 119 - * For `'byTags'` strategy, this transforms tag names. 120 - * 121 - * @default 'Sdk' for `'single'` strategy 122 - * 123 - * @example 124 - * // Set root name for single strategy 125 - * containerName: 'MyApi' 126 - * 127 - * @example 128 - * // Transform tag names with suffix 129 - * containerName: '{{name}}Service' 130 - * 131 - * @example 132 - * // With casing 133 - * containerName: { name: '{{name}}Service', case: 'PascalCase' } 134 - */ 109 + /** Customize container names. */ 135 110 containerName: NamingConfig; 136 - /** 137 - * Customize method/function names. 138 - * 139 - * Applied to the final segment of the path (the method name). 140 - */ 111 + /** Customize method/function names. */ 141 112 methodName: NamingConfig; 142 - /** 143 - * How methods are attached to class containers. 144 - * 145 - * Only applies when `container` is `'class'`. 146 - * 147 - * - `'static'` - Static methods, no instantiation required 148 - * - `'instance'` - Instance methods, requires `new ClassName(config)` 149 - */ 113 + /** How methods are attached to class containers. */ 150 114 methods: 'instance' | 'static'; 151 - /** 152 - * How to derive nesting structure from operations. 153 - * 154 - * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 155 - * - `'id'` - Use operation id as-is, no nesting 156 - * - Custom function for full control 157 - */ 115 + /** How to derive nesting structure from operations. */ 158 116 nesting: 'operationId' | 'id' | OperationPathStrategy; 159 - /** 160 - * Delimiters for splitting operationId. 161 - * 162 - * Only applies when `nesting` is `'operationId'`. 163 - */ 117 + /** Delimiters for splitting operationId. */ 164 118 nestingDelimiters: RegExp; 165 - /** 166 - * Customize nesting segment names. 167 - * 168 - * Applied to intermediate path segments (not the method name). 169 - */ 119 + /** Customize nesting segment names. */ 170 120 segmentName: NamingConfig; 171 - /** 172 - * Grouping strategy. 173 - * 174 - * - `'flat'` - Standalone functions, no grouping 175 - * - `'byTags'` - One container per operation tag 176 - * - `'single'` - All operations in one container 177 - * - Custom function for full control 178 - */ 121 + /** Grouping strategy. */ 179 122 strategy: OperationsStrategy; 180 - /** 181 - * Default container name for operations without tags. 182 - * 183 - * Only applies when `strategy` is `'byTags'`. 184 - */ 123 + /** Default container name for operations without tags. */ 185 124 strategyDefaultTag: string; 186 125 }
+3 -11
packages/openapi-ts/src/plugins/@hey-api/sdk/types.ts
··· 1 1 import type { DefinePlugin, NameTransformer, OperationsStrategy, Plugin } from '@hey-api/shared'; 2 2 3 - import type { 4 - PluginClientNames, 5 - PluginTransformerNames, 6 - PluginValidatorNames, 7 - } from '../../../plugins/types'; 3 + import type { PluginClientNames, PluginTransformerNames, PluginValidatorNames } from '../../types'; 8 4 import type { ExamplesConfig, UserExamplesConfig } from './examples'; 9 5 import type { OperationsConfig, UserOperationsConfig } from './operations'; 10 6 ··· 219 215 * @default true 220 216 */ 221 217 client: PluginClientNames | false; 222 - /** 223 - * Configuration for generating SDK code examples. 224 - */ 218 + /** Configuration for generating SDK code examples. */ 225 219 examples: ExamplesConfig; 226 - /** 227 - * Define the structure of generated SDK operations. 228 - */ 220 + /** Define the structure of generated SDK operations. */ 229 221 operations: OperationsConfig; 230 222 /** 231 223 * Define how request parameters are structured in generated SDK methods.
+2
packages/openapi-ts/src/plugins/config.ts
··· 23 23 import { defaultConfig as arktype } from '../plugins/arktype'; 24 24 import { defaultConfig as fastify } from '../plugins/fastify'; 25 25 import { defaultConfig as nestjs } from '../plugins/nestjs'; 26 + import { defaultConfig as orpc } from '../plugins/orpc'; 26 27 import { defaultConfig as swr } from '../plugins/swr'; 27 28 import { defaultConfig as valibot } from '../plugins/valibot'; 28 29 import { defaultConfig as zod } from '../plugins/zod'; ··· 53 54 arktype, 54 55 fastify, 55 56 nestjs, 57 + orpc, 56 58 swr, 57 59 valibot, 58 60 zod,
+76
packages/openapi-ts/src/plugins/orpc/config.ts
··· 1 + import { log } from '@hey-api/codegen-core'; 2 + import { definePluginConfig } from '@hey-api/shared'; 3 + 4 + import { resolveContracts } from './contracts/config'; 5 + import { handler } from './plugin'; 6 + import type { OrpcPlugin } from './types'; 7 + 8 + const validatorInferWarn = 9 + 'You set `validator: true` but no validator plugin was found in your plugins. Add a validator plugin like `zod` to enable this feature. The validator option has been disabled.'; 10 + 11 + export const defaultConfig: OrpcPlugin['Config'] = { 12 + config: { 13 + includeInEntry: false, 14 + }, 15 + handler, 16 + name: 'orpc', 17 + resolveConfig: (plugin, context) => { 18 + if (typeof plugin.config.validator !== 'object') { 19 + plugin.config.validator = { 20 + input: plugin.config.validator, 21 + output: plugin.config.validator, 22 + }; 23 + } 24 + 25 + if (plugin.config.validator.input || plugin.config.validator.input === undefined) { 26 + if ( 27 + typeof plugin.config.validator.input === 'boolean' || 28 + plugin.config.validator.input === undefined 29 + ) { 30 + try { 31 + plugin.config.validator.input = context.pluginByTag('validator'); 32 + plugin.dependencies.add(plugin.config.validator.input!); 33 + } catch { 34 + // avoid showing the warning with default configuration as it would be confusing 35 + if (plugin.config.validator.input !== undefined) { 36 + log.warn(validatorInferWarn); 37 + } 38 + plugin.config.validator.input = false; 39 + } 40 + } else { 41 + plugin.dependencies.add(plugin.config.validator.input); 42 + } 43 + } else { 44 + plugin.config.validator.input = false; 45 + } 46 + 47 + if (plugin.config.validator.output || plugin.config.validator.output === undefined) { 48 + if ( 49 + typeof plugin.config.validator.output === 'boolean' || 50 + plugin.config.validator.output === undefined 51 + ) { 52 + try { 53 + plugin.config.validator.output = context.pluginByTag('validator'); 54 + plugin.dependencies.add(plugin.config.validator.output!); 55 + } catch { 56 + // avoid showing the warning with default configuration as it would be confusing 57 + if (plugin.config.validator.output !== undefined) { 58 + log.warn(validatorInferWarn); 59 + } 60 + plugin.config.validator.output = false; 61 + } 62 + } else { 63 + plugin.dependencies.add(plugin.config.validator.output); 64 + } 65 + } else { 66 + plugin.config.validator.output = false; 67 + } 68 + 69 + plugin.config.contracts = resolveContracts(plugin.config, context); 70 + }, 71 + }; 72 + 73 + /** 74 + * Type helper for oRPC plugin, returns {@link Plugin.Config} object 75 + */ 76 + export const defineConfig = definePluginConfig(defaultConfig);
+61
packages/openapi-ts/src/plugins/orpc/contracts/config.ts
··· 1 + import type { PluginContext } from '@hey-api/shared'; 2 + 3 + import type { UserConfig } from '../types'; 4 + import type { ContractsConfig } from './types'; 5 + 6 + type Config = Omit<UserConfig, 'name'>; 7 + 8 + export function resolveContracts(config: Config, context: PluginContext): ContractsConfig { 9 + return normalizeConfig(config.contracts, context); 10 + } 11 + 12 + function normalizeConfig(input: Config['contracts'], context: PluginContext): ContractsConfig { 13 + if (!input || typeof input === 'string' || typeof input === 'function') { 14 + input = { strategy: input }; 15 + } 16 + 17 + const strategy = input.strategy ?? 'single'; 18 + 19 + return context.valueToObject({ 20 + defaultValue: { 21 + container: 'object', 22 + nesting: 'operationId', 23 + nestingDelimiters: /[./]/, 24 + strategy, 25 + strategyDefaultTag: 'default', 26 + }, 27 + mappers: { 28 + object(value) { 29 + value.containerName = context.valueToObject({ 30 + defaultValue: 31 + strategy === 'single' 32 + ? { casing: 'camelCase', name: 'contract' } 33 + : { casing: 'camelCase' }, 34 + mappers: { 35 + function: (name) => ({ name }), 36 + string: (name) => ({ name }), 37 + }, 38 + value: value.containerName, 39 + }); 40 + value.contractName = context.valueToObject({ 41 + defaultValue: { casing: 'camelCase' }, 42 + mappers: { 43 + function: (name) => ({ name }), 44 + string: (name) => ({ name }), 45 + }, 46 + value: value.contractName, 47 + }); 48 + value.segmentName = context.valueToObject({ 49 + defaultValue: { casing: 'camelCase' }, 50 + mappers: { 51 + function: (name) => ({ name }), 52 + string: (name) => ({ name }), 53 + }, 54 + value: value.segmentName, 55 + }); 56 + return value; 57 + }, 58 + }, 59 + value: input, 60 + }) as ContractsConfig; 61 + }
+4
packages/openapi-ts/src/plugins/orpc/contracts/index.ts
··· 1 + export { resolveContracts } from './config'; 2 + export { type ContractItem, createShell, source, toNode } from './node'; 3 + export { resolveStrategy } from './resolve'; 4 + export type { ContractsConfig, UserContractsConfig } from './types';
+218
packages/openapi-ts/src/plugins/orpc/contracts/node.ts
··· 1 + import type { 2 + StructureItem, 3 + StructureNode, 4 + StructureShell, 5 + Symbol, 6 + SymbolMeta, 7 + } from '@hey-api/codegen-core'; 8 + import type { IR } from '@hey-api/shared'; 9 + import { applyNaming } from '@hey-api/shared'; 10 + 11 + import { $ } from '../../../ts-dsl'; 12 + import { createOperationComment } from '../../shared/utils/operation'; 13 + import { getSuccessResponse, getTags, hasInput } from '../shared/operation'; 14 + import type { OrpcPlugin } from '../types'; 15 + 16 + export interface ContractItem { 17 + operation: IR.OperationObject; 18 + path: ReadonlyArray<string | number>; 19 + tags: ReadonlyArray<string> | undefined; 20 + } 21 + 22 + export const source = globalThis.Symbol('orpc'); 23 + 24 + function createShellMeta(node: StructureNode): SymbolMeta { 25 + return { 26 + category: 'contract', 27 + resource: 'container', 28 + resourceId: node.getPath().join('.'), 29 + tool: 'orpc', 30 + }; 31 + } 32 + 33 + function createContractSymbol( 34 + plugin: OrpcPlugin['Instance'], 35 + item: StructureItem & { data: ContractItem }, 36 + ): Symbol { 37 + const { operation, path, tags } = item.data; 38 + const name = item.location[item.location.length - 1]!; 39 + return plugin.symbol(applyNaming(name, plugin.config.contracts.contractName), { 40 + meta: { 41 + category: 'contract', 42 + path, 43 + resource: 'operation', 44 + resourceId: operation.id, 45 + role: 'contract', 46 + tags, 47 + tool: plugin.name, 48 + }, 49 + }); 50 + } 51 + 52 + function createContractExpression( 53 + plugin: OrpcPlugin['Instance'], 54 + operation: IR.OperationObject, 55 + baseSymbol: Symbol, 56 + ) { 57 + const successResponse = getSuccessResponse(operation); 58 + const tags = getTags(operation, plugin.config.contracts.strategyDefaultTag); 59 + 60 + let expression = $(baseSymbol) 61 + .attr('route') 62 + .call( 63 + $.object() 64 + .$if(operation.deprecated, (o, v) => o.prop('deprecated', $.literal(v))) 65 + .$if(operation.description, (o, v) => o.prop('description', $.literal(v))) 66 + .prop('method', $.literal(operation.method.toUpperCase())) 67 + .$if(operation.operationId, (o, v) => o.prop('operationId', $.literal(v))) 68 + .prop('path', $.literal(operation.path)) 69 + .$if( 70 + successResponse.hasOutput && 71 + successResponse.statusCode !== 200 && 72 + successResponse.statusCode, 73 + (o, v) => o.prop('successStatus', $.literal(v)), 74 + ) 75 + .$if(operation.summary, (o, v) => o.prop('summary', $.literal(v))) 76 + .$if(tags.length > 0 && tags, (o, v) => o.prop('tags', $.fromValue(v))), 77 + ); 78 + 79 + if (hasInput(operation) && plugin.config.validator.input) { 80 + expression = expression.attr('input').call( 81 + plugin.referenceSymbol({ 82 + category: 'schema', 83 + resource: 'operation', 84 + resourceId: operation.id, 85 + role: 'data', 86 + tool: plugin.config.validator.input, 87 + }), 88 + ); 89 + } 90 + 91 + if (successResponse.hasOutput && plugin.config.validator.output) { 92 + expression = expression.attr('output').call( 93 + plugin.referenceSymbol({ 94 + category: 'schema', 95 + resource: 'operation', 96 + resourceId: operation.id, 97 + role: 'responses', 98 + tool: plugin.config.validator.output, 99 + }), 100 + ); 101 + } 102 + 103 + return expression; 104 + } 105 + 106 + function buildContainerObject( 107 + node: StructureNode, 108 + plugin: OrpcPlugin['Instance'], 109 + symbols: Map<string, Symbol>, 110 + ): ReturnType<typeof $.object> { 111 + const obj = $.object(); 112 + 113 + for (const item of node.itemsFrom<ContractItem>(source)) { 114 + const { operation } = item.data; 115 + const contractSymbol = symbols.get(operation.id)!; 116 + const name = item.location[item.location.length - 1]!; 117 + const propName = applyNaming(name, plugin.config.contracts.contractName); 118 + obj.prop(propName, contractSymbol); 119 + } 120 + 121 + for (const child of node.children.values()) { 122 + if (child.shell) { 123 + const childShell = child.shell.define(child); 124 + const childNode = childShell.node as ReturnType<typeof $.const>; 125 + const childSymbol = childNode.symbol; 126 + if (childSymbol) { 127 + const propName = applyNaming(child.name, plugin.config.contracts.segmentName); 128 + obj.prop(propName, childSymbol); 129 + } 130 + } 131 + } 132 + 133 + return obj; 134 + } 135 + 136 + export function createShell(plugin: OrpcPlugin['Instance']): StructureShell { 137 + const cache = new Map<string | number, ReturnType<typeof $.const>>(); 138 + 139 + return { 140 + define: (node) => { 141 + const resourceId = node.getPath().join('.'); 142 + const cached = cache.get(resourceId); 143 + if (cached) { 144 + return { dependencies: [], node: cached }; 145 + } 146 + const symbol = plugin.symbol( 147 + applyNaming( 148 + node.name, 149 + node.isRoot ? plugin.config.contracts.containerName : plugin.config.contracts.segmentName, 150 + ), 151 + { 152 + meta: createShellMeta(node), 153 + }, 154 + ); 155 + 156 + const o = $.const(symbol).export().assign($.object()); 157 + cache.set(resourceId, o); 158 + 159 + return { dependencies: [], node: o }; 160 + }, 161 + }; 162 + } 163 + 164 + export function toNode( 165 + model: StructureNode, 166 + plugin: OrpcPlugin['Instance'], 167 + baseSymbol: Symbol, 168 + ): { 169 + nodes: ReadonlyArray<ReturnType<typeof $.const>>; 170 + symbols?: Map<string, Symbol>; 171 + } { 172 + if (model.virtual) { 173 + const nodes: Array<ReturnType<typeof $.const>> = []; 174 + const symbols = new Map<string, Symbol>(); 175 + 176 + for (const item of model.itemsFrom<ContractItem>(source)) { 177 + const { operation } = item.data; 178 + const contractSymbol = createContractSymbol(plugin, item); 179 + const expression = createContractExpression(plugin, operation, baseSymbol); 180 + 181 + const node = $.const(contractSymbol) 182 + .export() 183 + .$if(createOperationComment(operation), (n, v) => n.doc(v)) 184 + .assign(expression); 185 + nodes.push(node); 186 + symbols.set(operation.id, contractSymbol); 187 + } 188 + return { nodes, symbols }; 189 + } 190 + 191 + if (!model.shell) { 192 + return { nodes: [] }; 193 + } 194 + 195 + const nodes: Array<ReturnType<typeof $.const>> = []; 196 + const symbols = new Map<string, Symbol>(); 197 + 198 + for (const item of model.itemsFrom<ContractItem>(source)) { 199 + const { operation } = item.data; 200 + const contractSymbol = createContractSymbol(plugin, item); 201 + const expression = createContractExpression(plugin, operation, baseSymbol); 202 + 203 + const node = $.const(contractSymbol) 204 + .export() 205 + .$if(createOperationComment(operation), (n, v) => n.doc(v)) 206 + .assign(expression); 207 + nodes.push(node); 208 + symbols.set(operation.id, contractSymbol); 209 + } 210 + 211 + const shell = model.shell.define(model); 212 + const containerSymbol = shell.node.symbol!; 213 + const obj = buildContainerObject(model, plugin, symbols); 214 + const containerNode = $.const(containerSymbol).export().assign(obj.pretty()); 215 + nodes.push(containerNode); 216 + 217 + return { nodes, symbols }; 218 + }
+44
packages/openapi-ts/src/plugins/orpc/contracts/resolve.ts
··· 1 + import type { OperationPathStrategy, OperationStructureStrategy } from '@hey-api/shared'; 2 + import { OperationPath, OperationStrategy } from '@hey-api/shared'; 3 + 4 + import type { OrpcPlugin } from '../types'; 5 + 6 + function resolvePath(plugin: OrpcPlugin['Instance']): OperationPathStrategy { 7 + if (plugin.config.contracts.nesting === 'id') { 8 + return OperationPath.id(); 9 + } 10 + 11 + if (plugin.config.contracts.nesting === 'operationId') { 12 + return OperationPath.fromOperationId({ 13 + delimiters: plugin.config.contracts.nestingDelimiters, 14 + fallback: OperationPath.id(), 15 + }); 16 + } 17 + 18 + return plugin.config.contracts.nesting; 19 + } 20 + 21 + export function resolveStrategy(plugin: OrpcPlugin['Instance']): OperationStructureStrategy { 22 + if (plugin.config.contracts.strategy === 'flat') { 23 + return OperationStrategy.flat({ 24 + path: (operation) => [resolvePath(plugin)(operation).join('.')], 25 + }); 26 + } 27 + 28 + if (plugin.config.contracts.strategy === 'single') { 29 + const root = plugin.config.contracts.containerName; 30 + return OperationStrategy.single({ 31 + path: resolvePath(plugin), 32 + root: typeof root.name === 'string' ? root.name : (root.name?.('') ?? ''), 33 + }); 34 + } 35 + 36 + if (plugin.config.contracts.strategy === 'byTags') { 37 + return OperationStrategy.byTags({ 38 + fallback: plugin.config.contracts.strategyDefaultTag, 39 + path: resolvePath(plugin), 40 + }); 41 + } 42 + 43 + return plugin.config.contracts.strategy; 44 + }
+108
packages/openapi-ts/src/plugins/orpc/contracts/types.ts
··· 1 + import type { 2 + NamingConfig, 3 + NamingRule, 4 + OperationPathStrategy, 5 + OperationsStrategy, 6 + } from '@hey-api/shared'; 7 + 8 + export interface UserContractsConfig { 9 + /** 10 + * Type of container for grouped contracts. 11 + * 12 + * Ignored when `strategy` is `'flat'`. 13 + * 14 + * - `'object'` - Object with properties 15 + * 16 + * @default 'object' 17 + */ 18 + container?: 'object'; 19 + /** 20 + * Customize container names. 21 + * 22 + * For `'single'` strategy, this sets the root container name. 23 + * For `'byTags'` strategy, this transforms tag names. 24 + * 25 + * @default 'contract' for `'single'` strategy 26 + * 27 + * @example 28 + * // Set root name for single strategy 29 + * containerName: 'myContract' 30 + * 31 + * @example 32 + * // Transform tag names with suffix 33 + * containerName: '{{name}}Contract' 34 + * 35 + * @example 36 + * // With casing 37 + * containerName: { name: '{{name}}Contract', casing: 'camelCase' } 38 + */ 39 + containerName?: NamingRule; 40 + /** 41 + * Customize contract names. 42 + * 43 + * Applied to the final segment of the path (the contract name). 44 + */ 45 + contractName?: NamingRule; 46 + /** 47 + * How to derive nesting structure from operations. 48 + * 49 + * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 50 + * - `'id'` - Use operation id as-is, no nesting 51 + * - Custom function for full control 52 + * 53 + * @default 'operationId' 54 + */ 55 + nesting?: 'operationId' | 'id' | OperationPathStrategy; 56 + /** 57 + * Delimiters for splitting operationId. 58 + * 59 + * Only applies when `nesting` is `'operationId'`. 60 + * 61 + * @default /[./]/ 62 + */ 63 + nestingDelimiters?: RegExp; 64 + /** 65 + * Customize nesting segment names. 66 + * 67 + * Applied to intermediate path segments (not the contract name). 68 + */ 69 + segmentName?: NamingRule; 70 + /** 71 + * Grouping strategy. 72 + * 73 + * - `'flat'` - Standalone contracts, no grouping 74 + * - `'byTags'` - One container per operation tag 75 + * - `'single'` - All contracts in one container 76 + * - Custom function for full control 77 + * 78 + * @default 'single' 79 + */ 80 + strategy?: OperationsStrategy; 81 + /** 82 + * Default container name for operations without tags. 83 + * 84 + * Only applies when `strategy` is `'byTags'`. 85 + * 86 + * @default 'default' 87 + */ 88 + strategyDefaultTag?: string; 89 + } 90 + 91 + export interface ContractsConfig { 92 + /** Type of container for grouped operations. */ 93 + container: 'object'; 94 + /** Customize container names. */ 95 + containerName: NamingConfig; 96 + /** Customize contract names. */ 97 + contractName: NamingConfig; 98 + /** How to derive nesting structure from operations. */ 99 + nesting: 'operationId' | 'id' | OperationPathStrategy; 100 + /** Delimiters for splitting operationId. */ 101 + nestingDelimiters: RegExp; 102 + /** Customize nesting segment names. */ 103 + segmentName: NamingConfig; 104 + /** Grouping strategy. */ 105 + strategy: OperationsStrategy; 106 + /** Default container name for operations without tags. */ 107 + strategyDefaultTag: string; 108 + }
+2
packages/openapi-ts/src/plugins/orpc/index.ts
··· 1 + export { defaultConfig, defineConfig } from './config'; 2 + export type { OrpcPlugin } from './types';
+4
packages/openapi-ts/src/plugins/orpc/plugin.ts
··· 1 + import type { OrpcPlugin } from './types'; 2 + import { handlerV1 } from './v1/plugin'; 3 + 4 + export const handler: OrpcPlugin['Handler'] = (args) => handlerV1(args);
+38
packages/openapi-ts/src/plugins/orpc/shared/operation.ts
··· 1 + import type { IR } from '@hey-api/shared'; 2 + 3 + export function hasInput(operation: IR.OperationObject): boolean { 4 + const hasPathParams = Boolean( 5 + operation.parameters?.path && Object.keys(operation.parameters.path).length > 0, 6 + ); 7 + const hasQueryParams = Boolean( 8 + operation.parameters?.query && Object.keys(operation.parameters.query).length > 0, 9 + ); 10 + const hasHeaderParams = Boolean( 11 + operation.parameters?.header && Object.keys(operation.parameters.header).length > 0, 12 + ); 13 + const hasBody = Boolean(operation.body); 14 + return hasPathParams || hasQueryParams || hasHeaderParams || hasBody; 15 + } 16 + 17 + export function getSuccessResponse( 18 + operation: IR.OperationObject, 19 + ): { hasOutput: true; statusCode: number } | { hasOutput: false; statusCode?: undefined } { 20 + if (operation.responses) { 21 + for (const [statusCode, response] of Object.entries(operation.responses)) { 22 + const statusCodeNumber = Number.parseInt(statusCode, 10); 23 + if ( 24 + statusCodeNumber >= 200 && 25 + statusCodeNumber <= 399 && 26 + response?.mediaType && 27 + response?.schema 28 + ) { 29 + return { hasOutput: true, statusCode: statusCodeNumber }; 30 + } 31 + } 32 + } 33 + return { hasOutput: false, statusCode: undefined }; 34 + } 35 + 36 + export function getTags(operation: IR.OperationObject, defaultTag: string): ReadonlyArray<string> { 37 + return operation.tags && operation.tags.length > 0 ? [...operation.tags] : [defaultTag]; 38 + }
+67
packages/openapi-ts/src/plugins/orpc/types.ts
··· 1 + import type { DefinePlugin, OperationsStrategy, Plugin } from '@hey-api/shared'; 2 + 3 + import type { PluginValidatorNames } from '../types'; 4 + import type { ContractsConfig, UserContractsConfig } from './contracts/types'; 5 + 6 + export type UserConfig = Plugin.Name<'orpc'> & 7 + Plugin.Hooks & 8 + Plugin.UserExports & { 9 + /** 10 + * Define the structure of generated oRPC contracts. 11 + * 12 + * String shorthand: 13 + * - `'byTags'` – one container per operation tag 14 + * - `'flat'` – standalone functions, no container 15 + * - `'single'` – all operations in a single container 16 + * - custom function for full control 17 + * 18 + * Use the object form for advanced configuration. 19 + * 20 + * @default 'single' 21 + */ 22 + contracts?: OperationsStrategy | UserContractsConfig; 23 + /** 24 + * Validate input/output schemas. 25 + * 26 + * @default true 27 + */ 28 + validator?: 29 + | PluginValidatorNames 30 + | boolean 31 + | { 32 + /** 33 + * The validator plugin to use for input schemas. 34 + * 35 + * Can be a validator plugin name or boolean (true to auto-select, false 36 + * to disable). 37 + * 38 + * @default true 39 + */ 40 + input?: PluginValidatorNames | boolean; 41 + /** 42 + * The validator plugin to use for output schemas. 43 + * 44 + * Can be a validator plugin name or boolean (true to auto-select, false 45 + * to disable). 46 + * 47 + * @default true 48 + */ 49 + output?: PluginValidatorNames | boolean; 50 + }; 51 + }; 52 + 53 + export type Config = Plugin.Name<'orpc'> & 54 + Plugin.Hooks & 55 + Plugin.Exports & { 56 + /** Define the structure of generated oRPC contracts. */ 57 + contracts: ContractsConfig; 58 + /** Validate input/output schemas. */ 59 + validator: { 60 + /** The validator plugin to use for input schemas. */ 61 + input: PluginValidatorNames | false; 62 + /** The validator plugin to use for output schemas. */ 63 + output: PluginValidatorNames | false; 64 + }; 65 + }; 66 + 67 + export type OrpcPlugin = DefinePlugin<UserConfig, Config>;
+53
packages/openapi-ts/src/plugins/orpc/v1/plugin.ts
··· 1 + import { StructureModel } from '@hey-api/codegen-core'; 2 + 3 + import { $ } from '../../../ts-dsl'; 4 + import type { ContractItem } from '../contracts'; 5 + import { createShell, resolveStrategy, source, toNode } from '../contracts'; 6 + import type { OrpcPlugin } from '../types'; 7 + 8 + export const handlerV1: OrpcPlugin['Handler'] = ({ plugin }) => { 9 + const oc = plugin.symbol('oc', { 10 + external: '@orpc/contract', 11 + }); 12 + const baseSymbol = plugin.symbol('base'); 13 + 14 + const baseNode = $.const(baseSymbol) 15 + .export() 16 + .assign( 17 + $(oc) 18 + .attr('$route') 19 + .call($.object().prop('inputStructure', $.literal('detailed'))), 20 + ); 21 + plugin.node(baseNode); 22 + 23 + const structure = new StructureModel(); 24 + const shell = createShell(plugin); 25 + const strategy = resolveStrategy(plugin); 26 + 27 + plugin.forEach( 28 + 'operation', 29 + (event) => { 30 + structure.insert({ 31 + data: { 32 + operation: event.operation, 33 + path: event._path, 34 + tags: event.tags, 35 + } satisfies ContractItem, 36 + locations: strategy(event.operation).map((path) => ({ path, shell })), 37 + source, 38 + }); 39 + }, 40 + { order: 'declarations' }, 41 + ); 42 + 43 + const allNodes: Array<ReturnType<typeof $.class | typeof $.var>> = []; 44 + 45 + for (const node of structure.walk()) { 46 + const { nodes } = toNode(node, plugin, baseSymbol); 47 + allNodes.push(...nodes); 48 + } 49 + 50 + for (const node of allNodes) { 51 + plugin.node(node); 52 + } 53 + };
+5 -4
packages/openapi-ts/src/ts-dsl/type/query.ts
··· 1 - import type { AnalysisContext, NodeScope } from '@hey-api/codegen-core'; 1 + import type { AnalysisContext, NodeName, NodeScope, Ref } from '@hey-api/codegen-core'; 2 + import { ref } from '@hey-api/codegen-core'; 2 3 import ts from 'typescript'; 3 4 4 5 import type { MaybeTsDsl, TypeTsDsl } from '../base'; ··· 6 7 import { TypeExprMixin } from '../mixins/type-expr'; 7 8 import { f } from '../utils/factories'; 8 9 9 - export type TypeQueryExpr = string | MaybeTsDsl<TypeTsDsl | ts.Expression>; 10 + export type TypeQueryExpr = NodeName | MaybeTsDsl<TypeTsDsl | ts.Expression>; 10 11 export type TypeQueryCtor = (expr: TypeQueryExpr) => TypeQueryTsDsl; 11 12 12 13 const Mixed = TypeExprMixin(TsDsl<ts.TypeQueryNode>); ··· 15 16 readonly '~dsl' = 'TypeQueryTsDsl'; 16 17 override scope: NodeScope = 'type'; 17 18 18 - protected _expr: TypeQueryExpr; 19 + protected _expr: Ref<TypeQueryExpr>; 19 20 20 21 constructor(expr: TypeQueryExpr) { 21 22 super(); 22 - this._expr = expr; 23 + this._expr = ref(expr); 23 24 } 24 25 25 26 override analyze(ctx: AnalysisContext): void {
+6 -8
packages/shared/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 9 + .env 10 + coverage 14 11 dist 15 - coverage 16 - .env 12 + 13 + # test files 14 + .gen
+1 -1
packages/shared/src/plugins/shared/utils/config.ts
··· 1 - import type { Plugin } from '../../../plugins/types'; 1 + import type { Plugin } from '../../types'; 2 2 3 3 export const definePluginConfig = 4 4 <T extends Plugin.Types>(defaultConfig: Plugin.Config<T>) =>
+1 -1
packages/shared/src/plugins/shared/utils/instance.ts
··· 24 24 import type { ExampleIntent } from '../../../ir/intents'; 25 25 import type { IR } from '../../../ir/types'; 26 26 import type { Hooks } from '../../../parser/hooks'; 27 - import type { Plugin, PluginConfigMap } from '../../../plugins/types'; 28 27 import { jsonPointerToPath } from '../../../utils/ref'; 28 + import type { Plugin, PluginConfigMap } from '../../types'; 29 29 import type { BaseEvent, WalkEvent } from '../types/instance'; 30 30 31 31 // eslint-disable-next-line @typescript-eslint/no-empty-object-type
+7 -8
packages/vite-plugin/.gitignore
··· 1 1 .DS_Store 2 2 .idea 3 - .tsdown 4 3 .tmp 5 - junit.xml 4 + .tsdown 6 5 logs 7 6 node_modules 8 - npm-debug.log* 9 7 temp 10 - yarn-debug.log* 11 - yarn-error.log* 12 8 13 - *.iml 9 + .env 10 + coverage 14 11 dist 15 - coverage 16 - .env 12 + 13 + # test files 14 + .gen 15 + 17 16 18 17 # test files 19 18 test/generated
+113 -241
pnpm-lock.yaml
··· 118 118 '@opencode-ai/sdk': 119 119 specifier: 1.2.27 120 120 version: 1.2.27 121 + '@orpc/contract': 122 + specifier: 1.13.4 123 + version: 1.13.4 121 124 '@pinia/colada': 122 125 specifier: 0.19.1 123 126 version: 0.19.1(pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) ··· 1309 1312 version: 1.8.0 1310 1313 nuxt: 1311 1314 specifier: '>=3.0.0' 1312 - version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) 1315 + version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.2)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.7.0)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) 1313 1316 vue: 1314 1317 specifier: '>=3.5.13' 1315 1318 version: 3.5.13(typescript@5.9.3) ··· 1441 1444 version: 1.14.3 1442 1445 nuxt: 1443 1446 specifier: 3.14.1592 1444 - version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.2)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.7.0)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue-tsc@3.2.4(typescript@5.9.3)) 1447 + version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) 1445 1448 ofetch: 1446 1449 specifier: 1.5.1 1447 1450 version: 1.5.1 ··· 1583 1586 typescript: 1584 1587 specifier: 5.9.3 1585 1588 version: 5.9.3 1589 + 1590 + packages/openapi-ts-tests/orpc/v1: 1591 + devDependencies: 1592 + '@hey-api/openapi-ts': 1593 + specifier: workspace:* 1594 + version: link:../../../openapi-ts 1595 + '@orpc/contract': 1596 + specifier: 1.13.4 1597 + version: 1.13.4 1598 + typescript: 1599 + specifier: 5.9.3 1600 + version: 5.9.3 1601 + valibot: 1602 + specifier: 1.2.0 1603 + version: 1.2.0(typescript@5.9.3) 1604 + zod: 1605 + specifier: 4.3.6 1606 + version: 4.3.6 1586 1607 1587 1608 packages/openapi-ts-tests/sdks: 1588 1609 devDependencies: ··· 5131 5152 '@opencode-ai/sdk@1.2.27': 5132 5153 resolution: {integrity: sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA==} 5133 5154 5155 + '@orpc/client@1.13.4': 5156 + resolution: {integrity: sha512-s13GPMeoooJc5Th2EaYT5HMFtWG8S03DUVytYfJv8pIhP87RYKl94w52A36denH6r/B4LaAgBeC9nTAOslK+Og==} 5157 + 5158 + '@orpc/contract@1.13.4': 5159 + resolution: {integrity: sha512-TIxyaF67uOlihCRcasjHZxguZpbqfNK7aMrDLnhoufmQBE4OKvguNzmrOFHgsuM0OXoopX0Nuhun1ccaxKP10A==} 5160 + 5161 + '@orpc/shared@1.13.4': 5162 + resolution: {integrity: sha512-TYt9rLG/BUkNQBeQ6C1tEiHS/Seb8OojHgj9GlvqyjHJhMZx5qjsIyTW6RqLPZJ4U2vgK6x4Her36+tlFCKJug==} 5163 + peerDependencies: 5164 + '@opentelemetry/api': '>=1.9.0' 5165 + peerDependenciesMeta: 5166 + '@opentelemetry/api': 5167 + optional: true 5168 + 5169 + '@orpc/standard-server-fetch@1.13.4': 5170 + resolution: {integrity: sha512-/zmKwnuxfAXbppJpgr1CMnQX3ptPlYcDzLz1TaVzz9VG/Xg58Ov3YhabS2Oi1utLVhy5t4kaCppUducAvoKN+A==} 5171 + 5172 + '@orpc/standard-server-peer@1.13.4': 5173 + resolution: {integrity: sha512-UfqnTLqevjCKUk4cmImOG8cQUwANpV1dp9e9u2O1ki6BRBsg/zlXFg6G2N6wP0zr9ayIiO1d2qJdH55yl/1BNw==} 5174 + 5175 + '@orpc/standard-server@1.13.4': 5176 + resolution: {integrity: sha512-ZOzgfVp6XUg+wVYw+gqesfRfGPtQbnBIrIiSnFMtZF+6ncmFJeF2Shc4RI2Guqc0Qz25juy8Ogo4tX3YqysOcg==} 5177 + 5134 5178 '@oxc-minify/binding-android-arm-eabi@0.110.0': 5135 5179 resolution: {integrity: sha512-43fMTO8/5bMlqfOiNSZNKUzIqeLIYuB9Hr1Ohyf58B1wU11S2dPGibTXOGNaWsfgHy99eeZ1bSgeIHy/fEYqbw==} 5136 5180 engines: {node: ^20.19.0 || >=22.12.0} ··· 12554 12598 zod: 12555 12599 optional: true 12556 12600 12601 + openapi-types@12.1.3: 12602 + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} 12603 + 12557 12604 optionator@0.9.4: 12558 12605 resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 12559 12606 engines: {node: '>= 0.8.0'} ··· 13315 13362 13316 13363 quote-unquote@1.0.0: 13317 13364 resolution: {integrity: sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==} 13365 + 13366 + radash@12.1.1: 13367 + resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==} 13368 + engines: {node: '>=14.18.0'} 13318 13369 13319 13370 radix3@1.1.2: 13320 13371 resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} ··· 19747 19798 19748 19799 '@nuxt/devalue@2.0.2': {} 19749 19800 19750 - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))': 19751 - dependencies: 19752 - '@nuxt/kit': 3.21.0(magicast@0.3.5) 19753 - '@nuxt/schema': 3.16.2 19754 - execa: 7.2.0 19755 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) 19756 - transitivePeerDependencies: 19757 - - magicast 19758 - 19759 19801 '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': 19760 19802 dependencies: 19761 19803 '@nuxt/kit': 3.21.0(magicast@0.3.5) ··· 19852 19894 - utf-8-validate 19853 19895 - vue 19854 19896 19855 - '@nuxt/devtools@1.7.0(rollup@4.56.0)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))': 19856 - dependencies: 19857 - '@antfu/utils': 0.7.10 19858 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)) 19859 - '@nuxt/devtools-wizard': 1.7.0 19860 - '@nuxt/kit': 3.21.0(magicast@0.3.5) 19861 - '@vue/devtools-core': 7.6.8(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3)) 19862 - '@vue/devtools-kit': 7.6.8 19863 - birpc: 0.2.19 19864 - consola: 3.4.2 19865 - cronstrue: 2.59.0 19866 - destr: 2.0.5 19867 - error-stack-parser-es: 0.1.5 19868 - execa: 7.2.0 19869 - fast-npm-meta: 0.2.2 19870 - flatted: 3.3.3 19871 - get-port-please: 3.2.0 19872 - hookable: 5.5.3 19873 - image-meta: 0.2.1 19874 - is-installed-globally: 1.0.0 19875 - launch-editor: 2.11.1 19876 - local-pkg: 0.5.1 19877 - magicast: 0.3.5 19878 - nypm: 0.4.1 19879 - ohash: 1.1.6 19880 - pathe: 1.1.2 19881 - perfect-debounce: 1.0.0 19882 - pkg-types: 1.3.1 19883 - rc9: 2.1.2 19884 - scule: 1.3.0 19885 - semver: 7.7.3 19886 - simple-git: 3.28.0 19887 - sirv: 3.0.2 19888 - tinyglobby: 0.2.15 19889 - unimport: 3.14.6(rollup@4.56.0) 19890 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) 19891 - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.21.0(magicast@0.3.5))(rollup@4.56.0)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)) 19892 - vite-plugin-vue-inspector: 5.3.2(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)) 19893 - which: 3.0.1 19894 - ws: 8.18.3 19895 - transitivePeerDependencies: 19896 - - bufferutil 19897 - - rollup 19898 - - supports-color 19899 - - utf-8-validate 19900 - - vue 19901 - 19902 19897 '@nuxt/devtools@1.7.0(rollup@4.56.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': 19903 19898 dependencies: 19904 19899 '@antfu/utils': 0.7.10 ··· 20606 20601 20607 20602 '@opencode-ai/sdk@1.2.27': {} 20608 20603 20604 + '@orpc/client@1.13.4': 20605 + dependencies: 20606 + '@orpc/shared': 1.13.4 20607 + '@orpc/standard-server': 1.13.4 20608 + '@orpc/standard-server-fetch': 1.13.4 20609 + '@orpc/standard-server-peer': 1.13.4 20610 + transitivePeerDependencies: 20611 + - '@opentelemetry/api' 20612 + 20613 + '@orpc/contract@1.13.4': 20614 + dependencies: 20615 + '@orpc/client': 1.13.4 20616 + '@orpc/shared': 1.13.4 20617 + '@standard-schema/spec': 1.1.0 20618 + openapi-types: 12.1.3 20619 + transitivePeerDependencies: 20620 + - '@opentelemetry/api' 20621 + 20622 + '@orpc/shared@1.13.4': 20623 + dependencies: 20624 + radash: 12.1.1 20625 + type-fest: 5.4.3 20626 + 20627 + '@orpc/standard-server-fetch@1.13.4': 20628 + dependencies: 20629 + '@orpc/shared': 1.13.4 20630 + '@orpc/standard-server': 1.13.4 20631 + transitivePeerDependencies: 20632 + - '@opentelemetry/api' 20633 + 20634 + '@orpc/standard-server-peer@1.13.4': 20635 + dependencies: 20636 + '@orpc/shared': 1.13.4 20637 + '@orpc/standard-server': 1.13.4 20638 + transitivePeerDependencies: 20639 + - '@opentelemetry/api' 20640 + 20641 + '@orpc/standard-server@1.13.4': 20642 + dependencies: 20643 + '@orpc/shared': 1.13.4 20644 + transitivePeerDependencies: 20645 + - '@opentelemetry/api' 20646 + 20609 20647 '@oxc-minify/binding-android-arm-eabi@0.110.0': 20610 20648 optional: true 20611 20649 ··· 23541 23579 dependencies: 23542 23580 '@vue/devtools-kit': 8.0.5 23543 23581 23544 - '@vue/devtools-core@7.6.8(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))': 23545 - dependencies: 23546 - '@vue/devtools-kit': 7.7.7 23547 - '@vue/devtools-shared': 7.7.7 23548 - mitt: 3.0.1 23549 - nanoid: 5.1.5 23550 - pathe: 1.1.2 23551 - vite-hot-client: 0.2.4(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)) 23552 - vue: 3.5.25(typescript@5.9.3) 23553 - transitivePeerDependencies: 23554 - - vite 23555 - 23556 23582 '@vue/devtools-core@7.6.8(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': 23557 23583 dependencies: 23558 23584 '@vue/devtools-kit': 7.7.7 ··· 25746 25772 eslint: 9.17.0(jiti@2.6.1) 25747 25773 eslint-import-resolver-node: 0.3.9 25748 25774 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 25749 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)) 25775 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 25750 25776 eslint-plugin-jsx-a11y: 6.10.2(eslint@9.17.0(jiti@2.6.1)) 25751 25777 eslint-plugin-react: 7.37.5(eslint@9.17.0(jiti@2.6.1)) 25752 25778 eslint-plugin-react-hooks: 5.2.0(eslint@9.17.0(jiti@2.6.1)) ··· 25776 25802 tinyglobby: 0.2.15 25777 25803 unrs-resolver: 1.11.1 25778 25804 optionalDependencies: 25779 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)) 25805 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 25780 25806 transitivePeerDependencies: 25781 25807 - supports-color 25782 25808 ··· 25791 25817 transitivePeerDependencies: 25792 25818 - supports-color 25793 25819 25794 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)): 25820 + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)): 25795 25821 dependencies: 25796 25822 '@rtsao/scc': 1.1.0 25797 25823 array-includes: 3.1.9 ··· 28882 28908 28883 28909 nuxi@3.28.0: {} 28884 28910 28885 - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.2)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.7.0)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue-tsc@3.2.4(typescript@5.9.3)): 28911 + nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.2)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.7.0)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)): 28886 28912 dependencies: 28887 28913 '@nuxt/devalue': 2.0.2 28888 - '@nuxt/devtools': 1.7.0(rollup@4.56.0)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3)) 28889 - '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.56.0) 28890 - '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.56.0) 28914 + '@nuxt/devtools': 1.7.0(rollup@3.29.5)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) 28915 + '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@3.29.5) 28916 + '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@3.29.5) 28891 28917 '@nuxt/telemetry': 2.6.6(magicast@0.3.5) 28892 - '@nuxt/vite-builder': 3.14.1592(@types/node@25.2.1)(eslint@9.39.1(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)) 28918 + '@nuxt/vite-builder': 3.14.1592(@types/node@25.2.1)(eslint@9.39.2(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)) 28893 28919 '@unhead/dom': 1.11.20 28894 28920 '@unhead/shared': 1.11.20 28895 28921 '@unhead/ssr': 1.11.20 ··· 28912 28938 h3: 1.15.4 28913 28939 hookable: 5.5.3 28914 28940 ignore: 6.0.2 28915 - impound: 0.2.2(rollup@4.56.0) 28941 + impound: 0.2.2(rollup@3.29.5) 28916 28942 jiti: 2.6.1 28917 28943 klona: 2.0.6 28918 28944 knitwork: 1.3.0 ··· 28939 28965 unctx: 2.4.1 28940 28966 unenv: 1.10.0 28941 28967 unhead: 1.11.20 28942 - unimport: 3.14.6(rollup@4.56.0) 28968 + unimport: 3.14.6(rollup@3.29.5) 28943 28969 unplugin: 1.16.1 28944 - unplugin-vue-router: 0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) 28970 + unplugin-vue-router: 0.10.9(rollup@3.29.5)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) 28945 28971 unstorage: 1.17.0(@netlify/blobs@9.1.2)(db0@0.3.2)(ioredis@5.7.0) 28946 28972 untyped: 1.5.2 28947 28973 vue: 3.5.25(typescript@5.9.3) 28948 28974 vue-bundle-renderer: 2.1.2 28949 28975 vue-devtools-stub: 0.1.0 28950 - vue-router: 4.5.0(vue@3.5.25(typescript@5.9.3)) 28976 + vue-router: 4.5.0(vue@3.5.13(typescript@5.9.3)) 28951 28977 optionalDependencies: 28952 28978 '@parcel/watcher': 2.5.1 28953 28979 '@types/node': 25.2.1 ··· 29124 29150 - vue-tsc 29125 29151 - xml2js 29126 29152 29127 - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)): 29128 - dependencies: 29129 - '@nuxt/devalue': 2.0.2 29130 - '@nuxt/devtools': 1.7.0(rollup@3.29.5)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) 29131 - '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@3.29.5) 29132 - '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@3.29.5) 29133 - '@nuxt/telemetry': 2.6.6(magicast@0.3.5) 29134 - '@nuxt/vite-builder': 3.14.1592(@types/node@25.2.1)(eslint@9.39.2(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)) 29135 - '@unhead/dom': 1.11.20 29136 - '@unhead/shared': 1.11.20 29137 - '@unhead/ssr': 1.11.20 29138 - '@unhead/vue': 1.11.20(vue@3.5.25(typescript@5.9.3)) 29139 - '@vue/shared': 3.5.25 29140 - acorn: 8.14.0 29141 - c12: 2.0.1(magicast@0.3.5) 29142 - chokidar: 4.0.3 29143 - compatx: 0.1.8 29144 - consola: 3.4.2 29145 - cookie-es: 1.2.2 29146 - defu: 6.1.4 29147 - destr: 2.0.5 29148 - devalue: 5.3.2 29149 - errx: 0.1.0 29150 - esbuild: 0.24.2 29151 - escape-string-regexp: 5.0.0 29152 - estree-walker: 3.0.3 29153 - globby: 14.1.0 29154 - h3: 1.15.4 29155 - hookable: 5.5.3 29156 - ignore: 6.0.2 29157 - impound: 0.2.2(rollup@3.29.5) 29158 - jiti: 2.6.1 29159 - klona: 2.0.6 29160 - knitwork: 1.3.0 29161 - magic-string: 0.30.21 29162 - mlly: 1.8.0 29163 - nanotar: 0.1.1 29164 - nitropack: 2.12.4(@netlify/blobs@9.1.2)(encoding@0.1.13)(rolldown@1.0.0-rc.9) 29165 - nuxi: 3.28.0 29166 - nypm: 0.3.12 29167 - ofetch: 1.5.1 29168 - ohash: 1.1.6 29169 - pathe: 1.1.2 29170 - perfect-debounce: 1.0.0 29171 - pkg-types: 1.3.1 29172 - radix3: 1.1.2 29173 - scule: 1.3.0 29174 - semver: 7.7.3 29175 - std-env: 3.10.0 29176 - strip-literal: 2.1.1 29177 - tinyglobby: 0.2.10 29178 - ufo: 1.6.1 29179 - ultrahtml: 1.6.0 29180 - uncrypto: 0.1.3 29181 - unctx: 2.4.1 29182 - unenv: 1.10.0 29183 - unhead: 1.11.20 29184 - unimport: 3.14.6(rollup@3.29.5) 29185 - unplugin: 1.16.1 29186 - unplugin-vue-router: 0.10.9(rollup@3.29.5)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) 29187 - unstorage: 1.17.0(@netlify/blobs@9.1.2)(db0@0.3.4)(ioredis@5.9.2) 29188 - untyped: 1.5.2 29189 - vue: 3.5.25(typescript@5.9.3) 29190 - vue-bundle-renderer: 2.1.2 29191 - vue-devtools-stub: 0.1.0 29192 - vue-router: 4.5.0(vue@3.5.25(typescript@5.9.3)) 29193 - optionalDependencies: 29194 - '@parcel/watcher': 2.5.1 29195 - '@types/node': 25.2.1 29196 - transitivePeerDependencies: 29197 - - '@azure/app-configuration' 29198 - - '@azure/cosmos' 29199 - - '@azure/data-tables' 29200 - - '@azure/identity' 29201 - - '@azure/keyvault-secrets' 29202 - - '@azure/storage-blob' 29203 - - '@biomejs/biome' 29204 - - '@capacitor/preferences' 29205 - - '@deno/kv' 29206 - - '@electric-sql/pglite' 29207 - - '@libsql/client' 29208 - - '@netlify/blobs' 29209 - - '@planetscale/database' 29210 - - '@upstash/redis' 29211 - - '@vercel/blob' 29212 - - '@vercel/functions' 29213 - - '@vercel/kv' 29214 - - aws4fetch 29215 - - better-sqlite3 29216 - - bufferutil 29217 - - db0 29218 - - drizzle-orm 29219 - - encoding 29220 - - eslint 29221 - - idb-keyval 29222 - - ioredis 29223 - - less 29224 - - lightningcss 29225 - - magicast 29226 - - meow 29227 - - mysql2 29228 - - optionator 29229 - - rolldown 29230 - - rollup 29231 - - sass 29232 - - sass-embedded 29233 - - sqlite3 29234 - - stylelint 29235 - - stylus 29236 - - sugarss 29237 - - supports-color 29238 - - terser 29239 - - typescript 29240 - - uploadthing 29241 - - utf-8-validate 29242 - - vite 29243 - - vls 29244 - - vti 29245 - - vue-tsc 29246 - - xml2js 29247 - 29248 29153 nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)): 29249 29154 dependencies: 29250 29155 '@nuxt/devalue': 2.0.2 ··· 29656 29561 optionalDependencies: 29657 29562 ws: 8.18.3 29658 29563 zod: 3.25.3 29564 + 29565 + openapi-types@12.1.3: {} 29659 29566 29660 29567 optionator@0.9.4: 29661 29568 dependencies: ··· 30511 30418 quick-format-unescaped@4.0.4: {} 30512 30419 30513 30420 quote-unquote@1.0.0: {} 30421 + 30422 + radash@12.1.1: {} 30514 30423 30515 30424 radix3@1.1.2: {} 30516 30425 ··· 32613 32522 unplugin: 2.0.0-beta.1 32614 32523 yaml: 2.8.2 32615 32524 optionalDependencies: 32616 - vue-router: 4.5.0(vue@3.5.25(typescript@5.9.3)) 32525 + vue-router: 4.5.0(vue@3.5.13(typescript@5.9.3)) 32617 32526 transitivePeerDependencies: 32618 32527 - rollup 32619 32528 - vue ··· 32919 32828 vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) 32920 32829 vite-hot-client: 2.1.0(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) 32921 32830 32922 - vite-hot-client@0.2.4(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)): 32923 - dependencies: 32924 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) 32925 - 32926 32831 vite-hot-client@0.2.4(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): 32927 32832 dependencies: 32928 32833 vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) ··· 33054 32959 - rollup 33055 32960 - supports-color 33056 32961 33057 - vite-plugin-inspect@0.8.9(@nuxt/kit@3.21.0(magicast@0.3.5))(rollup@4.56.0)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)): 33058 - dependencies: 33059 - '@antfu/utils': 0.7.10 33060 - '@rollup/pluginutils': 5.2.0(rollup@4.56.0) 33061 - debug: 4.4.3 33062 - error-stack-parser-es: 0.1.5 33063 - fs-extra: 11.3.1 33064 - open: 10.2.0 33065 - perfect-debounce: 1.0.0 33066 - picocolors: 1.1.1 33067 - sirv: 3.0.2 33068 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) 33069 - optionalDependencies: 33070 - '@nuxt/kit': 3.21.0(magicast@0.3.5) 33071 - transitivePeerDependencies: 33072 - - rollup 33073 - - supports-color 33074 - 33075 32962 vite-plugin-inspect@0.8.9(@nuxt/kit@3.21.0(magicast@0.3.5))(rollup@4.56.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): 33076 32963 dependencies: 33077 32964 '@antfu/utils': 0.7.10 ··· 33136 33023 - '@nuxt/kit' 33137 33024 - supports-color 33138 33025 - vue 33139 - 33140 - vite-plugin-vue-inspector@5.3.2(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)): 33141 - dependencies: 33142 - '@babel/core': 7.28.3 33143 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.3) 33144 - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.3) 33145 - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.3) 33146 - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.3) 33147 - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.3) 33148 - '@vue/compiler-dom': 3.5.25 33149 - kolorist: 1.8.0 33150 - magic-string: 0.30.21 33151 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) 33152 - transitivePeerDependencies: 33153 - - supports-color 33154 33026 33155 33027 vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): 33156 33028 dependencies:
+285
specs/3.0.x/orpc.yaml
··· 1 + openapi: 3.0.4 2 + info: 3 + title: OpenAPI 3.0.4 oRPC example 4 + version: 1 5 + paths: 6 + /users: 7 + get: 8 + tags: 9 + - users 10 + operationId: getUsers 11 + summary: Get all users 12 + parameters: 13 + - name: limit 14 + in: query 15 + description: Maximum number of users to return 16 + required: false 17 + schema: 18 + type: integer 19 + default: 10 20 + - name: offset 21 + in: query 22 + description: Number of users to skip 23 + required: false 24 + schema: 25 + type: integer 26 + default: 0 27 + responses: 28 + '200': 29 + description: List of users 30 + content: 31 + application/json: 32 + schema: 33 + type: array 34 + items: 35 + $ref: '#/components/schemas/User' 36 + post: 37 + tags: 38 + - users 39 + operationId: createUser 40 + summary: Create a new user 41 + requestBody: 42 + required: true 43 + content: 44 + application/json: 45 + schema: 46 + $ref: '#/components/schemas/CreateUserInput' 47 + responses: 48 + '201': 49 + description: User created 50 + content: 51 + application/json: 52 + schema: 53 + $ref: '#/components/schemas/User' 54 + /users/{userId}: 55 + get: 56 + tags: 57 + - users 58 + operationId: getUserById 59 + summary: Get a user by ID 60 + parameters: 61 + - name: userId 62 + in: path 63 + description: User ID 64 + required: true 65 + schema: 66 + type: string 67 + responses: 68 + '200': 69 + description: User found 70 + content: 71 + application/json: 72 + schema: 73 + $ref: '#/components/schemas/User' 74 + put: 75 + tags: 76 + - users 77 + operationId: updateUser 78 + summary: Update a user 79 + parameters: 80 + - name: userId 81 + in: path 82 + description: User ID 83 + required: true 84 + schema: 85 + type: string 86 + requestBody: 87 + required: true 88 + content: 89 + application/json: 90 + schema: 91 + $ref: '#/components/schemas/UpdateUserInput' 92 + responses: 93 + '200': 94 + description: User updated 95 + content: 96 + application/json: 97 + schema: 98 + $ref: '#/components/schemas/User' 99 + delete: 100 + tags: 101 + - users 102 + operationId: deleteUser 103 + summary: Delete a user 104 + parameters: 105 + - name: userId 106 + in: path 107 + description: User ID 108 + required: true 109 + schema: 110 + type: string 111 + - name: X-Request-Id 112 + in: header 113 + description: Request ID for tracing 114 + required: false 115 + schema: 116 + type: string 117 + responses: 118 + '204': 119 + description: User deleted 120 + /posts: 121 + get: 122 + tags: 123 + - posts 124 + operationId: getPosts 125 + summary: Get all posts 126 + parameters: 127 + - name: authorId 128 + in: query 129 + description: Filter by author ID 130 + required: false 131 + schema: 132 + type: string 133 + - name: status 134 + in: query 135 + description: Filter by status 136 + required: false 137 + schema: 138 + type: string 139 + enum: 140 + - draft 141 + - published 142 + - archived 143 + responses: 144 + '200': 145 + description: List of posts 146 + content: 147 + application/json: 148 + schema: 149 + type: array 150 + items: 151 + $ref: '#/components/schemas/Post' 152 + post: 153 + tags: 154 + - posts 155 + operationId: createPost 156 + summary: Create a new post 157 + parameters: 158 + - name: X-Author-Id 159 + in: header 160 + description: Author ID 161 + required: true 162 + schema: 163 + type: string 164 + requestBody: 165 + required: true 166 + content: 167 + application/json: 168 + schema: 169 + $ref: '#/components/schemas/CreatePostInput' 170 + responses: 171 + '201': 172 + description: Post created 173 + content: 174 + application/json: 175 + schema: 176 + $ref: '#/components/schemas/Post' 177 + /posts/{postId}: 178 + get: 179 + tags: 180 + - posts 181 + operationId: getPostById 182 + summary: Get a post by ID 183 + parameters: 184 + - name: postId 185 + in: path 186 + description: Post ID 187 + required: true 188 + schema: 189 + type: string 190 + - name: includeComments 191 + in: query 192 + description: Include comments in response 193 + required: false 194 + schema: 195 + type: boolean 196 + default: false 197 + responses: 198 + '200': 199 + description: Post found 200 + content: 201 + application/json: 202 + schema: 203 + $ref: '#/components/schemas/Post' 204 + components: 205 + schemas: 206 + User: 207 + type: object 208 + required: 209 + - id 210 + - email 211 + - name 212 + properties: 213 + id: 214 + type: string 215 + email: 216 + type: string 217 + format: email 218 + name: 219 + type: string 220 + createdAt: 221 + type: string 222 + format: date-time 223 + CreateUserInput: 224 + type: object 225 + required: 226 + - email 227 + - name 228 + properties: 229 + email: 230 + type: string 231 + format: email 232 + name: 233 + type: string 234 + password: 235 + type: string 236 + minLength: 8 237 + UpdateUserInput: 238 + type: object 239 + properties: 240 + email: 241 + type: string 242 + format: email 243 + name: 244 + type: string 245 + Post: 246 + type: object 247 + required: 248 + - id 249 + - title 250 + - content 251 + - authorId 252 + properties: 253 + id: 254 + type: string 255 + title: 256 + type: string 257 + content: 258 + type: string 259 + authorId: 260 + type: string 261 + status: 262 + type: string 263 + enum: 264 + - draft 265 + - published 266 + - archived 267 + createdAt: 268 + type: string 269 + format: date-time 270 + CreatePostInput: 271 + type: object 272 + required: 273 + - title 274 + - content 275 + properties: 276 + title: 277 + type: string 278 + content: 279 + type: string 280 + status: 281 + type: string 282 + enum: 283 + - draft 284 + - published 285 + default: draft
+285
specs/3.1.x/orpc.yaml
··· 1 + openapi: 3.1.1 2 + info: 3 + title: OpenAPI 3.1.1 oRPC example 4 + version: 1 5 + paths: 6 + /users: 7 + get: 8 + tags: 9 + - users 10 + operationId: getUsers 11 + summary: Get all users 12 + parameters: 13 + - name: limit 14 + in: query 15 + description: Maximum number of users to return 16 + required: false 17 + schema: 18 + type: integer 19 + default: 10 20 + - name: offset 21 + in: query 22 + description: Number of users to skip 23 + required: false 24 + schema: 25 + type: integer 26 + default: 0 27 + responses: 28 + '200': 29 + description: List of users 30 + content: 31 + application/json: 32 + schema: 33 + type: array 34 + items: 35 + $ref: '#/components/schemas/User' 36 + post: 37 + tags: 38 + - users 39 + operationId: createUser 40 + summary: Create a new user 41 + requestBody: 42 + required: true 43 + content: 44 + application/json: 45 + schema: 46 + $ref: '#/components/schemas/CreateUserInput' 47 + responses: 48 + '201': 49 + description: User created 50 + content: 51 + application/json: 52 + schema: 53 + $ref: '#/components/schemas/User' 54 + /users/{userId}: 55 + get: 56 + tags: 57 + - users 58 + operationId: getUserById 59 + summary: Get a user by ID 60 + parameters: 61 + - name: userId 62 + in: path 63 + description: User ID 64 + required: true 65 + schema: 66 + type: string 67 + responses: 68 + '200': 69 + description: User found 70 + content: 71 + application/json: 72 + schema: 73 + $ref: '#/components/schemas/User' 74 + put: 75 + tags: 76 + - users 77 + operationId: updateUser 78 + summary: Update a user 79 + parameters: 80 + - name: userId 81 + in: path 82 + description: User ID 83 + required: true 84 + schema: 85 + type: string 86 + requestBody: 87 + required: true 88 + content: 89 + application/json: 90 + schema: 91 + $ref: '#/components/schemas/UpdateUserInput' 92 + responses: 93 + '200': 94 + description: User updated 95 + content: 96 + application/json: 97 + schema: 98 + $ref: '#/components/schemas/User' 99 + delete: 100 + tags: 101 + - users 102 + operationId: deleteUser 103 + summary: Delete a user 104 + parameters: 105 + - name: userId 106 + in: path 107 + description: User ID 108 + required: true 109 + schema: 110 + type: string 111 + - name: X-Request-Id 112 + in: header 113 + description: Request ID for tracing 114 + required: false 115 + schema: 116 + type: string 117 + responses: 118 + '204': 119 + description: User deleted 120 + /posts: 121 + get: 122 + tags: 123 + - posts 124 + operationId: getPosts 125 + summary: Get all posts 126 + parameters: 127 + - name: authorId 128 + in: query 129 + description: Filter by author ID 130 + required: false 131 + schema: 132 + type: string 133 + - name: status 134 + in: query 135 + description: Filter by status 136 + required: false 137 + schema: 138 + type: string 139 + enum: 140 + - draft 141 + - published 142 + - archived 143 + responses: 144 + '200': 145 + description: List of posts 146 + content: 147 + application/json: 148 + schema: 149 + type: array 150 + items: 151 + $ref: '#/components/schemas/Post' 152 + post: 153 + tags: 154 + - posts 155 + operationId: createPost 156 + summary: Create a new post 157 + parameters: 158 + - name: X-Author-Id 159 + in: header 160 + description: Author ID 161 + required: true 162 + schema: 163 + type: string 164 + requestBody: 165 + required: true 166 + content: 167 + application/json: 168 + schema: 169 + $ref: '#/components/schemas/CreatePostInput' 170 + responses: 171 + '201': 172 + description: Post created 173 + content: 174 + application/json: 175 + schema: 176 + $ref: '#/components/schemas/Post' 177 + /posts/{postId}: 178 + get: 179 + tags: 180 + - posts 181 + operationId: getPostById 182 + summary: Get a post by ID 183 + parameters: 184 + - name: postId 185 + in: path 186 + description: Post ID 187 + required: true 188 + schema: 189 + type: string 190 + - name: includeComments 191 + in: query 192 + description: Include comments in response 193 + required: false 194 + schema: 195 + type: boolean 196 + default: false 197 + responses: 198 + '200': 199 + description: Post found 200 + content: 201 + application/json: 202 + schema: 203 + $ref: '#/components/schemas/Post' 204 + components: 205 + schemas: 206 + User: 207 + type: object 208 + required: 209 + - id 210 + - email 211 + - name 212 + properties: 213 + id: 214 + type: string 215 + email: 216 + type: string 217 + format: email 218 + name: 219 + type: string 220 + createdAt: 221 + type: string 222 + format: date-time 223 + CreateUserInput: 224 + type: object 225 + required: 226 + - email 227 + - name 228 + properties: 229 + email: 230 + type: string 231 + format: email 232 + name: 233 + type: string 234 + password: 235 + type: string 236 + minLength: 8 237 + UpdateUserInput: 238 + type: object 239 + properties: 240 + email: 241 + type: string 242 + format: email 243 + name: 244 + type: string 245 + Post: 246 + type: object 247 + required: 248 + - id 249 + - title 250 + - content 251 + - authorId 252 + properties: 253 + id: 254 + type: string 255 + title: 256 + type: string 257 + content: 258 + type: string 259 + authorId: 260 + type: string 261 + status: 262 + type: string 263 + enum: 264 + - draft 265 + - published 266 + - archived 267 + createdAt: 268 + type: string 269 + format: date-time 270 + CreatePostInput: 271 + type: object 272 + required: 273 + - title 274 + - content 275 + properties: 276 + title: 277 + type: string 278 + content: 279 + type: string 280 + status: 281 + type: string 282 + enum: 283 + - draft 284 + - published 285 + default: draft
+9
vitest.config.ts
··· 70 70 { 71 71 extends: true, 72 72 test: { 73 + globalSetup: ['./test/globalTeardown.ts'], 74 + name: '@test/openapi-ts-orpc-v1', 75 + root: 'packages/openapi-ts-tests/orpc/v1', 76 + setupFiles: ['./vitest.setup.ts'], 77 + }, 78 + }, 79 + { 80 + extends: true, 81 + test: { 73 82 name: '@test/openapi-ts-sdks', 74 83 root: 'packages/openapi-ts-tests/sdks', 75 84 setupFiles: ['./vitest.setup.ts'],