@b3-business/cherry 0.2.6 → 0.3.0

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.
package/README.md CHANGED
@@ -10,10 +10,12 @@ A tree-shakeable, minimal API client factory. Import only the routes you need
10
10
 
11
11
  ---
12
12
 
13
- ## Latest Changelog - 0.2.6
13
+ ## Latest Changelog - 0.3.0
14
14
 
15
- - Fix npm/JSR badges to update on new versions (rollback HTML to markdown)
16
- - GitHub badge shows repo name instead of stars
15
+ - Fix: Simplify type inference for void params using the same technique as event-bus-core
16
+ - Fix: Allow omitting empty object for calls that don't require params (e.g., `client.listPosts()` instead of `client.listPosts({})`)
17
+ - Fix: Autocomplete for routes now works correctly in IDE
18
+ - Add comprehensive JSDoc comments to types.ts
17
19
 
18
20
  See [CHANGELOG.md](https://github.com/b3-business/cherry/blob/main/packages/cherry/CHANGELOG.md) for full history.
19
21
 
@@ -24,10 +26,10 @@ See [CHANGELOG.md](https://github.com/b3-business/cherry/blob/main/packages/cher
24
26
  Cherry is a lightweight API client library that separates **route definitions** from the **client runtime**. Routes are plain objects with validation schemas — import only what you use, bundle only what you import.
25
27
 
26
28
  ```ts
27
- import { createClient } from "@b3b/cherry";
29
+ import { createCherryClient } from "@b3b/cherry";
28
30
  import { listZones, getZone } from "./routes/cloudflare";
29
31
 
30
- const cf = createClient({
32
+ const cf = createCherryClient({
31
33
  baseUrl: "https://api.cloudflare.com/client/v4",
32
34
  headers: () => ({ Authorization: `Bearer ${process.env.CF_TOKEN}` }),
33
35
  routes: { listZones, getZone },
@@ -96,12 +98,12 @@ deno add jsr:@b3b/cherry
96
98
 
97
99
  ```ts
98
100
  import * as v from "valibot";
99
- import { defineRoute } from "@b3b/cherry";
101
+ import { route, path, param } from "@b3b/cherry";
100
102
 
101
- export const listZones = defineRoute({
103
+ export const listZones = route({
102
104
  method: "GET",
103
- path: "/zones",
104
- params: v.object({
105
+ path: path`/zones`,
106
+ queryParams: v.object({
105
107
  account_id: v.string(),
106
108
  page: v.optional(v.number()),
107
109
  }),
@@ -114,10 +116,10 @@ export const listZones = defineRoute({
114
116
  ### 2. Create a Client
115
117
 
116
118
  ```ts
117
- import { createClient } from "@b3b/cherry";
119
+ import { createCherryClient } from "@b3b/cherry";
118
120
  import { listZones, getZone, createDnsRecord } from "./routes/cloudflare";
119
121
 
120
- const cf = createClient({
122
+ const cf = createCherryClient({
121
123
  baseUrl: "https://api.cloudflare.com/client/v4",
122
124
  headers: () => ({ Authorization: `Bearer ${process.env.CF_TOKEN}` }),
123
125
  routes: { listZones, getZone, createDnsRecord },
@@ -138,23 +140,166 @@ const zones = await cf.call(listZones, { account_id: "abc" });
138
140
 
139
141
  ## Features
140
142
 
141
- ### Dynamic Path Parameters
143
+ ### Path Parameters
144
+
145
+ Use `path` tagged template with `param()` markers for dynamic URL segments:
146
+
147
+ ```ts
148
+ import { route, path, param } from "@b3b/cherry";
149
+
150
+ export const getUser = route({
151
+ method: "GET",
152
+ path: path`/users/${param("id")}`,
153
+ pathParams: v.object({ id: v.number() }),
154
+ response: UserSchema,
155
+ });
156
+
157
+ // Multiple params
158
+ export const getComment = route({
159
+ method: "GET",
160
+ path: path`/posts/${param("postId")}/comments/${param("commentId")}`,
161
+ pathParams: v.object({ postId: v.number(), commentId: v.number() }),
162
+ response: CommentSchema,
163
+ });
164
+ ```
165
+
166
+ ### Optional Path Parameters
167
+
168
+ Use `optional()` for optional URL segments:
169
+
170
+ ```ts
171
+ import { route, path, optional } from "@b3b/cherry";
172
+
173
+ export const getApiResource = route({
174
+ method: "GET",
175
+ path: path`/api${optional("version")}/resource`,
176
+ pathParams: v.object({ version: v.optional(v.string()) }),
177
+ response: ResourceSchema,
178
+ });
179
+ ```
180
+
181
+ ### Query Parameters
182
+
183
+ Define query string parameters with their own schema:
184
+
185
+ ```ts
186
+ export const listUsers = route({
187
+ method: "GET",
188
+ path: path`/users`,
189
+ queryParams: v.object({
190
+ page: v.optional(v.number()),
191
+ limit: v.optional(v.number()),
192
+ search: v.optional(v.string()),
193
+ }),
194
+ response: v.array(UserSchema),
195
+ });
196
+
197
+ // Usage: client.listUsers({ page: 1, limit: 10, search: "john" })
198
+ // → GET /users?page=1&limit=10&search=john
199
+ ```
200
+
201
+ ### Query Array Formats
202
+
203
+ Configure how arrays are serialized in query strings:
142
204
 
143
205
  ```ts
144
- export const getZone = defineRoute({
206
+ export const filterItems = route({
145
207
  method: "GET",
146
- path: (p) => `/zones/${p.zone_id}`,
147
- params: v.object({ zone_id: v.string() }),
148
- response: v.object({ /* ... */ }),
208
+ path: path`/items`,
209
+ queryParams: v.object({ tags: v.array(v.string()) }),
210
+ queryParamOptions: { arrayFormat: "comma" }, // or "repeat" | "brackets" | "json"
211
+ response: v.array(ItemSchema),
212
+ });
213
+
214
+ // arrayFormat examples for tags=["a","b"]:
215
+ // "repeat" → ?tags=a&tags=b (default)
216
+ // "comma" → ?tags=a,b
217
+ // "brackets" → ?tags[]=a&tags[]=b
218
+ // "json" → ?tags=["a","b"]
219
+ ```
220
+
221
+ ### Body Parameters
222
+
223
+ Define request body schema for POST/PUT/PATCH:
224
+
225
+ ```ts
226
+ export const createPost = route({
227
+ method: "POST",
228
+ path: path`/posts`,
229
+ bodyParams: v.object({
230
+ title: v.string(),
231
+ body: v.string(),
232
+ userId: v.number(),
233
+ }),
234
+ response: PostSchema,
235
+ });
236
+ ```
237
+
238
+ ### Namespaced Routes
239
+
240
+ Group related routes into nested objects for better organization:
241
+
242
+ ```ts
243
+ // routes.ts
244
+ export const posts = {
245
+ list: route({ method: "GET", path: path`/posts`, response: v.array(PostSchema) }),
246
+ get: route({ method: "GET", path: path`/posts/${param("id")}`, pathParams: v.object({ id: v.number() }), response: PostSchema }),
247
+ create: route({ method: "POST", path: path`/posts`, bodyParams: PostInputSchema, response: PostSchema }),
248
+ };
249
+
250
+ export const users = {
251
+ list: route({ method: "GET", path: path`/users`, response: v.array(UserSchema) }),
252
+ get: route({ method: "GET", path: path`/users/${param("id")}`, pathParams: v.object({ id: v.number() }), response: UserSchema }),
253
+ };
254
+
255
+ // client.ts
256
+ const api = createCherryClient({
257
+ baseUrl: "https://api.example.com",
258
+ routes: { posts, users },
259
+ });
260
+
261
+ // Usage with namespacing
262
+ await api.posts.list({});
263
+ await api.posts.get({ id: 1 });
264
+ await api.users.get({ id: 42 });
265
+ ```
266
+
267
+ ### Dynamic Headers
268
+
269
+ Provide headers dynamically (supports async for token refresh):
270
+
271
+ ```ts
272
+ const client = createCherryClient({
273
+ baseUrl: "https://api.example.com",
274
+ headers: async () => ({
275
+ Authorization: `Bearer ${await getAccessToken()}`,
276
+ "X-Request-ID": crypto.randomUUID(),
277
+ }),
278
+ routes: { /* ... */ },
149
279
  });
150
280
  ```
151
281
 
282
+ ### Generic `call()` Method
283
+
284
+ Call any route without registering it in the client:
285
+
286
+ ```ts
287
+ import { createCherryClient } from "@b3b/cherry";
288
+ import { getUser, listPosts } from "./routes";
289
+
290
+ const client = createCherryClient({ baseUrl: "https://api.example.com" });
291
+
292
+ // Works with any route - useful for one-off calls or dynamic route selection
293
+ const user = await client.call(getUser, { id: 1 });
294
+ const posts = await client.call(listPosts, {});
295
+ ```
296
+
152
297
  ### Custom Fetcher
153
298
 
154
- Replace the underlying fetch logic for logging, retries, auth refresh, etc.
299
+ Replace the underlying fetch logic for logging, retries, auth refresh, etc.:
155
300
 
156
301
  ```ts
157
- createClient({
302
+ createCherryClient({
158
303
  baseUrl: "...",
159
304
  fetcher: async (req) => {
160
305
  console.log(`→ ${req.init.method} ${req.url}`);
@@ -187,8 +332,106 @@ const withLogging = (fetcher: Fetcher): Fetcher =>
187
332
  return fetcher(req);
188
333
  };
189
334
 
190
- createClient({
191
- fetcher: withLogging(withRetry(defaultFetcher)),
335
+ const baseFetcher: Fetcher = (req) => fetch(req.url, req.init);
336
+
337
+ createCherryClient({
338
+ baseUrl: "...",
339
+ fetcher: withLogging(withRetry(baseFetcher)),
340
+ });
341
+ ```
342
+
343
+ ### Railway-Oriented Error Handling
344
+
345
+ All client methods return `ResultAsync<T, CherryError>` from [neverthrow](https://github.com/supermacro/neverthrow):
346
+
347
+ ```ts
348
+ const result = await client.posts.get({ id: 1 });
349
+
350
+ // Pattern 1: Check and unwrap
351
+ if (result.isOk()) {
352
+ console.log(result.value); // typed as Post
353
+ } else {
354
+ console.error(result.error); // typed as CherryError
355
+ }
356
+
357
+ // Pattern 2: Map/chain operations
358
+ const title = await client.posts.get({ id: 1 })
359
+ .map(post => post.title)
360
+ .unwrapOr("Unknown");
361
+
362
+ // Pattern 3: Match both cases
363
+ result.match(
364
+ (post) => console.log(`Got: ${post.title}`),
365
+ (error) => console.error(`Failed: ${error.message}`),
366
+ );
367
+ ```
368
+
369
+ ### Typed Error Hierarchy
370
+
371
+ All errors extend `CherryError` with `type` and `retryable` properties:
372
+
373
+ ```ts
374
+ import {
375
+ CherryError,
376
+ HttpError, // HTTP 4xx/5xx (retryable for 5xx and 429)
377
+ ValidationError, // Valibot schema validation failed
378
+ NetworkError, // fetch() threw (always retryable)
379
+ SerializationError, // JSON serialization failed
380
+ UnknownCherryError, // Catch-all
381
+ isCherryError,
382
+ } from "@b3b/cherry";
383
+
384
+ const result = await client.posts.get({ id: 1 });
385
+
386
+ if (result.isErr()) {
387
+ const err = result.error;
388
+
389
+ if (err instanceof HttpError) {
390
+ console.log(err.status, err.statusText, err.body);
391
+ if (err.retryable) { /* retry logic */ }
392
+ }
393
+
394
+ if (err instanceof ValidationError) {
395
+ console.log(err.target); // "request" or "response"
396
+ console.log(err.issues); // Valibot issues array
397
+ }
398
+ }
399
+ ```
400
+
401
+ ### Type Inference Utilities
402
+
403
+ Extract input/output types from route definitions:
404
+
405
+ ```ts
406
+ import type { InferRouteInput, InferRouteOutput } from "@b3b/cherry";
407
+ import { getUser } from "./routes";
408
+
409
+ type GetUserInput = InferRouteInput<typeof getUser>;
410
+ // { id: number }
411
+
412
+ type GetUserOutput = InferRouteOutput<typeof getUser>;
413
+ // { id: number; name: string; email: string; ... }
414
+ ```
415
+
416
+ ### Route Validation at Definition Time
417
+
418
+ Routes validate configuration immediately — catch mistakes during development:
419
+
420
+ ```ts
421
+ // ❌ Throws: "Route has path params [id] but no pathParams schema"
422
+ const bad = route({
423
+ method: "GET",
424
+ path: path`/users/${param("id")}`,
425
+ response: UserSchema,
426
+ // Missing pathParams!
427
+ });
428
+
429
+ // ❌ Throws: "Path param ':userId' not found in pathParams schema"
430
+ const mismatch = route({
431
+ method: "GET",
432
+ path: path`/users/${param("userId")}`,
433
+ pathParams: v.object({ id: v.number() }), // Wrong key!
434
+ response: UserSchema,
192
435
  });
193
436
  ```
194
437
 
@@ -204,18 +447,6 @@ createClient({
204
447
 
205
448
  ---
206
449
 
207
- ## Generating Routes from OpenAPI
208
-
209
- Cherry includes a generator that transforms OpenAPI 3.x specs into route definitions:
210
-
211
- ```bash
212
- cherry generate --input ./openapi.json --output ./routes/
213
- ```
214
-
215
- See [ARCHITECTURE.md](./agent/ARCHITECTURE.md) for generator implementation details.
216
-
217
- ---
218
-
219
450
  ## Stack
220
451
 
221
452
  - **Runtime:** Bun
package/dist/index.d.ts CHANGED
@@ -78,8 +78,14 @@ type QueryParamOptions = {
78
78
  customSerializer?: (params: Record<string, unknown>) => string;
79
79
  };
80
80
  type Prettify<T> = { [K in keyof T]: T[K] } & {};
81
- /** Infer combined input params from a route */
82
- type InferRouteInput<T> = T extends CherryRoute<infer TPath, infer TQuery, infer TBody, any> ? Prettify<(TPath extends BaseSchema<any, any, any> ? InferInput<TPath> : {}) & (TQuery extends BaseSchema<any, any, any> ? InferInput<TQuery> : {}) & (TBody extends BaseSchema<any, any, any> ? InferInput<TBody> : {})> : never;
81
+ type HasRequiredKeys<T> = keyof T extends never ? false : true;
82
+ type InferSchemaInput<T> = [T] extends [undefined] ? {} : [NonNullable<T>] extends [never] ? {} : [NonNullable<T>] extends [BaseSchema<any, any, any>] ? InferInput<NonNullable<T>> : {};
83
+ type BuildRouteInputFromProps<TPathParams, TQueryParams, TBodyParams> = InferSchemaInput<TPathParams> & InferSchemaInput<TQueryParams> & InferSchemaInput<TBodyParams>;
84
+ type InferRouteInput<T> = T extends {
85
+ pathParams?: infer TPath;
86
+ queryParams?: infer TQuery;
87
+ bodyParams?: infer TBody;
88
+ } ? HasRequiredKeys<BuildRouteInputFromProps<TPath, TQuery, TBody>> extends true ? Prettify<BuildRouteInputFromProps<TPath, TQuery, TBody>> : void : never;
83
89
  /** Infer response output from a route */
84
90
  type InferRouteOutput<T extends CherryRoute<any, any, any, any>> = T["response"] extends BaseSchema<any, any, any> ? InferOutput<T["response"]> : never;
85
91
  /** Cherry result type - always ResultAsync */
@@ -103,17 +109,17 @@ type ClientConfig<TRoutes extends RouteTree | undefined = undefined> = {
103
109
  routes?: TRoutes;
104
110
  };
105
111
  type Client<TRoutes extends RouteTree | undefined = undefined> = {
106
- call: <T extends CherryRoute<any, any, any, any>>(route: T, params: InferRouteInput<T>) => CherryResult<InferRouteOutput<T>>;
112
+ call: <T extends CherryRoute<any, any, any, any>>(route: T, ...args: InferRouteInput<T> extends void ? [] : [params: InferRouteInput<T>]) => CherryResult<InferRouteOutput<T>>;
107
113
  } & (TRoutes extends RouteTree ? RoutesToClient<TRoutes> : {});
108
114
  /** Convert a nested route tree into a nested client method tree */
109
- type RoutesToClient<TRoutes extends RouteTree> = { [K in keyof TRoutes]: TRoutes[K] extends CherryRoute<any, any, any, any> ? (params: InferRouteInput<TRoutes[K]>) => CherryResult<InferRouteOutput<TRoutes[K]>> : TRoutes[K] extends RouteTree ? RoutesToClient<TRoutes[K]> : never };
115
+ type RoutesToClient<TRoutes extends RouteTree> = { [K in keyof TRoutes]: TRoutes[K] extends CherryRoute<any, any, any, any> ? InferRouteInput<TRoutes[K]> extends void ? () => CherryResult<InferRouteOutput<TRoutes[K]>> : (params: InferRouteInput<TRoutes[K]>) => CherryResult<InferRouteOutput<TRoutes[K]>> : TRoutes[K] extends RouteTree ? RoutesToClient<TRoutes[K]> : never };
110
116
  //#endregion
111
117
  //#region src/cherry_client.d.ts
112
118
  declare function serializeQueryParams(params: Record<string, unknown>, options?: QueryParamOptions): string;
113
119
  declare function createCherryClient<TRoutes extends RouteTree | undefined = undefined>(config: ClientConfig<TRoutes>): Client<TRoutes>;
114
120
  //#endregion
115
121
  //#region src/route.d.ts
116
- type RouteConfig<TPathParams extends v.BaseSchema<any, any, any> | undefined, TQueryParams extends v.BaseSchema<any, any, any> | undefined, TBodyParams extends v.BaseSchema<any, any, any> | undefined, TResponse extends v.BaseSchema<any, any, any>> = {
122
+ type RouteConfig<TPathParams extends v.BaseSchema<any, any, any> | undefined = undefined, TQueryParams extends v.BaseSchema<any, any, any> | undefined = undefined, TBodyParams extends v.BaseSchema<any, any, any> | undefined = undefined, TResponse extends v.BaseSchema<any, any, any> = v.BaseSchema<any, any, any>> = {
117
123
  method: HttpMethod;
118
124
  path: PathTemplate;
119
125
  pathParams?: TPathParams;
@@ -123,7 +129,7 @@ type RouteConfig<TPathParams extends v.BaseSchema<any, any, any> | undefined, TQ
123
129
  queryParamOptions?: QueryParamOptions;
124
130
  description?: string;
125
131
  };
126
- declare function route<TPathParams extends v.BaseSchema<any, any, any> | undefined, TQueryParams extends v.BaseSchema<any, any, any> | undefined, TBodyParams extends v.BaseSchema<any, any, any> | undefined, TResponse extends v.BaseSchema<any, any, any>>(config: RouteConfig<TPathParams, TQueryParams, TBodyParams, TResponse>): CherryRoute<TPathParams, TQueryParams, TBodyParams, TResponse>;
132
+ declare function route<TPathParams extends v.BaseSchema<any, any, any> | undefined = undefined, TQueryParams extends v.BaseSchema<any, any, any> | undefined = undefined, TBodyParams extends v.BaseSchema<any, any, any> | undefined = undefined, TResponse extends v.BaseSchema<any, any, any> = v.BaseSchema<any, any, any>>(config: RouteConfig<TPathParams, TQueryParams, TBodyParams, TResponse>): CherryRoute<TPathParams, TQueryParams, TBodyParams, TResponse>;
127
133
  //#endregion
128
134
  //#region src/path.d.ts
129
135
  /** Branded type for path parameter markers */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/cherry_client.ts","../src/route.ts","../src/path.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/cherry_client.ts","../src/route.ts","../src/path.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["route","result"],"sources":["../src/errors.ts","../src/cherry_client.ts","../src/route.ts","../src/path.ts"],"sourcesContent":["import { errAsync, ResultAsync } from \"neverthrow\";\n\n/** Base error class for all Cherry errors */\nexport abstract class CherryError extends Error {\n abstract readonly type: string;\n abstract readonly retryable: boolean;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = this.constructor.name;\n }\n}\n\n/** HTTP response errors (4xx, 5xx) */\nexport class HttpError extends CherryError {\n readonly type = \"HttpError\";\n readonly retryable: boolean;\n\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly body?: unknown,\n cause?: unknown,\n ) {\n super(`HTTP ${status}: ${statusText}`, { cause });\n this.retryable = status >= 500 || status === 429;\n }\n}\n\n/** Valibot validation errors */\nexport class ValidationError extends CherryError {\n readonly type = \"ValidationError\";\n readonly retryable = false;\n\n constructor(\n public readonly target: \"request\" | \"response\",\n public readonly issues: unknown[],\n cause?: unknown,\n ) {\n super(`Validation failed for ${target}`, { cause });\n }\n}\n\n/** Network/fetch errors */\nexport class NetworkError extends CherryError {\n readonly type = \"NetworkError\";\n readonly retryable = true;\n\n constructor(cause?: unknown) {\n super(`Network error`, { cause });\n }\n}\n\n/** Serialization errors (e.g., circular references, BigInt in JSON) */\nexport class SerializationError extends CherryError {\n readonly type = \"SerializationError\";\n readonly retryable = false;\n\n constructor(\n public readonly target: \"query\" | \"body\",\n public readonly key: string,\n cause?: unknown,\n ) {\n super(`Failed to serialize ${target} parameter \"${key}\"`, { cause });\n }\n}\n\n/** Catch-all for unexpected errors */\nexport class UnknownCherryError extends CherryError {\n readonly type = \"UnknownCherryError\";\n readonly retryable = false;\n\n constructor(cause?: unknown) {\n super(`Unknown error`, { cause });\n }\n}\n\n/** Type guard for CherryError */\nexport function isCherryError(error: unknown): error is CherryError {\n return error instanceof CherryError;\n}\n\n/** Helper to create error ResultAsync */\nexport function cherryErr<T>(error: CherryError): ResultAsync<T, CherryError> {\n return errAsync(error);\n}\n","import { ResultAsync } from \"neverthrow\";\nimport * as v from \"valibot\";\nimport type {\n CherryRoute,\n CherryResult,\n InferRouteInput,\n InferRouteOutput,\n Fetcher,\n FetchRequest,\n ClientConfig,\n Client,\n RouteTree,\n RoutesToClient,\n QueryParamOptions,\n} from \"./types\";\nimport { HttpError, ValidationError, NetworkError, SerializationError, UnknownCherryError } from \"./errors\";\n\nconst defaultFetcher: Fetcher = (req) => fetch(req.url, req.init);\n\nexport function serializeQueryParams(\n params: Record<string, unknown>,\n options?: QueryParamOptions,\n): string {\n if (options?.customSerializer) {\n return options.customSerializer(params);\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n\n if (Array.isArray(value)) {\n switch (options?.arrayFormat ?? \"repeat\") {\n case \"repeat\":\n for (const item of value) {\n searchParams.append(key, String(item));\n }\n break;\n case \"comma\":\n searchParams.set(key, value.join(\",\"));\n break;\n case \"brackets\":\n for (const item of value) {\n searchParams.append(`${key}[]`, String(item));\n }\n break;\n case \"json\":\n try {\n searchParams.set(key, JSON.stringify(value));\n } catch (error) {\n throw new SerializationError(\"query\", key, error);\n }\n break;\n }\n } else {\n searchParams.set(key, String(value));\n }\n }\n\n return searchParams.toString();\n}\n\nexport function createCherryClient<TRoutes extends RouteTree | undefined = undefined>(\n config: ClientConfig<TRoutes>,\n): Client<TRoutes> {\n const fetcher = config.fetcher ?? defaultFetcher;\n\n function call<T extends CherryRoute<any, any, any, any>>(\n route: T,\n params: InferRouteInput<T>,\n ): CherryResult<InferRouteOutput<T>> {\n return ResultAsync.fromPromise(executeRoute(route, params), (error) => {\n if (error instanceof HttpError) return error;\n if (error instanceof ValidationError) return error;\n if (error instanceof NetworkError) return error;\n if (error instanceof SerializationError) return error;\n return new UnknownCherryError(error);\n });\n }\n\n async function executeRoute<T extends CherryRoute<any, any, any, any>>(\n route: T,\n params: InferRouteInput<T>,\n ): Promise<InferRouteOutput<T>> {\n let pathParams: Record<string, unknown> = {};\n if (route.pathParams) {\n const result = v.safeParse(route.pathParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n pathParams = result.output;\n }\n\n let queryParams: Record<string, unknown> = {};\n if (route.queryParams) {\n const result = v.safeParse(route.queryParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n queryParams = result.output;\n }\n\n let bodyParams: Record<string, unknown> | undefined;\n if (route.bodyParams) {\n const result = v.safeParse(route.bodyParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n bodyParams = result.output;\n }\n\n let url = route.path.template;\n for (const [key, value] of Object.entries(pathParams)) {\n url = url.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n\n const fullUrl = new URL(url, config.baseUrl);\n\n if (Object.keys(queryParams).length > 0) {\n fullUrl.search = serializeQueryParams(queryParams, route.queryParamOptions);\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(await config.headers?.()),\n };\n\n const init: RequestInit = {\n method: route.method,\n headers,\n };\n\n if (bodyParams && route.method !== \"GET\") {\n init.body = JSON.stringify(bodyParams);\n }\n\n const req: FetchRequest = {\n url: fullUrl.toString(),\n init,\n };\n\n let response: Response;\n try {\n response = await fetcher(req);\n } catch (error) {\n throw new NetworkError(error);\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => undefined);\n throw new HttpError(response.status, response.statusText, body);\n }\n\n const json = await response.json();\n const result = v.safeParse(route.response, json);\n if (!result.success) throw new ValidationError(\"response\", result.issues);\n\n return result.output;\n }\n\n function forgeRouteMethods<T extends RouteTree>(routes: T): RoutesToClient<T> {\n const out: any = {};\n\n for (const [key, value] of Object.entries(routes)) {\n if (value && typeof value === \"object\" && \"method\" in value && \"path\" in value) {\n out[key] = (params: any) => call(value as any, params);\n } else if (value && typeof value === \"object\") {\n out[key] = forgeRouteMethods(value as RouteTree);\n }\n }\n\n return out;\n }\n\n const routes = config.routes ? forgeRouteMethods(config.routes) : {};\n return { call, ...routes } as Client<TRoutes>;\n}\n","import * as v from \"valibot\";\nimport type {\n CherryRoute,\n HttpMethod,\n PathTemplate,\n QueryParamOptions,\n} from \"./types\";\n\nconst HttpMethodSchema = v.picklist([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"]);\n\nexport type RouteConfig<\n TPathParams extends v.BaseSchema<any, any, any> | undefined,\n TQueryParams extends v.BaseSchema<any, any, any> | undefined,\n TBodyParams extends v.BaseSchema<any, any, any> | undefined,\n TResponse extends v.BaseSchema<any, any, any>,\n> = {\n method: HttpMethod;\n path: PathTemplate;\n pathParams?: TPathParams;\n queryParams?: TQueryParams;\n bodyParams?: TBodyParams;\n response: TResponse;\n queryParamOptions?: QueryParamOptions;\n description?: string;\n};\n\nexport function route<\n TPathParams extends v.BaseSchema<any, any, any> | undefined,\n TQueryParams extends v.BaseSchema<any, any, any> | undefined,\n TBodyParams extends v.BaseSchema<any, any, any> | undefined,\n TResponse extends v.BaseSchema<any, any, any>,\n>(\n config: RouteConfig<TPathParams, TQueryParams, TBodyParams, TResponse>,\n): CherryRoute<TPathParams, TQueryParams, TBodyParams, TResponse> {\n // validate HTTP method\n v.parse(HttpMethodSchema, config.method);\n\n // validate availability and content of pathParams schema, if needed\n if (config.path.paramNames.length > 0) {\n if (!config.pathParams) {\n throw new Error(\n `Route has path params [${config.path.paramNames.join(\", \")}] but no pathParams schema`,\n );\n }\n\n const schemaKeys = getSchemaKeys(config.pathParams);\n\n for (const paramName of config.path.paramNames) {\n if (!schemaKeys.includes(paramName)) {\n throw new Error(\n `Path param \":${paramName}\" not found in pathParams schema. ` +\n `Available: [${schemaKeys.join(\", \")}]`,\n );\n }\n }\n\n for (const schemaKey of schemaKeys) {\n if (!config.path.paramNames.includes(schemaKey)) {\n throw new Error(\n `pathParams schema key \"${schemaKey}\" not present in path template. ` +\n `Template params: [${config.path.paramNames.join(\", \")}]`,\n );\n }\n }\n }\n\n return config as CherryRoute<\n TPathParams,\n TQueryParams,\n TBodyParams,\n TResponse\n >;\n}\n\nfunction getSchemaKeys(schema: v.BaseSchema<any, any, any>): string[] {\n if (\n \"entries\" in schema &&\n typeof (schema as any).entries === \"object\" &&\n (schema as any).entries !== null\n ) {\n return Object.keys((schema as any).entries);\n }\n return [];\n}\n","// path.ts - Tagged template functions for type-safe path building\nimport type { PathTemplate } from \"./types\";\n\n/** Branded type for path parameter markers */\ndeclare const PathParamBrand: unique symbol;\nexport type PathParam<T extends string = string> = string & {\n readonly [PathParamBrand]: T;\n};\n\n/** Branded type for optional path parameter markers */\ndeclare const OptionalParamBrand: unique symbol;\nexport type OptionalParam<T extends string = string> = string & {\n readonly [OptionalParamBrand]: T;\n};\n\n/** Union type for any path param marker */\nexport type AnyPathParam = PathParam<string> | OptionalParam<string>;\n\n/** Create a path parameter marker */\nexport function param<T extends string>(name: T): PathParam<T> {\n return `:${name}` as PathParam<T>;\n}\n\n/** Create an optional path parameter marker */\nexport function optional<T extends string>(name: T): OptionalParam<T> {\n return `(:${name})` as OptionalParam<T>;\n}\n\n/**\n * Tagged template for building path templates.\n *\n * @example\n * ```ts\n * // Simple path with one param\n * const userPath = path`/users/${param(\"id\")}`;\n * // { template: \"/users/:id\", paramNames: [\"id\"] }\n *\n * // Multiple params\n * const postPath = path`/users/${param(\"userId\")}/posts/${param(\"postId\")}`;\n * // { template: \"/users/:userId/posts/:postId\", paramNames: [\"userId\", \"postId\"] }\n *\n * // Optional params\n * const versionedPath = path`/api${optional(\"version\")}/users`;\n * // { template: \"/api(:version)/users\", paramNames: [\"version\"] }\n *\n * // No params\n * const staticPath = path`/health`;\n * // { template: \"/health\", paramNames: [] }\n * ```\n */\nexport function path(\n strings: TemplateStringsArray,\n ...params: AnyPathParam[]\n): PathTemplate {\n const paramNames: string[] = [];\n let template = strings[0];\n\n for (let i = 0; i < params.length; i++) {\n const p = params[i];\n template += p + strings[i + 1];\n\n // Extract param name from `:name` or `(:name)`\n const match = p.match(/^\\(?:(\\w+)\\)?$/);\n if (match) {\n paramNames.push(match[1]);\n }\n }\n\n return { template, paramNames };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["route","result"],"sources":["../src/errors.ts","../src/cherry_client.ts","../src/route.ts","../src/path.ts"],"sourcesContent":["import { errAsync, ResultAsync } from \"neverthrow\";\n\n/** Base error class for all Cherry errors */\nexport abstract class CherryError extends Error {\n abstract readonly type: string;\n abstract readonly retryable: boolean;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = this.constructor.name;\n }\n}\n\n/** HTTP response errors (4xx, 5xx) */\nexport class HttpError extends CherryError {\n readonly type = \"HttpError\";\n readonly retryable: boolean;\n\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly body?: unknown,\n cause?: unknown,\n ) {\n super(`HTTP ${status}: ${statusText}`, { cause });\n this.retryable = status >= 500 || status === 429;\n }\n}\n\n/** Valibot validation errors */\nexport class ValidationError extends CherryError {\n readonly type = \"ValidationError\";\n readonly retryable = false;\n\n constructor(\n public readonly target: \"request\" | \"response\",\n public readonly issues: unknown[],\n cause?: unknown,\n ) {\n super(`Validation failed for ${target}`, { cause });\n }\n}\n\n/** Network/fetch errors */\nexport class NetworkError extends CherryError {\n readonly type = \"NetworkError\";\n readonly retryable = true;\n\n constructor(cause?: unknown) {\n super(`Network error`, { cause });\n }\n}\n\n/** Serialization errors (e.g., circular references, BigInt in JSON) */\nexport class SerializationError extends CherryError {\n readonly type = \"SerializationError\";\n readonly retryable = false;\n\n constructor(\n public readonly target: \"query\" | \"body\",\n public readonly key: string,\n cause?: unknown,\n ) {\n super(`Failed to serialize ${target} parameter \"${key}\"`, { cause });\n }\n}\n\n/** Catch-all for unexpected errors */\nexport class UnknownCherryError extends CherryError {\n readonly type = \"UnknownCherryError\";\n readonly retryable = false;\n\n constructor(cause?: unknown) {\n super(`Unknown error`, { cause });\n }\n}\n\n/** Type guard for CherryError */\nexport function isCherryError(error: unknown): error is CherryError {\n return error instanceof CherryError;\n}\n\n/** Helper to create error ResultAsync */\nexport function cherryErr<T>(error: CherryError): ResultAsync<T, CherryError> {\n return errAsync(error);\n}\n","import { ResultAsync } from \"neverthrow\";\nimport * as v from \"valibot\";\nimport type {\n CherryRoute,\n CherryResult,\n InferRouteInput,\n InferRouteOutput,\n Fetcher,\n FetchRequest,\n ClientConfig,\n Client,\n RouteTree,\n RoutesToClient,\n QueryParamOptions,\n} from \"./types\";\nimport { HttpError, ValidationError, NetworkError, SerializationError, UnknownCherryError } from \"./errors\";\n\nconst defaultFetcher: Fetcher = (req) => fetch(req.url, req.init);\n\nexport function serializeQueryParams(\n params: Record<string, unknown>,\n options?: QueryParamOptions,\n): string {\n if (options?.customSerializer) {\n return options.customSerializer(params);\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n\n if (Array.isArray(value)) {\n switch (options?.arrayFormat ?? \"repeat\") {\n case \"repeat\":\n for (const item of value) {\n searchParams.append(key, String(item));\n }\n break;\n case \"comma\":\n searchParams.set(key, value.join(\",\"));\n break;\n case \"brackets\":\n for (const item of value) {\n searchParams.append(`${key}[]`, String(item));\n }\n break;\n case \"json\":\n try {\n searchParams.set(key, JSON.stringify(value));\n } catch (error) {\n throw new SerializationError(\"query\", key, error);\n }\n break;\n }\n } else {\n searchParams.set(key, String(value));\n }\n }\n\n return searchParams.toString();\n}\n\nexport function createCherryClient<TRoutes extends RouteTree | undefined = undefined>(\n config: ClientConfig<TRoutes>,\n): Client<TRoutes> {\n const fetcher = config.fetcher ?? defaultFetcher;\n\n function call<T extends CherryRoute<any, any, any, any>>(\n route: T,\n params: InferRouteInput<T>,\n ): CherryResult<InferRouteOutput<T>> {\n return ResultAsync.fromPromise(executeRoute(route, params), (error) => {\n if (error instanceof HttpError) return error;\n if (error instanceof ValidationError) return error;\n if (error instanceof NetworkError) return error;\n if (error instanceof SerializationError) return error;\n return new UnknownCherryError(error);\n });\n }\n\n async function executeRoute<T extends CherryRoute<any, any, any, any>>(\n route: T,\n params: InferRouteInput<T>,\n ): Promise<InferRouteOutput<T>> {\n let pathParams: Record<string, unknown> = {};\n if (route.pathParams) {\n const result = v.safeParse(route.pathParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n pathParams = result.output;\n }\n\n let queryParams: Record<string, unknown> = {};\n if (route.queryParams) {\n const result = v.safeParse(route.queryParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n queryParams = result.output;\n }\n\n let bodyParams: Record<string, unknown> | undefined;\n if (route.bodyParams) {\n const result = v.safeParse(route.bodyParams, params);\n if (!result.success) throw new ValidationError(\"request\", result.issues);\n bodyParams = result.output;\n }\n\n let url = route.path.template;\n for (const [key, value] of Object.entries(pathParams)) {\n url = url.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n\n const fullUrl = new URL(url, config.baseUrl);\n\n if (Object.keys(queryParams).length > 0) {\n fullUrl.search = serializeQueryParams(queryParams, route.queryParamOptions);\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(await config.headers?.()),\n };\n\n const init: RequestInit = {\n method: route.method,\n headers,\n };\n\n if (bodyParams && route.method !== \"GET\") {\n init.body = JSON.stringify(bodyParams);\n }\n\n const req: FetchRequest = {\n url: fullUrl.toString(),\n init,\n };\n\n let response: Response;\n try {\n response = await fetcher(req);\n } catch (error) {\n throw new NetworkError(error);\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => undefined);\n throw new HttpError(response.status, response.statusText, body);\n }\n\n const json = await response.json();\n const result = v.safeParse(route.response, json);\n if (!result.success) throw new ValidationError(\"response\", result.issues);\n\n return result.output;\n }\n\n function forgeRouteMethods<T extends RouteTree>(routes: T): RoutesToClient<T> {\n const out: any = {};\n\n for (const [key, value] of Object.entries(routes)) {\n if (value && typeof value === \"object\" && \"method\" in value && \"path\" in value) {\n out[key] = (params: any) => call(value as any, params);\n } else if (value && typeof value === \"object\") {\n out[key] = forgeRouteMethods(value as RouteTree);\n }\n }\n\n return out;\n }\n\n const routes = config.routes ? forgeRouteMethods(config.routes) : {};\n return { call, ...routes } as Client<TRoutes>;\n}\n","import * as v from \"valibot\";\nimport type {\n CherryRoute,\n HttpMethod,\n PathTemplate,\n QueryParamOptions,\n} from \"./types\";\n\nconst HttpMethodSchema = v.picklist([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"]);\n\nexport type RouteConfig<\n TPathParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TQueryParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TBodyParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TResponse extends v.BaseSchema<any, any, any> = v.BaseSchema<any, any, any>,\n> = {\n method: HttpMethod;\n path: PathTemplate;\n pathParams?: TPathParams;\n queryParams?: TQueryParams;\n bodyParams?: TBodyParams;\n response: TResponse;\n queryParamOptions?: QueryParamOptions;\n description?: string;\n};\n\nexport function route<\n TPathParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TQueryParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TBodyParams extends v.BaseSchema<any, any, any> | undefined = undefined,\n TResponse extends v.BaseSchema<any, any, any> = v.BaseSchema<any, any, any>,\n>(\n config: RouteConfig<TPathParams, TQueryParams, TBodyParams, TResponse>,\n): CherryRoute<TPathParams, TQueryParams, TBodyParams, TResponse> {\n // validate HTTP method\n v.parse(HttpMethodSchema, config.method);\n\n // validate availability and content of pathParams schema, if needed\n if (config.path.paramNames.length > 0) {\n if (!config.pathParams) {\n throw new Error(\n `Route has path params [${config.path.paramNames.join(\", \")}] but no pathParams schema`,\n );\n }\n\n const schemaKeys = getSchemaKeys(config.pathParams);\n\n for (const paramName of config.path.paramNames) {\n if (!schemaKeys.includes(paramName)) {\n throw new Error(\n `Path param \":${paramName}\" not found in pathParams schema. ` +\n `Available: [${schemaKeys.join(\", \")}]`,\n );\n }\n }\n\n for (const schemaKey of schemaKeys) {\n if (!config.path.paramNames.includes(schemaKey)) {\n throw new Error(\n `pathParams schema key \"${schemaKey}\" not present in path template. ` +\n `Template params: [${config.path.paramNames.join(\", \")}]`,\n );\n }\n }\n }\n\n return config as CherryRoute<\n TPathParams,\n TQueryParams,\n TBodyParams,\n TResponse\n >;\n}\n\nfunction getSchemaKeys(schema: v.BaseSchema<any, any, any>): string[] {\n if (\n \"entries\" in schema &&\n typeof (schema as any).entries === \"object\" &&\n (schema as any).entries !== null\n ) {\n return Object.keys((schema as any).entries);\n }\n return [];\n}\n","// path.ts - Tagged template functions for type-safe path building\nimport type { PathTemplate } from \"./types\";\n\n/** Branded type for path parameter markers */\ndeclare const PathParamBrand: unique symbol;\nexport type PathParam<T extends string = string> = string & {\n readonly [PathParamBrand]: T;\n};\n\n/** Branded type for optional path parameter markers */\ndeclare const OptionalParamBrand: unique symbol;\nexport type OptionalParam<T extends string = string> = string & {\n readonly [OptionalParamBrand]: T;\n};\n\n/** Union type for any path param marker */\nexport type AnyPathParam = PathParam<string> | OptionalParam<string>;\n\n/** Create a path parameter marker */\nexport function param<T extends string>(name: T): PathParam<T> {\n return `:${name}` as PathParam<T>;\n}\n\n/** Create an optional path parameter marker */\nexport function optional<T extends string>(name: T): OptionalParam<T> {\n return `(:${name})` as OptionalParam<T>;\n}\n\n/**\n * Tagged template for building path templates.\n *\n * @example\n * ```ts\n * // Simple path with one param\n * const userPath = path`/users/${param(\"id\")}`;\n * // { template: \"/users/:id\", paramNames: [\"id\"] }\n *\n * // Multiple params\n * const postPath = path`/users/${param(\"userId\")}/posts/${param(\"postId\")}`;\n * // { template: \"/users/:userId/posts/:postId\", paramNames: [\"userId\", \"postId\"] }\n *\n * // Optional params\n * const versionedPath = path`/api${optional(\"version\")}/users`;\n * // { template: \"/api(:version)/users\", paramNames: [\"version\"] }\n *\n * // No params\n * const staticPath = path`/health`;\n * // { template: \"/health\", paramNames: [] }\n * ```\n */\nexport function path(\n strings: TemplateStringsArray,\n ...params: AnyPathParam[]\n): PathTemplate {\n const paramNames: string[] = [];\n let template = strings[0];\n\n for (let i = 0; i < params.length; i++) {\n const p = params[i];\n template += p + strings[i + 1];\n\n // Extract param name from `:name` or `(:name)`\n const match = p.match(/^\\(?:(\\w+)\\)?$/);\n if (match) {\n paramNames.push(match[1]);\n }\n }\n\n return { template, paramNames };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3-business/cherry",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "A tree-shakeable, minimal API client factory. Import only the routes you need — nothing more.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,25 +8,19 @@
8
8
  },
9
9
  "license": "MIT",
10
10
  "type": "module",
11
- "main": "./dist/index.js",
12
11
  "types": "./dist/index.d.ts",
13
12
  "exports": {
14
- ".": {
15
- "import": {
16
- "types": "./dist/index.d.ts",
17
- "default": "./dist/index.js"
18
- }
19
- }
13
+ ".": "./src/index.ts",
14
+ "./package.json": "./package.json"
20
15
  },
21
16
  "files": [
22
17
  "dist"
23
18
  ],
24
19
  "scripts": {
25
20
  "build": "tsdown",
26
- "check": "run-s lint typecheck typecheck-test",
21
+ "check": "run-s lint typecheck",
27
22
  "lint": "oxlint src test",
28
23
  "typecheck": "tsc --noEmit -p .",
29
- "typecheck-test": "tsc --noEmit -p tsconfig.test.json",
30
24
  "test": "bun test",
31
25
  "prepublishOnly": "npm run check && npm run test && npm run build",
32
26
  "dry-npm": "npm publish --dry-run --access public",
@@ -44,5 +38,11 @@
44
38
  "oxlint": "^1.36.0",
45
39
  "tsdown": "^0.19.0-beta.2",
46
40
  "typescript": "^5.9.3"
41
+ },
42
+ "publishConfig": {
43
+ "exports": {
44
+ ".": "./dist/index.js",
45
+ "./package.json": "./package.json"
46
+ }
47
47
  }
48
48
  }