@srpc.org/core 0.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,400 @@
1
+ import { SRPC as SRPC$1, AnySRPC } from './server.js';
2
+
3
+ type ProcedureType<TContext> = (
4
+ ctx: TContext,
5
+ ...args: any[]
6
+ ) => Promise<any> | any;
7
+
8
+ type AnyProcedure = ProcedureType<any>;
9
+
10
+ type Routes<TContext> = {
11
+ [key: string]: ProcedureType<TContext> | SRPC<TContext>;
12
+ };
13
+ declare class SRPC<TContext, TRoutes extends Routes<TContext> = {}> {
14
+ __context: TContext;
15
+ ipc: TRoutes;
16
+ constructor(routes?: TRoutes);
17
+ context<T>(): SRPC<T>;
18
+ router<T extends Routes<TContext>>(routes: T): SRPC<TContext, T>;
19
+ }
20
+
21
+ /**
22
+ * Used from trpc.io
23
+ */
24
+ interface ProxyCallbackOptions {
25
+ path: readonly string[];
26
+ args: readonly unknown[];
27
+ }
28
+ type ProxyCallback = (opts: ProxyCallbackOptions) => unknown;
29
+ /**
30
+ * Creates a proxy that calls the callback with the path and arguments
31
+ *
32
+ * @internal
33
+ */
34
+ declare const createRecursiveProxy: <TFaux = unknown>(callback: ProxyCallback) => TFaux;
35
+ /**
36
+ * Used in place of `new Proxy` where each handler will map 1 level deep to another value.
37
+ *
38
+ * @internal
39
+ */
40
+ declare const createFlatProxy: <TFaux>(callback: (path: string & keyof TFaux) => any) => TFaux;
41
+
42
+ /**
43
+ * @module
44
+ *
45
+ * Shared SRPC utilities, types, and error handling.
46
+ *
47
+ * This module contains types and utilities used by both client and server sides:
48
+ * - Error handling with `SRPCError`
49
+ * - Serialization interfaces
50
+ * - Type inference utilities
51
+ * - Proxy utilities for dynamic API creation
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * import { SRPCError, type InferRouterInputs, type InferRouterOutputs } from "@srpc/core/shared";
56
+ *
57
+ * // Throw typed errors
58
+ * throw new SRPCError("Not found", "NOT_FOUND");
59
+ *
60
+ * // Extract types from router
61
+ * type Inputs = InferRouterInputs<AppRouter>;
62
+ * type Outputs = InferRouterOutputs<AppRouter>;
63
+ * ```
64
+ */
65
+
66
+ /**
67
+ * Interface for custom serialization strategies.
68
+ *
69
+ * Implement this interface to support serialization formats beyond JSON,
70
+ * such as MessagePack, Protocol Buffers, or superjson for complex types.
71
+ *
72
+ * @example Using superjson for Date, Map, Set support
73
+ * ```typescript
74
+ * import superjson from "superjson";
75
+ * import type { Serializer } from "@srpc/core/shared";
76
+ *
77
+ * const customSerializer: Serializer = {
78
+ * serialize: (value) => superjson.stringify(value),
79
+ * deserialize: (value) => superjson.parse(value)
80
+ * };
81
+ *
82
+ * // Use with client
83
+ * const client = createSRPCClient<AppRouter>({
84
+ * endpoint: "/api",
85
+ * transformer: customSerializer
86
+ * });
87
+ *
88
+ * // Use with server
89
+ * const { fetch } = srpcFetchApi({
90
+ * router: appRouter,
91
+ * endpoint: "/api",
92
+ * transformer: customSerializer
93
+ * });
94
+ * ```
95
+ */
96
+ interface Serializer {
97
+ serialize: (value: any) => any;
98
+ deserialize: (value: any) => any;
99
+ }
100
+ /**
101
+ * Default JSON-based serializer used by SRPC.
102
+ *
103
+ * Uses `JSON.stringify` for serialization and `JSON.parse` for deserialization.
104
+ * Works with JSON-compatible types (strings, numbers, booleans, objects, arrays, null).
105
+ * Does not support: Date, Map, Set, undefined, functions, symbols.
106
+ *
107
+ * For complex types, provide a custom `Serializer` implementation.
108
+ */
109
+ declare const defaultSerializer: Serializer;
110
+ /**
111
+ * Union type of all standard error codes in SRPC.
112
+ *
113
+ * Each error code maps to a specific HTTP status code:
114
+ * - `BAD_REQUEST` → 400
115
+ * - `UNAUTHORIZED` → 401
116
+ * - `FORBIDDEN` → 403
117
+ * - `NOT_FOUND` → 404
118
+ * - `UNSUPPORTED_MEDIA_TYPE` → 415
119
+ * - `INTERNAL_SERVER_ERROR` → 500
120
+ * - `NOT_IMPLEMENTED` → 501
121
+ * - `GENERIC_ERROR` → 500 (fallback for unexpected errors)
122
+ */
123
+ type ErrorCodes = "NOT_FOUND" | "FORBIDDEN" | "UNAUTHORIZED" | "INTERNAL_SERVER_ERROR" | "BAD_REQUEST" | "NOT_IMPLEMENTED" | "UNSUPPORTED_MEDIA_TYPE" | "GENERIC_ERROR";
124
+ /**
125
+ * Mapping of error codes to HTTP status codes.
126
+ *
127
+ * Used internally by server adapters to convert `SRPCError` instances
128
+ * to appropriate HTTP responses.
129
+ */
130
+ declare const StatusCodeMap: {
131
+ BAD_REQUEST: number;
132
+ NOT_FOUND: number;
133
+ FORBIDDEN: number;
134
+ UNAUTHORIZED: number;
135
+ INTERNAL_SERVER_ERROR: number;
136
+ NOT_IMPLEMENTED: number;
137
+ UNSUPPORTED_MEDIA_TYPE: number;
138
+ GENERIC_ERROR: number;
139
+ };
140
+ /**
141
+ * Standard error class for SRPC procedures.
142
+ *
143
+ * Thrown errors are automatically serialized and sent to the client with
144
+ * the appropriate HTTP status code. The client reconstructs the error
145
+ * with the same message and code.
146
+ *
147
+ * @example Throwing errors in procedures
148
+ * ```typescript
149
+ * import { SRPCError } from "@srpc.org/core";
150
+ *
151
+ * const appRouter = s.router({
152
+ * getUser: async (_, id: number) => {
153
+ * const user = await db.users.findById(id);
154
+ * if (!user) {
155
+ * throw new SRPCError("User not found", "NOT_FOUND");
156
+ * }
157
+ * return user;
158
+ * },
159
+ * deleteUser: async (ctx, id: number) => {
160
+ * if (!ctx.user?.isAdmin) {
161
+ * throw new SRPCError("Insufficient permissions", "FORBIDDEN");
162
+ * }
163
+ * await db.users.delete(id);
164
+ * return { success: true };
165
+ * }
166
+ * });
167
+ * ```
168
+ *
169
+ * @example Handling errors on the client
170
+ * ```typescript
171
+ * import { SRPCError } from "@srpc.org/core";
172
+ *
173
+ * try {
174
+ * const user = await client.getUser(999);
175
+ * } catch (error) {
176
+ * if (error instanceof SRPCError) {
177
+ * switch (error.code) {
178
+ * case "NOT_FOUND":
179
+ * console.log("User not found");
180
+ * break;
181
+ * case "FORBIDDEN":
182
+ * console.log("Access denied");
183
+ * break;
184
+ * case "UNAUTHORIZED":
185
+ * redirectToLogin();
186
+ * break;
187
+ * }
188
+ * }
189
+ * }
190
+ * ```
191
+ */
192
+ declare class SRPCError extends Error {
193
+ readonly code: ErrorCodes;
194
+ constructor(message: string, code: ErrorCodes);
195
+ __BRAND__: string;
196
+ }
197
+ /**
198
+ * Type utility to extract input parameter types from a single procedure.
199
+ *
200
+ * Returns a tuple of the procedure's parameters, excluding the context parameter.
201
+ *
202
+ * @template T - The procedure type to extract inputs from
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * import type { InferProcedureInput } from "@srpc/core/shared";
207
+ *
208
+ * type GetUserProcedure = (ctx: Context, id: number) => Promise<User>;
209
+ * type GetUserInput = InferProcedureInput<GetUserProcedure>; // [id: number]
210
+ *
211
+ * type CreateUserProcedure = (ctx: Context, name: string, email: string) => Promise<User>;
212
+ * type CreateUserInput = InferProcedureInput<CreateUserProcedure>; // [name: string, email: string]
213
+ * ```
214
+ */
215
+ type InferProcedureInput<T extends AnyProcedure> = T extends (_ctx: any, ...args: infer TArgs) => any ? TArgs : never;
216
+ /**
217
+ * Type utility to convert a server procedure to a client-side callable function.
218
+ *
219
+ * Removes the context parameter and preserves the return type.
220
+ *
221
+ * @template T - The procedure type to convert
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * import type { ClientProcedure } from "@srpc/core/shared";
226
+ *
227
+ * // Server procedure
228
+ * type ServerProc = (ctx: Context, id: number) => Promise<User>;
229
+ *
230
+ * // Client procedure (context removed)
231
+ * type ClientProc = ClientProcedure<ServerProc>; // (id: number) => Promise<User>
232
+ * ```
233
+ */
234
+ type ClientProcedure<T extends AnyProcedure> = (...args: InferProcedureInput<T>) => ReturnType<T>;
235
+ /**
236
+ * Type utility that transforms a router's procedures into client-callable functions.
237
+ *
238
+ * Recursively processes nested routers and converts each procedure to a client
239
+ * procedure (with context parameter removed).
240
+ *
241
+ * @template TRouter - The router routes type
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * import type { DecoratedProcedureRecord } from "@srpc/core/shared";
246
+ *
247
+ * // Server router
248
+ * const appRouter = s.router({
249
+ * getUser: async (ctx, id: number) => ({ id, name: "John" }),
250
+ * users: s.router({
251
+ * admin: s.router({
252
+ * createUser: async (ctx, data: UserData) => ({ id: 1, ...data })
253
+ * })
254
+ * })
255
+ * });
256
+ *
257
+ * type Routes = typeof appRouter["ipc"];
258
+ * type ClientAPI = DecoratedProcedureRecord<Routes>;
259
+ * // {
260
+ * // getUser: (id: number) => Promise<{ id: number, name: string }>,
261
+ * // users: {
262
+ * // admin: {
263
+ * // createUser: (data: UserData) => Promise<{ id: number } & UserData>
264
+ * // }
265
+ * // }
266
+ * // }
267
+ * ```
268
+ */
269
+ type DecoratedProcedureRecord<TRouter extends Routes<any>> = {
270
+ [TKey in keyof TRouter]: TRouter[TKey] extends AnyProcedure ? ClientProcedure<TRouter[TKey]> : TRouter[TKey] extends SRPC$1<any> ? DecoratedProcedureRecord<TRouter[TKey]["ipc"]> : never;
271
+ };
272
+ /**
273
+ * Type utility to extract the client API type from an SRPC router.
274
+ *
275
+ * Convenience type that wraps `DecoratedProcedureRecord`.
276
+ *
277
+ * @template TRouter - The SRPC router type
278
+ */
279
+ type InferRPCFromRouter<TRouter extends AnySRPC> = DecoratedProcedureRecord<TRouter["ipc"]>;
280
+ /**
281
+ * Type utility that extracts return types from all procedures in a router.
282
+ *
283
+ * Recursively processes nested routers and extracts awaited return types
284
+ * from each procedure.
285
+ *
286
+ * @template TRouter - The router routes type
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * import type { DecoratedProcedureOutputs } from "@srpc/core/shared";
291
+ *
292
+ * const appRouter = s.router({
293
+ * getUser: async (ctx, id: number) => ({ id, name: "John" }),
294
+ * users: s.router({
295
+ * createUser: async (ctx, data: UserData) => ({ id: 1, ...data })
296
+ * })
297
+ * });
298
+ *
299
+ * type Routes = typeof appRouter["ipc"];
300
+ * type Outputs = DecoratedProcedureOutputs<Routes>;
301
+ * // {
302
+ * // getUser: { id: number, name: string },
303
+ * // users: {
304
+ * // createUser: { id: number } & UserData
305
+ * // }
306
+ * // }
307
+ * ```
308
+ */
309
+ type DecoratedProcedureOutputs<TRouter extends Routes<any>> = {
310
+ [TKey in keyof TRouter]: TRouter[TKey] extends AnyProcedure ? Awaited<ReturnType<TRouter[TKey]>> : TRouter[TKey] extends SRPC$1<any> ? DecoratedProcedureOutputs<TRouter[TKey]["ipc"]> : never;
311
+ };
312
+ /**
313
+ * Type utility to extract output types from all procedures in an SRPC router.
314
+ *
315
+ * Returns a mapped type where each key is a procedure name and the value
316
+ * is the awaited return type of that procedure.
317
+ *
318
+ * @template TRouter - The SRPC router type
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * import type { InferRouterOutputs } from "@srpc.org/core";
323
+ * import type { AppRouter } from "./server";
324
+ *
325
+ * type RouterOutputs = InferRouterOutputs<AppRouter>;
326
+ *
327
+ * // Use output types in your code
328
+ * type User = RouterOutputs["getUser"];
329
+ * type Post = RouterOutputs["posts"]["getPost"];
330
+ * ```
331
+ */
332
+ type InferRouterOutputs<TRouter extends AnySRPC> = DecoratedProcedureOutputs<TRouter["ipc"]>;
333
+ /**
334
+ * Type utility that extracts input parameter tuples from all procedures in a router.
335
+ *
336
+ * Recursively processes nested routers and extracts input parameters
337
+ * (excluding context) from each procedure.
338
+ *
339
+ * @template TRouter - The router routes type
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * import type { DecoratedProcedureInputs } from "@srpc/core/shared";
344
+ *
345
+ * const appRouter = s.router({
346
+ * getUser: async (ctx, id: number) => ({ id, name: "John" }),
347
+ * users: s.router({
348
+ * createUser: async (ctx, name: string, email: string) => ({ id: 1, name, email })
349
+ * })
350
+ * });
351
+ *
352
+ * type Routes = typeof appRouter["ipc"];
353
+ * type Inputs = DecoratedProcedureInputs<Routes>;
354
+ * // {
355
+ * // getUser: [id: number],
356
+ * // users: {
357
+ * // createUser: [name: string, email: string]
358
+ * // }
359
+ * // }
360
+ * ```
361
+ */
362
+ type DecoratedProcedureInputs<TRouter extends Routes<any>> = {
363
+ [TKey in keyof TRouter]: TRouter[TKey] extends AnyProcedure ? InferProcedureInput<TRouter[TKey]> : TRouter[TKey] extends SRPC$1<any> ? DecoratedProcedureInputs<TRouter[TKey]["ipc"]> : never;
364
+ };
365
+ /**
366
+ * Type utility to extract input parameter types from all procedures in an SRPC router.
367
+ *
368
+ * Returns a mapped type where each key is a procedure name and the value
369
+ * is a tuple of that procedure's input parameters (excluding context).
370
+ *
371
+ * @template TRouter - The SRPC router type
372
+ *
373
+ * @example
374
+ * ```typescript
375
+ * import type { InferRouterInputs } from "@srpc.org/core";
376
+ * import type { AppRouter } from "./server";
377
+ *
378
+ * type RouterInputs = InferRouterInputs<AppRouter>;
379
+ *
380
+ * // Use input types in your code
381
+ * type GetUserArgs = RouterInputs["getUser"]; // [id: number]
382
+ * type CreatePostArgs = RouterInputs["posts"]["createPost"]; // [title: string, content: string]
383
+ *
384
+ * // Useful for creating type-safe helpers
385
+ * function callGetUser(...args: RouterInputs["getUser"]) {
386
+ * return client.getUser(...args);
387
+ * }
388
+ * ```
389
+ */
390
+ type InferRouterInputs<TRouter extends AnySRPC> = DecoratedProcedureInputs<TRouter["ipc"]>;
391
+
392
+ /**
393
+ * Type representing any routes object with any context.
394
+ *
395
+ * Used as a constraint for generic types that accept any routes.
396
+ */
397
+ type AnyRoutes = Routes<any>;
398
+
399
+ export { SRPCError, StatusCodeMap, createFlatProxy, createRecursiveProxy, defaultSerializer };
400
+ export type { AnyProcedure, AnyRoutes, ClientProcedure, DecoratedProcedureInputs, DecoratedProcedureOutputs, DecoratedProcedureRecord, ErrorCodes, InferProcedureInput, InferRPCFromRouter, InferRouterInputs, InferRouterOutputs, Routes, Serializer };
package/dist/shared.js ADDED
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Used from trpc.io
3
+ */ const noop = ()=>{
4
+ // noop
5
+ };
6
+ const freezeIfAvailable = (obj)=>{
7
+ if (Object.freeze) {
8
+ Object.freeze(obj);
9
+ }
10
+ };
11
+ function createInnerProxy(callback, path, memo) {
12
+ var _memo, _cacheKey;
13
+ const cacheKey = path.join(".");
14
+ (_memo = memo)[_cacheKey = cacheKey] ?? (_memo[_cacheKey] = new Proxy(noop, {
15
+ get (_obj, key) {
16
+ if (typeof key !== "string" || key === "then") {
17
+ // special case for if the proxy is accidentally treated
18
+ // like a PromiseLike (like in `Promise.resolve(proxy)`)
19
+ return undefined;
20
+ }
21
+ return createInnerProxy(callback, [
22
+ ...path,
23
+ key
24
+ ], memo);
25
+ },
26
+ apply (_1, _2, args) {
27
+ const lastOfPath = path[path.length - 1];
28
+ let opts = {
29
+ args,
30
+ path
31
+ };
32
+ // special handling for e.g. `trpc.hello.call(this, 'there')` and `trpc.hello.apply(this, ['there'])
33
+ if (lastOfPath === "call") {
34
+ opts = {
35
+ args: args.length >= 2 ? [
36
+ args[1]
37
+ ] : [],
38
+ path: path.slice(0, -1)
39
+ };
40
+ } else if (lastOfPath === "apply") {
41
+ opts = {
42
+ args: args.length >= 2 ? args[1] : [],
43
+ path: path.slice(0, -1)
44
+ };
45
+ } else if (lastOfPath === "toString") {
46
+ return path.slice(0, -1).join(".");
47
+ } else if (lastOfPath === "toJSON") {
48
+ return {
49
+ path: path.slice(0, -1),
50
+ pathString: path.slice(0, -1).join("."),
51
+ __type: "SRPC"
52
+ };
53
+ }
54
+ freezeIfAvailable(opts.args);
55
+ freezeIfAvailable(opts.path);
56
+ return callback(opts);
57
+ }
58
+ }));
59
+ return memo[cacheKey];
60
+ }
61
+ /**
62
+ * Creates a proxy that calls the callback with the path and arguments
63
+ *
64
+ * @internal
65
+ */ const createRecursiveProxy = (callback)=>createInnerProxy(callback, [], Object.create(null));
66
+ /**
67
+ * Used in place of `new Proxy` where each handler will map 1 level deep to another value.
68
+ *
69
+ * @internal
70
+ */ const createFlatProxy = (callback)=>{
71
+ return new Proxy(noop, {
72
+ get (_obj, name) {
73
+ if (typeof name !== "string" || name === "then") {
74
+ // special case for if the proxy is accidentally treated
75
+ // like a PromiseLike (like in `Promise.resolve(proxy)`)
76
+ return undefined;
77
+ }
78
+ return callback(name);
79
+ }
80
+ });
81
+ };
82
+
83
+ /**
84
+ * Default JSON-based serializer used by SRPC.
85
+ *
86
+ * Uses `JSON.stringify` for serialization and `JSON.parse` for deserialization.
87
+ * Works with JSON-compatible types (strings, numbers, booleans, objects, arrays, null).
88
+ * Does not support: Date, Map, Set, undefined, functions, symbols.
89
+ *
90
+ * For complex types, provide a custom `Serializer` implementation.
91
+ */ const defaultSerializer = {
92
+ serialize: (value)=>JSON.stringify(value),
93
+ deserialize: (value)=>JSON.parse(value)
94
+ };
95
+ /**
96
+ * Mapping of error codes to HTTP status codes.
97
+ *
98
+ * Used internally by server adapters to convert `SRPCError` instances
99
+ * to appropriate HTTP responses.
100
+ */ const StatusCodeMap = {
101
+ BAD_REQUEST: 400,
102
+ NOT_FOUND: 404,
103
+ FORBIDDEN: 403,
104
+ UNAUTHORIZED: 401,
105
+ INTERNAL_SERVER_ERROR: 500,
106
+ NOT_IMPLEMENTED: 501,
107
+ UNSUPPORTED_MEDIA_TYPE: 415,
108
+ GENERIC_ERROR: 500
109
+ };
110
+ /**
111
+ * Standard error class for SRPC procedures.
112
+ *
113
+ * Thrown errors are automatically serialized and sent to the client with
114
+ * the appropriate HTTP status code. The client reconstructs the error
115
+ * with the same message and code.
116
+ *
117
+ * @example Throwing errors in procedures
118
+ * ```typescript
119
+ * import { SRPCError } from "@srpc.org/core";
120
+ *
121
+ * const appRouter = s.router({
122
+ * getUser: async (_, id: number) => {
123
+ * const user = await db.users.findById(id);
124
+ * if (!user) {
125
+ * throw new SRPCError("User not found", "NOT_FOUND");
126
+ * }
127
+ * return user;
128
+ * },
129
+ * deleteUser: async (ctx, id: number) => {
130
+ * if (!ctx.user?.isAdmin) {
131
+ * throw new SRPCError("Insufficient permissions", "FORBIDDEN");
132
+ * }
133
+ * await db.users.delete(id);
134
+ * return { success: true };
135
+ * }
136
+ * });
137
+ * ```
138
+ *
139
+ * @example Handling errors on the client
140
+ * ```typescript
141
+ * import { SRPCError } from "@srpc.org/core";
142
+ *
143
+ * try {
144
+ * const user = await client.getUser(999);
145
+ * } catch (error) {
146
+ * if (error instanceof SRPCError) {
147
+ * switch (error.code) {
148
+ * case "NOT_FOUND":
149
+ * console.log("User not found");
150
+ * break;
151
+ * case "FORBIDDEN":
152
+ * console.log("Access denied");
153
+ * break;
154
+ * case "UNAUTHORIZED":
155
+ * redirectToLogin();
156
+ * break;
157
+ * }
158
+ * }
159
+ * }
160
+ * ```
161
+ */ class SRPCError extends Error {
162
+ constructor(message, code){
163
+ super(message), this.code = code, this.__BRAND__ = "SRPCError";
164
+ this.name = "SRPCError";
165
+ }
166
+ }
167
+
168
+ export { SRPCError, StatusCodeMap, createFlatProxy, createRecursiveProxy, defaultSerializer };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@srpc.org/core",
3
+ "version": "0.20.3",
4
+ "description": "A lightweight, type-safe RPC framework for TypeScript",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./server": {
17
+ "types": "./dist/server.d.ts",
18
+ "default": "./dist/server.js"
19
+ },
20
+ "./client": {
21
+ "types": "./dist/client.d.ts",
22
+ "default": "./dist/client.js"
23
+ },
24
+ "./shared": {
25
+ "types": "./dist/shared.d.ts",
26
+ "default": "./dist/shared.js"
27
+ }
28
+ },
29
+ "keywords": [
30
+ "rpc",
31
+ "typescript",
32
+ "type-safe",
33
+ "api",
34
+ "client",
35
+ "server"
36
+ ],
37
+ "author": "",
38
+ "license": "MIT",
39
+ "devDependencies": {
40
+ "bunchee": "^6.6.2",
41
+ "get-port-please": "^3.1.2",
42
+ "vitest": "^4.0.10"
43
+ },
44
+ "scripts": {
45
+ "build": "bunchee",
46
+ "test": "vitest run",
47
+ "test:dev": "vitest",
48
+ "version": "node ../../version.mjs",
49
+ "release:npm": "pnpm publish --access=public",
50
+ "release:jsr": "pnpx jsr publish"
51
+ }
52
+ }