@zap-studio/fetch 2.1.0 → 2.1.1

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/CHANGELOG.md CHANGED
@@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [2.1.0]
7
+ ## [2.1.1]
8
+
9
+ ### Changed
10
+
11
+ Reverted the `@zap-studio/monads` dependency and the `$fetchResult`/`apiResult`/`createFetch(...).​$fetchResult`/`createFetch(...).​apiResult` exports added in 2.1.0 — they added a dependency and bundle size cost for a use case consumers can already cover themselves by wrapping `$fetch`/`api` with `@zap-studio/monads`'s `fromPromise`. See the README's "Using with `@zap-studio/monads`" section. 2.1.0 is deprecated on npm in favor of this release.
12
+
13
+ ## [2.1.0] (deprecated — see 2.1.1)
8
14
 
9
15
  ### Added
10
16
 
package/README.md CHANGED
@@ -30,7 +30,6 @@ You also need a schema library that implements [Standard Schema](https://standar
30
30
  - **Configured clients** through `createFetch(...)` with shared `baseURL`, headers, query params, and error defaults.
31
31
  - **JSON convenience** through the `json` option, which serializes the request body and sets `Content-Type`.
32
32
  - **Structured errors** with `FetchError` for HTTP failures and `ValidationError` for schema failures.
33
- - **`Result`-returning variant** through `$fetchResult`/`apiResult`, for explicit error handling with [`@zap-studio/monads`](https://www.npmjs.com/package/@zap-studio/monads) instead of throw/catch.
34
33
  - **Validator-agnostic** — works with any library that implements Standard Schema.
35
34
  - **Optional logging** through `createFetch({ logger })` ([`@zap-studio/logger`](https://www.npmjs.com/package/@zap-studio/logger)) — omit it and there's zero logging overhead.
36
35
  - **Tree-shakeable** — every export is a standalone function with no shared internal state; unused exports are dropped by any modern bundler.
@@ -130,25 +129,6 @@ try {
130
129
  }
131
130
  ```
132
131
 
133
- ## Result-Returning Variant
134
-
135
- `$fetchResult`/`apiResult` — additive alternative to `$fetch`/`api` for consumers who prefer explicit [`Result`](https://www.zapstudio.dev/monads/result)/[`ResultAsync`](https://www.zapstudio.dev/monads/result-async) values over throw/catch. `createFetch(...)` instances get `$fetchResult`/`apiResult` too, alongside `$fetch`/`api`.
136
-
137
- ```ts
138
- import { isOk } from "@zap-studio/monads";
139
- import { apiResult } from "@zap-studio/fetch";
140
-
141
- const result = await apiResult.get("/api/users/1", UserSchema);
142
-
143
- if (isOk(result)) {
144
- console.log(result.value);
145
- } else {
146
- console.error(result.error); // FetchError | ValidationError
147
- }
148
- ```
149
-
150
- There's no `throwOnFetchError`/`throwOnValidationError` option — these always return a `Result`. A non-ok response and validation issues both become `Err`; a malformed schema or request still throws, since that's a programmer error, not a value to branch on.
151
-
152
132
  ## Validator-Agnostic
153
133
 
154
134
  Works with any library that implements Standard Schema.
@@ -195,6 +175,23 @@ await api.get("/users/1", UserSchema);
195
175
 
196
176
  On failure — a non-2xx response or a thrown error — the span is marked `ERROR`; thrown errors are also recorded as span exceptions.
197
177
 
178
+ ## Using with `@zap-studio/monads`
179
+
180
+ This package has no dependency on `@zap-studio/monads` — nothing is added to your
181
+ bundle unless you install it yourself. If you want a `Result` instead of throw/catch,
182
+ wrap the call with `@zap-studio/monads`'s `fromPromise`, mapping the rejection into
183
+ your error type:
184
+
185
+ ```ts
186
+ import { fromPromise } from "@zap-studio/monads";
187
+ import { api } from "@zap-studio/fetch";
188
+
189
+ const result = fromPromise(
190
+ api.get("/users/1", UserSchema, { throwOnFetchError: true, throwOnValidationError: true }),
191
+ (error) => error,
192
+ );
193
+ ```
194
+
198
195
  ## Runtime Support
199
196
 
200
197
  | Runtime | Minimum version |
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { FetchError } from "./errors.js";
2
- import { $Fetch, $FetchResult, ApiMethods, ApiResultMethods, ExtendedRequestInit, FetchDefaults, FetchInput, FetchInstance, FetchResultRequestInit, NormalizedRequest } from "./types.js";
3
- import { ResultAsync } from "@zap-studio/monads";
4
- import { StandardSchemaV1, ValidationError } from "@zap-studio/validation";
2
+ import { $Fetch, ApiMethods, ExtendedRequestInit, FetchDefaults, FetchInput, FetchInstance, NormalizedRequest } from "./types.js";
3
+ import { StandardSchemaV1 } from "@zap-studio/validation";
5
4
  //#region src/index.d.ts
6
5
  /**
7
6
  * Default options for the global $fetch
@@ -68,50 +67,6 @@ declare function $fetch<TSchema extends StandardSchemaV1>(input: FetchInput, sch
68
67
  throwOnValidationError?: true;
69
68
  }): Promise<StandardSchemaV1.InferOutput<TSchema>>;
70
69
  declare function $fetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;
71
- /**
72
- * `Result`-returning counterpart to {@link $fetch}, for consumers who prefer
73
- * explicit `Result`/`ResultAsync` values (from `@zap-studio/monads`) over
74
- * throw/catch.
75
- *
76
- * There's no `throwOnFetchError`/`throwOnValidationError` option — this
77
- * function always returns a `Result`, so the flags don't apply. A non-ok
78
- * response and validation issues both become `Err`; a malformed schema or
79
- * request still throws, since that's a programmer error, not a value to
80
- * branch on.
81
- *
82
- * If no schema is provided, resolves to `Ok` with the raw `Response` object
83
- * (still `Err(FetchError)` on a non-ok response).
84
- *
85
- * @throws {TypeError} When both `body` and `json` are provided, when JSON request
86
- * serialization fails, when request construction fails, when headers/search params are
87
- * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`
88
- * implementation rejects network-level failures as `TypeError`.
89
- * @throws {DOMException} When the runtime rejects an aborted request or response body read
90
- * as an `AbortError` DOMException.
91
- * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the
92
- * response body.
93
- * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator
94
- * that isn't a `ValidationError`.
95
- *
96
- * @example
97
- * ```ts
98
- * import { isOk } from "@zap-studio/monads";
99
- * import { $fetchResult } from "@zap-studio/fetch";
100
- * import { z } from "zod";
101
- *
102
- * const UserSchema = z.object({ id: z.number(), name: z.string() });
103
- *
104
- * const result = await $fetchResult("/api/users/1", UserSchema);
105
- *
106
- * if (isOk(result)) {
107
- * console.log("Validated user:", result.value);
108
- * } else {
109
- * console.error("Failed:", result.error);
110
- * }
111
- * ```
112
- */
113
- declare function $fetchResult<TSchema extends StandardSchemaV1>(input: FetchInput, schema: TSchema, options?: FetchResultRequestInit): ResultAsync<StandardSchemaV1.InferOutput<TSchema>, FetchError | ValidationError>;
114
- declare function $fetchResult(input: FetchInput, options?: FetchResultRequestInit): ResultAsync<Response, FetchError>;
115
70
  /**
116
71
  * Convenience methods for common HTTP verbs.
117
72
  *
@@ -136,22 +91,6 @@ declare function $fetchResult(input: FetchInput, options?: FetchResultRequestIni
136
91
  * }
137
92
  */
138
93
  declare const api: ApiMethods;
139
- /**
140
- * `Result`-returning counterpart to {@link api}.
141
- *
142
- * @example
143
- * import { z } from "zod";
144
- * import { apiResult } from "@zap-studio/fetch";
145
- *
146
- * const PostSchema = z.object({
147
- * id: z.number(),
148
- * title: z.string(),
149
- * content: z.string(),
150
- * });
151
- *
152
- * const result = await apiResult.get(`https://api.example.com/posts/1`, PostSchema);
153
- */
154
- declare const apiResult: ApiResultMethods;
155
94
  /**
156
95
  * Creates a custom fetch instance with pre-configured defaults.
157
96
  *
@@ -181,5 +120,5 @@ declare const apiResult: ApiResultMethods;
181
120
  */
182
121
  declare const createFetch: (factoryOptions?: Partial<FetchDefaults>) => FetchInstance;
183
122
  //#endregion
184
- export { type $Fetch, type $FetchResult, $fetch, $fetchResult, type ApiMethods, type ApiResultMethods, type ExtendedRequestInit, type FetchDefaults, FetchError, type FetchInput, type FetchInstance, type FetchResultRequestInit, GLOBAL_DEFAULTS, type NormalizedRequest, api, apiResult, createFetch };
123
+ export { type $Fetch, $fetch, type ApiMethods, type ExtendedRequestInit, type FetchDefaults, FetchError, type FetchInput, type FetchInstance, GLOBAL_DEFAULTS, type NormalizedRequest, api, createFetch };
185
124
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cAmEa,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAygBR,OAAO,gBAAgB,kBAC3C,OAAO,YACP,QAAQ,SACR,SAAS;EAAwB;IAChC,QAAQ,iBAAiB,OAAO,iBAAiB,YAAY;iBAE1C,OAAO,gBAAgB,kBAC3C,OAAO,YACP,QAAQ,SACR,UAAU;EAAwB;IACjC,QAAQ,iBAAiB,YAAY;iBAElB,OAAO,OAAO,YAAY,UAAU,sBAAsB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwDxE,aAAa,gBAAgB,kBAC3C,OAAO,YACP,QAAQ,SACR,UAAU,yBACT,YAAY,iBAAiB,YAAY,UAAU,aAAa;iBAEnD,aACd,OAAO,YACP,UAAU,yBACT,YAAY,UAAU;;;;;;;;;;;;;;;;;;;;;;;;cAqCZ,KAAK;;;;;;;;;;;;;;;;cAuBL,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmCX,cAAe,iBAAgB,QAAQ,mBAAsB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;cA2Da,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwbR,OAAO,gBAAgB,kBAC3C,OAAO,YACP,QAAQ,SACR,SAAS;EAAwB;IAChC,QAAQ,iBAAiB,OAAO,iBAAiB,YAAY;iBAE1C,OAAO,gBAAgB,kBAC3C,OAAO,YACP,QAAQ,SACR,UAAU;EAAwB;IACjC,QAAQ,iBAAiB,YAAY;iBAElB,OAAO,OAAO,YAAY,UAAU,sBAAsB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;cAqC3E,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmCL,cAAe,iBAAgB,QAAQ,mBAAsB"}
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { FetchError } from "./errors.js";
2
2
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
3
- import { ResultAsync, err, ok } from "@zap-studio/monads";
4
- import { ValidationError, isStandardSchema, standardValidate } from "@zap-studio/validation";
3
+ import { isStandardSchema, standardValidate } from "@zap-studio/validation";
5
4
  //#endregion
6
5
  //#region src/_otel.ts
7
6
  /**
@@ -9,7 +8,7 @@ import { ValidationError, isStandardSchema, standardValidate } from "@zap-studio
9
8
  * `TracerProvider`; a no-op provider (the default until an app registers an
10
9
  * SDK) makes every span/propagation call below a no-op too.
11
10
  */
12
- const tracer = trace.getTracer("@zap-studio/fetch", "2.1.0");
11
+ const tracer = trace.getTracer("@zap-studio/fetch", "2.1.1");
13
12
  /**
14
13
  * `TextMapSetter` for the Web `Headers` API, used to inject `traceparent`
15
14
  * (and any other registered propagator fields) into the outgoing request.
@@ -259,63 +258,6 @@ const fetchInternal = async (input, schema, options, defaults) => {
259
258
  }
260
259
  };
261
260
  /**
262
- * Runs `fetchInternal` with both throw flags forced to `true`, converting a
263
- * thrown `FetchError`/`ValidationError` into `Err` instead of rethrowing.
264
- *
265
- * Any other thrown value (malformed input, a `TypeError`/`DOMException`/
266
- * `SyntaxError`, or an unknown validator throw) is a programmer error, not a
267
- * value a caller should branch on, and propagates unchanged.
268
- *
269
- * @throws {unknown} Any error thrown or rejected by `fetchInternal` that isn't a
270
- * `FetchError` or `ValidationError`.
271
- */
272
- const fetchInternalResult = async (input, schema, options, defaults) => {
273
- try {
274
- const requestInit = {
275
- ...options,
276
- throwOnFetchError: true,
277
- throwOnValidationError: true
278
- };
279
- const value = await fetchInternal(input, schema, requestInit, defaults);
280
- return ok(value);
281
- } catch (error) {
282
- if (error instanceof FetchError || error instanceof ValidationError) return err(error);
283
- throw error;
284
- }
285
- };
286
- /**
287
- * Creates an HTTP method helper bound to a `Result`-returning fetch function.
288
- *
289
- * The returned function mirrors `$FetchResult`'s overloads but forces the
290
- * provided HTTP method (`GET`, `POST`, etc.) into request options.
291
- *
292
- * @param fetchFn - `Result`-returning fetch function to wrap.
293
- * @param method - HTTP method to enforce.
294
- * @returns Method-bound `Result`-returning fetch function.
295
- *
296
- * @example
297
- * const get = createMethodResult($fetchResult, "GET");
298
- * const result = await get("/users/1", UserSchema);
299
- */
300
- const createMethodResult = (fetchFn, method) => {
301
- /**
302
- * Method-bound `$FetchResult` implementation.
303
- *
304
- * Resolves the schema/options overload and injects the configured HTTP method.
305
- */
306
- function methodFetch(input, schemaOrOptions, optionsOrUndefined) {
307
- if (isStandardSchema(schemaOrOptions)) return fetchFn(input, schemaOrOptions, {
308
- ...optionsOrUndefined,
309
- method
310
- });
311
- return fetchFn(input, {
312
- ...schemaOrOptions,
313
- method
314
- });
315
- }
316
- return methodFetch;
317
- };
318
- /**
319
261
  * Creates an HTTP method helper bound to a fetch function.
320
262
  *
321
263
  * The returned function mirrors `$Fetch` overloads but forces the provided
@@ -366,10 +308,6 @@ async function $fetch(input, schemaOrOptions, optionsOrUndefined) {
366
308
  const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
367
309
  return await fetchInternal(input, schema, options, GLOBAL_DEFAULTS);
368
310
  }
369
- function $fetchResult(input, schemaOrOptions, optionsOrUndefined) {
370
- const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
371
- return new ResultAsync(fetchInternalResult(input, schema, options, GLOBAL_DEFAULTS));
372
- }
373
311
  /**
374
312
  * Convenience methods for common HTTP verbs.
375
313
  *
@@ -401,28 +339,6 @@ const api = {
401
339
  put: createMethod($fetch, "PUT")
402
340
  };
403
341
  /**
404
- * `Result`-returning counterpart to {@link api}.
405
- *
406
- * @example
407
- * import { z } from "zod";
408
- * import { apiResult } from "@zap-studio/fetch";
409
- *
410
- * const PostSchema = z.object({
411
- * id: z.number(),
412
- * title: z.string(),
413
- * content: z.string(),
414
- * });
415
- *
416
- * const result = await apiResult.get(`https://api.example.com/posts/1`, PostSchema);
417
- */
418
- const apiResult = {
419
- delete: createMethodResult($fetchResult, "DELETE"),
420
- get: createMethodResult($fetchResult, "GET"),
421
- patch: createMethodResult($fetchResult, "PATCH"),
422
- post: createMethodResult($fetchResult, "POST"),
423
- put: createMethodResult($fetchResult, "PUT")
424
- };
425
- /**
426
342
  * Creates a custom fetch instance with pre-configured defaults.
427
343
  *
428
344
  * Use this factory to create API clients with a base URL, default headers,
@@ -461,31 +377,18 @@ const createFetch = (factoryOptions = {}) => {
461
377
  const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
462
378
  return await fetchInternal(input, schema, options, defaults);
463
379
  }
464
- const customApi = {
465
- delete: createMethod(customFetch, "DELETE"),
466
- get: createMethod(customFetch, "GET"),
467
- patch: createMethod(customFetch, "PATCH"),
468
- post: createMethod(customFetch, "POST"),
469
- put: createMethod(customFetch, "PUT")
470
- };
471
- function customFetchResult(input, schemaOrOptions, optionsOrUndefined) {
472
- const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
473
- return new ResultAsync(fetchInternalResult(input, schema, options, defaults));
474
- }
475
380
  return {
476
381
  $fetch: customFetch,
477
- $fetchResult: customFetchResult,
478
- api: customApi,
479
- apiResult: {
480
- delete: createMethodResult(customFetchResult, "DELETE"),
481
- get: createMethodResult(customFetchResult, "GET"),
482
- patch: createMethodResult(customFetchResult, "PATCH"),
483
- post: createMethodResult(customFetchResult, "POST"),
484
- put: createMethodResult(customFetchResult, "PUT")
382
+ api: {
383
+ delete: createMethod(customFetch, "DELETE"),
384
+ get: createMethod(customFetch, "GET"),
385
+ patch: createMethod(customFetch, "PATCH"),
386
+ post: createMethod(customFetch, "POST"),
387
+ put: createMethod(customFetch, "PUT")
485
388
  }
486
389
  };
487
390
  };
488
391
  //#endregion
489
- export { $fetch, $fetchResult, FetchError, GLOBAL_DEFAULTS, api, apiResult, createFetch };
392
+ export { $fetch, FetchError, GLOBAL_DEFAULTS, api, createFetch };
490
393
 
491
394
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["pkg.name","pkg.version","otelContext"],"sources":["../package.json","../src/_otel.ts","../src/index.ts"],"sourcesContent":["","/**\n * Internal OpenTelemetry wiring for the fetch package: tracer resolution,\n * the `Headers` propagation carrier, and span error recording. Kept out of\n * `index.ts` so request logic doesn't get tangled with tracing concerns.\n *\n * @module @zap-studio/fetch/otel\n */\n\nimport type { Span, TextMapSetter, Tracer } from \"@opentelemetry/api\";\n\nimport { SpanStatusCode, trace } from \"@opentelemetry/api\";\n\nimport pkg from \"../package.json\" with { type: \"json\" };\n\n/**\n * OpenTelemetry tracer for this package. Resolved once against the global\n * `TracerProvider`; a no-op provider (the default until an app registers an\n * SDK) makes every span/propagation call below a no-op too.\n */\nexport const tracer: Tracer = trace.getTracer(pkg.name, pkg.version);\n\n/**\n * `TextMapSetter` for the Web `Headers` API, used to inject `traceparent`\n * (and any other registered propagator fields) into the outgoing request.\n */\nexport const HEADERS_SETTER: TextMapSetter<Headers> = {\n set(carrier, key, value) {\n carrier.set(key, value);\n },\n};\n\n/**\n * Records `error` on `span` and marks it as failed. `recordException` only\n * accepts an `Error` or `string`, so other thrown values just get the\n * `ERROR` status without an attached exception event.\n */\nexport const recordSpanError = (span: Span, error: unknown): void => {\n if (error instanceof Error || typeof error === \"string\") {\n span.recordException(error);\n }\n span.setStatus({ code: SpanStatusCode.ERROR });\n};\n","/**\n * Public entrypoint for the fetch package.\n *\n * Exports `$fetch`, `api`, `createFetch`, `FetchError`, `GLOBAL_DEFAULTS`,\n * and the public type contracts. `FetchError` and the type contracts are\n * also available from dedicated subpaths (`@zap-studio/fetch/errors`,\n * `@zap-studio/fetch/types`) for consumers who prefer granular imports. All\n * exports are side-effect free and tree-shakeable.\n *\n * @module @zap-studio/fetch\n */\n\nimport type { Logger } from \"@zap-studio/logger\";\nimport type { Result } from \"@zap-studio/monads\";\nimport type { StandardSchemaV1 } from \"@zap-studio/validation\";\n\nimport {\n SpanKind,\n SpanStatusCode,\n context as otelContext,\n propagation,\n trace,\n} from \"@opentelemetry/api\";\nimport { err, ok, ResultAsync } from \"@zap-studio/monads\";\nimport { isStandardSchema, standardValidate, ValidationError } from \"@zap-studio/validation\";\n\nimport type {\n $Fetch,\n $FetchResult,\n ApiMethods,\n ApiResultMethods,\n ExtendedRequestInit,\n FetchDefaults,\n FetchInput,\n FetchInstance,\n FetchResultRequestInit,\n NormalizedRequest,\n} from \"./types.ts\";\n\nimport { HEADERS_SETTER, recordSpanError, tracer } from \"./_otel.ts\";\nimport { FetchError } from \"./errors.ts\";\n\nexport { FetchError } from \"./errors.ts\";\nexport type {\n $Fetch,\n $FetchResult,\n ApiMethods,\n ApiResultMethods,\n ExtendedRequestInit,\n FetchDefaults,\n FetchInput,\n FetchInstance,\n FetchResultRequestInit,\n NormalizedRequest,\n} from \"./types.ts\";\n\n/**\n * Default options for the global $fetch\n *\n * These defaults are used by the top-level `$fetch` export.\n * Use `createFetch(...)` when you need per-client defaults.\n *\n * @example\n * import { GLOBAL_DEFAULTS } from \"@zap-studio/fetch\";\n *\n * console.log(GLOBAL_DEFAULTS.throwOnFetchError); // true\n */\nexport const GLOBAL_DEFAULTS: FetchDefaults = {\n baseURL: \"\",\n throwOnFetchError: true,\n throwOnValidationError: true,\n};\n\n/**\n * Merges two HeadersInit objects, with the second one taking precedence.\n *\n * @param base - Base/default headers.\n * @param override - Request-level override headers.\n * @returns A merged `Headers` object, or `undefined` when both inputs are empty.\n * @throws {TypeError} When either header input contains invalid header names or values.\n */\nconst mergeHeaders = (base?: HeadersInit, override?: HeadersInit): Headers | undefined => {\n if (base === undefined && override === undefined) {\n return undefined;\n }\n\n const merged = new Headers(base);\n for (const [key, value] of new Headers(override).entries()) {\n merged.set(key, value);\n }\n return merged;\n};\n\n// SAFETY: Every property of `ExtendedRequestInit` is optional, so `{}` is already a structurally valid value; the cast only pins the type.\nconst EMPTY_OPTIONS = {} as ExtendedRequestInit;\n\n/**\n * Normalizes fetch `input` and request-level options into a consistent internal shape.\n *\n * @param input - Request URL/path or Request instance.\n * @param options - Optional request options.\n * @returns A normalized request structure for internal processing.\n * @throws {TypeError} When cloning a `Request` fails or the merged headers are invalid.\n */\nconst normalizeRequest = (input: FetchInput, options?: ExtendedRequestInit): NormalizedRequest => {\n if (!(input instanceof Request)) {\n const url = input instanceof URL ? input.href : input;\n return {\n options: options ?? EMPTY_OPTIONS,\n url,\n };\n }\n\n const request = new Request(input);\n const { headers, ...rest } = options ?? {};\n const mergedHeaders = mergeHeaders(request.headers, headers);\n // SAFETY: `rest` is `options` with only the `headers` key removed, so it's already structurally an `ExtendedRequestInit` minus `headers`, which is set below.\n const normalizedOptions = { ...rest } as ExtendedRequestInit;\n\n if (mergedHeaders !== undefined) {\n normalizedOptions.headers = mergedHeaders;\n }\n\n return {\n options: normalizedOptions,\n request,\n url: request.url,\n };\n};\n\n/**\n * Copies search params into target, overriding duplicate keys.\n */\nconst mergeSearchParams = (\n target: URLSearchParams,\n source: ExtendedRequestInit[\"searchParams\"] | undefined,\n): void => {\n for (const [key, value] of new URLSearchParams(source)) {\n target.set(key, value);\n }\n};\n\n/**\n * Ensures a URL has a trailing slash for relative URL resolution.\n */\nconst ensureTrailingSlash = (url: string): string => (url.endsWith(\"/\") ? url : `${url}/`);\n\n/**\n * Resolves search params by applying default params, URL params, then request params.\n */\nconst resolveSearchParams = (\n url: string,\n defaultSearchParams: FetchDefaults[\"searchParams\"] | undefined,\n searchParams: ExtendedRequestInit[\"searchParams\"] | undefined,\n): string => {\n if (defaultSearchParams === undefined && searchParams === undefined) {\n return url;\n }\n\n const hashIndex = url.indexOf(\"#\");\n const hasFragment = hashIndex !== -1;\n const urlWithoutHash = hasFragment ? url.slice(0, hashIndex) : url;\n const hash = hasFragment ? url.slice(hashIndex + 1) : \"\";\n const queryIndex = urlWithoutHash.indexOf(\"?\");\n const pathname = queryIndex === -1 ? urlWithoutHash : urlWithoutHash.slice(0, queryIndex);\n const urlSearchParams = queryIndex === -1 ? undefined : urlWithoutHash.slice(queryIndex + 1);\n const resolvedSearchParams = new URLSearchParams();\n\n mergeSearchParams(resolvedSearchParams, defaultSearchParams);\n mergeSearchParams(resolvedSearchParams, urlSearchParams);\n mergeSearchParams(resolvedSearchParams, searchParams);\n\n const resolvedSearch = resolvedSearchParams.toString();\n const fragmentSuffix = hasFragment ? `#${hash}` : \"\";\n\n if (resolvedSearch.length === 0) {\n return `${pathname}${fragmentSuffix}`;\n }\n\n return `${pathname}?${resolvedSearch}${fragmentSuffix}`;\n};\n\n/**\n * Resolves final request URL by applying baseURL and layered search params.\n *\n * Search param precedence:\n * 1. `defaults.searchParams`\n * 2. search params already present in `resourceUrl`\n * 3. per-request `searchParams`\n *\n * @throws {TypeError} When `baseURL` and `resourceUrl` cannot be resolved by\n * `URL`, or when default/per-request search params cannot be converted by\n * `URLSearchParams`.\n */\nconst resolveRequestUrl = (\n resourceUrl: string,\n defaults: FetchDefaults,\n searchParams?: ExtendedRequestInit[\"searchParams\"],\n): string => {\n const url = defaults.baseURL\n ? new URL(resourceUrl, ensureTrailingSlash(defaults.baseURL)).toString()\n : resourceUrl;\n\n return resolveSearchParams(url, defaults.searchParams, searchParams);\n};\n\n/**\n * Normalizes request-level options into a final RequestInit payload and runtime flags.\n *\n * @param options - Request-level options.\n * @param defaults - Client-level defaults.\n * @returns Fully merged request init payload and effective runtime flags.\n */\nconst prepareRequestInit = (options: ExtendedRequestInit, defaults: FetchDefaults) => {\n const {\n headers,\n json,\n searchParams,\n throwOnFetchError = defaults.throwOnFetchError,\n throwOnValidationError = defaults.throwOnValidationError,\n ...rest\n } = options;\n\n const init: RequestInit = { ...rest };\n const mergedHeaders = mergeHeaders(defaults.headers, headers);\n if (mergedHeaders !== undefined) {\n init.headers = mergedHeaders;\n }\n\n if (json !== undefined) {\n if (init.body !== undefined && init.body !== null) {\n throw new TypeError(\"Cannot provide both `body` and `json`.\");\n }\n\n init.body = JSON.stringify(json);\n const requestHeaders = new Headers(init.headers);\n if (!requestHeaders.has(\"Content-Type\")) {\n requestHeaders.set(\"Content-Type\", \"application/json\");\n }\n init.headers = requestHeaders;\n }\n\n return {\n init,\n searchParams,\n throwOnFetchError,\n throwOnValidationError,\n };\n};\n\n/**\n * Logs a fetch response: `debug` for 2xx, `warn` otherwise.\n */\nconst logResponse = (\n logger: Logger | undefined,\n method: string,\n url: string,\n response: Response,\n): void => {\n const context = { method, status: response.status, url };\n if (response.ok) {\n logger?.debug(\"fetch response\", context);\n } else {\n logger?.warn(\"fetch response\", context);\n }\n};\n\n/**\n * Validates the raw JSON payload against `schema`, logging a `fetch\n * validation failed` message at `error` on failure regardless of throw mode.\n *\n * @throws {unknown} Any error thrown by `standardValidate` in throw mode.\n */\nconst validateResponse = async (\n raw: unknown,\n schema: StandardSchemaV1,\n throwOnValidationError: boolean,\n logger: Logger | undefined,\n url: string,\n): Promise<unknown> => {\n if (throwOnValidationError) {\n try {\n return await standardValidate(raw, schema, { throwOnError: true });\n } catch (error) {\n logger?.error(\"fetch validation failed\", { error, url });\n throw error;\n }\n }\n\n const result = await standardValidate(raw, schema, { throwOnError: false });\n if (result.issues) {\n logger?.error(\"fetch validation failed\", { issues: result.issues, url });\n }\n return result;\n};\n\n/**\n * Internal fetch implementation used by both $fetch and createFetch.\n *\n * This function normalizes request input, resolves final URL + query params,\n * executes `fetch`, optionally throws `FetchError`, and optionally validates\n * JSON response payloads using Standard Schema.\n *\n * @param input - Request URL, path, or Request object.\n * @param schema - Optional Standard Schema for response validation.\n * @param options - Optional request options and package-specific flags.\n * @param defaults - Effective client defaults.\n * @returns Raw `Response` when no schema is provided; otherwise validated output.\n * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.\n * @throws {ValidationError} When a schema is provided, validation returns issues, and\n * `throwOnValidationError` is `true`.\n * @throws {TypeError} When both `body` and `json` are provided, when JSON request\n * serialization fails, when request construction fails, when headers/search params are\n * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`\n * implementation rejects network-level failures as `TypeError`.\n * @throws {DOMException} When the runtime rejects an aborted request or response body read\n * as an `AbortError` DOMException.\n * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the\n * response body.\n * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.\n */\nconst fetchInternal = async (\n input: FetchInput,\n schema: StandardSchemaV1 | undefined,\n options: ExtendedRequestInit | undefined,\n defaults: FetchDefaults,\n): Promise<unknown> => {\n const { logger } = defaults;\n const request = normalizeRequest(input, options);\n const { init, searchParams, throwOnFetchError, throwOnValidationError } = prepareRequestInit(\n request.options,\n defaults,\n );\n const url = resolveRequestUrl(request.url, defaults, searchParams);\n const method = init.method ?? \"GET\";\n\n logger?.debug(\"fetch request\", { method, url });\n\n const span = tracer.startSpan(method, {\n attributes: {\n \"http.request.method\": method,\n \"url.full\": url,\n },\n kind: SpanKind.CLIENT,\n });\n const spanContext = trace.setSpan(otelContext.active(), span);\n\n try {\n return await otelContext.with(spanContext, async () => {\n const headers = new Headers(init.headers);\n propagation.inject(spanContext, headers, HEADERS_SETTER);\n init.headers = headers;\n\n const response = request.request\n ? await fetch(new Request(url, request.request), init)\n : await fetch(url, init);\n\n logResponse(logger, method, url, response);\n span.setAttribute(\"http.response.status_code\", response.status);\n if (!response.ok) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n if (throwOnFetchError && !response.ok) {\n throw new FetchError(`HTTP ${response.status}: ${response.statusText}`, response);\n }\n\n if (schema === undefined) {\n return response;\n }\n\n const raw: unknown = await response.json();\n return await validateResponse(raw, schema, throwOnValidationError, logger, url);\n });\n } catch (error) {\n recordSpanError(span, error);\n throw error;\n } finally {\n span.end();\n }\n};\n\n/**\n * Runs `fetchInternal` with both throw flags forced to `true`, converting a\n * thrown `FetchError`/`ValidationError` into `Err` instead of rethrowing.\n *\n * Any other thrown value (malformed input, a `TypeError`/`DOMException`/\n * `SyntaxError`, or an unknown validator throw) is a programmer error, not a\n * value a caller should branch on, and propagates unchanged.\n *\n * @throws {unknown} Any error thrown or rejected by `fetchInternal` that isn't a\n * `FetchError` or `ValidationError`.\n */\nconst fetchInternalResult = async (\n input: FetchInput,\n schema: StandardSchemaV1 | undefined,\n options: FetchResultRequestInit | undefined,\n defaults: FetchDefaults,\n): Promise<Result<unknown, FetchError | ValidationError>> => {\n try {\n // SAFETY: `options` is `FetchResultRequestInit`, i.e. `ExtendedRequestInit` minus the two throw flags set explicitly below, so this spread is already structurally a valid `ExtendedRequestInit`.\n const requestInit = {\n ...options,\n throwOnFetchError: true,\n throwOnValidationError: true,\n } as ExtendedRequestInit;\n const value = await fetchInternal(input, schema, requestInit, defaults);\n return ok(value);\n } catch (error) {\n if (error instanceof FetchError || error instanceof ValidationError) {\n return err(error);\n }\n\n throw error;\n }\n};\n\n/**\n * Creates an HTTP method helper bound to a `Result`-returning fetch function.\n *\n * The returned function mirrors `$FetchResult`'s overloads but forces the\n * provided HTTP method (`GET`, `POST`, etc.) into request options.\n *\n * @param fetchFn - `Result`-returning fetch function to wrap.\n * @param method - HTTP method to enforce.\n * @returns Method-bound `Result`-returning fetch function.\n *\n * @example\n * const get = createMethodResult($fetchResult, \"GET\");\n * const result = await get(\"/users/1\", UserSchema);\n */\nconst createMethodResult = (fetchFn: $FetchResult, method: string): $FetchResult => {\n function methodFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: FetchResultRequestInit,\n ): ResultAsync<StandardSchemaV1.InferOutput<TSchema>, FetchError | ValidationError>;\n\n function methodFetch(\n input: FetchInput,\n options?: FetchResultRequestInit,\n ): ResultAsync<Response, FetchError>;\n\n /**\n * Method-bound `$FetchResult` implementation.\n *\n * Resolves the schema/options overload and injects the configured HTTP method.\n */\n function methodFetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | FetchResultRequestInit,\n optionsOrUndefined?: FetchResultRequestInit,\n ): ResultAsync<unknown, FetchError | ValidationError> {\n if (isStandardSchema(schemaOrOptions)) {\n return fetchFn(input, schemaOrOptions, { ...optionsOrUndefined, method });\n }\n\n return fetchFn(input, { ...schemaOrOptions, method });\n }\n\n return methodFetch;\n};\n\n/**\n * Creates an HTTP method helper bound to a fetch function.\n *\n * The returned function mirrors `$Fetch` overloads but forces the provided\n * HTTP method (`GET`, `POST`, etc.) into request options.\n *\n * @param fetchFn - Fetch function to wrap.\n * @param method - HTTP method to enforce.\n * @returns Method-bound fetch function.\n * @throws {unknown} Any error thrown or rejected by `fetchFn` when the returned method-bound\n * fetch function is called.\n *\n * @example\n * const get = createMethod($fetch, \"GET\");\n * const user = await get(\"/users/1\", UserSchema);\n */\nconst createMethod = (fetchFn: $Fetch, method: string): $Fetch => {\n function methodFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & {\n throwOnValidationError: false;\n },\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n function methodFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & {\n throwOnValidationError?: true;\n },\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n function methodFetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\n /**\n * Method-bound `$Fetch` implementation.\n *\n * Resolves schema/option overloads and injects the configured HTTP method.\n */\n async function methodFetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n ): Promise<unknown> {\n if (isStandardSchema(schemaOrOptions)) {\n if (optionsOrUndefined?.throwOnValidationError === false) {\n return await fetchFn(input, schemaOrOptions, {\n ...optionsOrUndefined,\n method,\n throwOnValidationError: false,\n });\n }\n\n const { throwOnValidationError, ...restOptions } = optionsOrUndefined ?? {};\n\n if (throwOnValidationError === true) {\n return await fetchFn(input, schemaOrOptions, {\n ...restOptions,\n method,\n throwOnValidationError: true,\n });\n }\n\n return await fetchFn(input, schemaOrOptions, {\n ...restOptions,\n method,\n });\n }\n\n return await fetchFn(input, {\n ...schemaOrOptions,\n method,\n });\n }\n\n return methodFetch;\n};\n\n/**\n * Type-safe fetch wrapper with Standard Schema validation.\n *\n * - When `throwOnValidationError: true`: validated data of type `TSchema`\n * - When `throwOnValidationError: false`: Standard Schema Result object `{ value?, issues? }`\n * - When `throwOnFetchError: true`: throws `FetchError` on non-ok responses\n *\n * If no schema is provided, returns the raw `Response` object.\n *\n * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.\n * @throws {ValidationError} When a schema is provided, validation returns issues, and\n * `throwOnValidationError` is `true`.\n * @throws {TypeError} When both `body` and `json` are provided, when JSON request\n * serialization fails, when request construction fails, when headers/search params are\n * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`\n * implementation rejects network-level failures as `TypeError`.\n * @throws {DOMException} When the runtime rejects an aborted request or response body read\n * as an `AbortError` DOMException.\n * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the\n * response body.\n * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.\n *\n * @example\n * import { z } from \"zod\";\n * import { $fetch } from \"@zap-studio/fetch\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage (schema validation)\n * const user = await $fetch(\"/api/users/1\", UserSchema, { headers: { \"Authorization\": \"Bearer token\" } });\n * console.log(\"Validated user:\", user);\n *\n * // Raw usage (no schema validation and typed Response object)\n * const result = await $fetch(\"/api/data\", { method: \"POST\", body: JSON.stringify({ key: \"value\" }) });\n * const json = await result.json() as ResultType;\n * console.log(\"Raw response data:\", json);\n *\n * // Usage with validation errors returned instead of thrown\n * const result = await $fetch(\"/api/users/1\", UserSchema, { throwOnValidationError: false });\n *\n * if (result.issues) {\n * console.error(\"Validation errors:\", result.issues);\n * } else {\n * console.log(\"Validated user:\", result.value);\n * }\n */\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & { throwOnValidationError: false },\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & { throwOnValidationError?: true },\n): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\nexport async function $fetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\nexport async function $fetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(input, schema, options, GLOBAL_DEFAULTS);\n}\n\n/**\n * `Result`-returning counterpart to {@link $fetch}, for consumers who prefer\n * explicit `Result`/`ResultAsync` values (from `@zap-studio/monads`) over\n * throw/catch.\n *\n * There's no `throwOnFetchError`/`throwOnValidationError` option — this\n * function always returns a `Result`, so the flags don't apply. A non-ok\n * response and validation issues both become `Err`; a malformed schema or\n * request still throws, since that's a programmer error, not a value to\n * branch on.\n *\n * If no schema is provided, resolves to `Ok` with the raw `Response` object\n * (still `Err(FetchError)` on a non-ok response).\n *\n * @throws {TypeError} When both `body` and `json` are provided, when JSON request\n * serialization fails, when request construction fails, when headers/search params are\n * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`\n * implementation rejects network-level failures as `TypeError`.\n * @throws {DOMException} When the runtime rejects an aborted request or response body read\n * as an `AbortError` DOMException.\n * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the\n * response body.\n * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator\n * that isn't a `ValidationError`.\n *\n * @example\n * ```ts\n * import { isOk } from \"@zap-studio/monads\";\n * import { $fetchResult } from \"@zap-studio/fetch\";\n * import { z } from \"zod\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * const result = await $fetchResult(\"/api/users/1\", UserSchema);\n *\n * if (isOk(result)) {\n * console.log(\"Validated user:\", result.value);\n * } else {\n * console.error(\"Failed:\", result.error);\n * }\n * ```\n */\nexport function $fetchResult<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: FetchResultRequestInit,\n): ResultAsync<StandardSchemaV1.InferOutput<TSchema>, FetchError | ValidationError>;\n\nexport function $fetchResult(\n input: FetchInput,\n options?: FetchResultRequestInit,\n): ResultAsync<Response, FetchError>;\n\nexport function $fetchResult(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | FetchResultRequestInit,\n optionsOrUndefined?: FetchResultRequestInit,\n): ResultAsync<unknown, FetchError | ValidationError> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return new ResultAsync(fetchInternalResult(input, schema, options, GLOBAL_DEFAULTS));\n}\n\n/**\n * Convenience methods for common HTTP verbs.\n *\n * These methods always require a schema for validation.\n * For raw responses without validation, use `$fetch` directly.\n *\n * Each method has the same throw behavior as {@link $fetch}.\n *\n * @example\n * import { z } from \"zod\";\n * import { api } from \"@zap-studio/fetch\";\n *\n * const PostSchema = z.object({\n * id: z.number(),\n * title: z.string(),\n * content: z.string(),\n * });\n *\n * async function fetchPost(postId: number) {\n * const post = await api.get(`https://api.example.com/posts/${postId}`, PostSchema);\n * return post; // post is typed as { id: number; title: string; content: string; }\n * }\n */\nexport const api: ApiMethods = {\n delete: createMethod($fetch, \"DELETE\"),\n get: createMethod($fetch, \"GET\"),\n patch: createMethod($fetch, \"PATCH\"),\n post: createMethod($fetch, \"POST\"),\n put: createMethod($fetch, \"PUT\"),\n};\n\n/**\n * `Result`-returning counterpart to {@link api}.\n *\n * @example\n * import { z } from \"zod\";\n * import { apiResult } from \"@zap-studio/fetch\";\n *\n * const PostSchema = z.object({\n * id: z.number(),\n * title: z.string(),\n * content: z.string(),\n * });\n *\n * const result = await apiResult.get(`https://api.example.com/posts/1`, PostSchema);\n */\nexport const apiResult: ApiResultMethods = {\n delete: createMethodResult($fetchResult, \"DELETE\"),\n get: createMethodResult($fetchResult, \"GET\"),\n patch: createMethodResult($fetchResult, \"PATCH\"),\n post: createMethodResult($fetchResult, \"POST\"),\n put: createMethodResult($fetchResult, \"PUT\"),\n};\n\n/**\n * Creates a custom fetch instance with pre-configured defaults.\n *\n * Use this factory to create API clients with a base URL, default headers,\n * and other shared configuration. Each instance is independent.\n *\n * The returned `$fetch` and `api` methods have the same throw behavior as the\n * top-level {@link $fetch} export.\n *\n * @example\n * import { z } from \"zod\";\n * import { createFetch } from \"@zap-studio/fetch\";\n *\n * // Create a configured instance\n * const { $fetch, api } = createFetch({\n * baseURL: \"https://api.example.com\",\n * headers: { \"Authorization\": \"Bearer token\" },\n * });\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Now use relative paths - baseURL is prepended automatically\n * const user = await api.get(\"/users/1\", UserSchema);\n *\n * // Or use $fetch directly\n * const response = await $fetch(\"/users\", UserSchema, { method: \"POST\", json: { name: \"John\" } });\n */\nexport const createFetch = (factoryOptions: Partial<FetchDefaults> = {}): FetchInstance => {\n const defaults: FetchDefaults = {\n ...GLOBAL_DEFAULTS,\n ...factoryOptions,\n baseURL: factoryOptions.baseURL ?? GLOBAL_DEFAULTS.baseURL,\n throwOnFetchError: factoryOptions.throwOnFetchError ?? GLOBAL_DEFAULTS.throwOnFetchError,\n throwOnValidationError:\n factoryOptions.throwOnValidationError ?? GLOBAL_DEFAULTS.throwOnValidationError,\n };\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & { throwOnValidationError: false },\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & {\n throwOnValidationError?: true;\n },\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n async function customFetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\n async function customFetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(input, schema, options, defaults);\n }\n\n const customApi = {\n delete: createMethod(customFetch, \"DELETE\"),\n get: createMethod(customFetch, \"GET\"),\n patch: createMethod(customFetch, \"PATCH\"),\n post: createMethod(customFetch, \"POST\"),\n put: createMethod(customFetch, \"PUT\"),\n };\n\n function customFetchResult<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: FetchResultRequestInit,\n ): ResultAsync<StandardSchemaV1.InferOutput<TSchema>, FetchError | ValidationError>;\n\n function customFetchResult(\n input: FetchInput,\n options?: FetchResultRequestInit,\n ): ResultAsync<Response, FetchError>;\n\n function customFetchResult(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | FetchResultRequestInit,\n optionsOrUndefined?: FetchResultRequestInit,\n ): ResultAsync<unknown, FetchError | ValidationError> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return new ResultAsync(fetchInternalResult(input, schema, options, defaults));\n }\n\n const customApiResult: ApiResultMethods = {\n delete: createMethodResult(customFetchResult, \"DELETE\"),\n get: createMethodResult(customFetchResult, \"GET\"),\n patch: createMethodResult(customFetchResult, \"PATCH\"),\n post: createMethodResult(customFetchResult, \"POST\"),\n put: createMethodResult(customFetchResult, \"PUT\"),\n };\n\n return {\n $fetch: customFetch,\n $fetchResult: customFetchResult,\n api: customApi,\n apiResult: customApiResult,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["pkg.name","pkg.version","otelContext"],"sources":["../package.json","../src/_otel.ts","../src/index.ts"],"sourcesContent":["","/**\n * Internal OpenTelemetry wiring for the fetch package: tracer resolution,\n * the `Headers` propagation carrier, and span error recording. Kept out of\n * `index.ts` so request logic doesn't get tangled with tracing concerns.\n *\n * @module @zap-studio/fetch/otel\n */\n\nimport type { Span, TextMapSetter, Tracer } from \"@opentelemetry/api\";\n\nimport { SpanStatusCode, trace } from \"@opentelemetry/api\";\n\nimport pkg from \"../package.json\" with { type: \"json\" };\n\n/**\n * OpenTelemetry tracer for this package. Resolved once against the global\n * `TracerProvider`; a no-op provider (the default until an app registers an\n * SDK) makes every span/propagation call below a no-op too.\n */\nexport const tracer: Tracer = trace.getTracer(pkg.name, pkg.version);\n\n/**\n * `TextMapSetter` for the Web `Headers` API, used to inject `traceparent`\n * (and any other registered propagator fields) into the outgoing request.\n */\nexport const HEADERS_SETTER: TextMapSetter<Headers> = {\n set(carrier, key, value) {\n carrier.set(key, value);\n },\n};\n\n/**\n * Records `error` on `span` and marks it as failed. `recordException` only\n * accepts an `Error` or `string`, so other thrown values just get the\n * `ERROR` status without an attached exception event.\n */\nexport const recordSpanError = (span: Span, error: unknown): void => {\n if (error instanceof Error || typeof error === \"string\") {\n span.recordException(error);\n }\n span.setStatus({ code: SpanStatusCode.ERROR });\n};\n","/**\n * Public entrypoint for the fetch package.\n *\n * Exports `$fetch`, `api`, `createFetch`, `FetchError`, `GLOBAL_DEFAULTS`,\n * and the public type contracts. `FetchError` and the type contracts are\n * also available from dedicated subpaths (`@zap-studio/fetch/errors`,\n * `@zap-studio/fetch/types`) for consumers who prefer granular imports. All\n * exports are side-effect free and tree-shakeable.\n *\n * @module @zap-studio/fetch\n */\n\nimport type { Logger } from \"@zap-studio/logger\";\nimport type { StandardSchemaV1 } from \"@zap-studio/validation\";\n\nimport {\n SpanKind,\n SpanStatusCode,\n context as otelContext,\n propagation,\n trace,\n} from \"@opentelemetry/api\";\nimport { isStandardSchema, standardValidate } from \"@zap-studio/validation\";\n\nimport type {\n $Fetch,\n ApiMethods,\n ExtendedRequestInit,\n FetchDefaults,\n FetchInput,\n FetchInstance,\n NormalizedRequest,\n} from \"./types.ts\";\n\nimport { HEADERS_SETTER, recordSpanError, tracer } from \"./_otel.ts\";\nimport { FetchError } from \"./errors.ts\";\n\nexport { FetchError } from \"./errors.ts\";\nexport type {\n $Fetch,\n ApiMethods,\n ExtendedRequestInit,\n FetchDefaults,\n FetchInput,\n FetchInstance,\n NormalizedRequest,\n} from \"./types.ts\";\n\n/**\n * Default options for the global $fetch\n *\n * These defaults are used by the top-level `$fetch` export.\n * Use `createFetch(...)` when you need per-client defaults.\n *\n * @example\n * import { GLOBAL_DEFAULTS } from \"@zap-studio/fetch\";\n *\n * console.log(GLOBAL_DEFAULTS.throwOnFetchError); // true\n */\nexport const GLOBAL_DEFAULTS: FetchDefaults = {\n baseURL: \"\",\n throwOnFetchError: true,\n throwOnValidationError: true,\n};\n\n/**\n * Merges two HeadersInit objects, with the second one taking precedence.\n *\n * @param base - Base/default headers.\n * @param override - Request-level override headers.\n * @returns A merged `Headers` object, or `undefined` when both inputs are empty.\n * @throws {TypeError} When either header input contains invalid header names or values.\n */\nconst mergeHeaders = (base?: HeadersInit, override?: HeadersInit): Headers | undefined => {\n if (base === undefined && override === undefined) {\n return undefined;\n }\n\n const merged = new Headers(base);\n for (const [key, value] of new Headers(override).entries()) {\n merged.set(key, value);\n }\n return merged;\n};\n\n// SAFETY: Every property of `ExtendedRequestInit` is optional, so `{}` is already a structurally valid value; the cast only pins the type.\nconst EMPTY_OPTIONS = {} as ExtendedRequestInit;\n\n/**\n * Normalizes fetch `input` and request-level options into a consistent internal shape.\n *\n * @param input - Request URL/path or Request instance.\n * @param options - Optional request options.\n * @returns A normalized request structure for internal processing.\n * @throws {TypeError} When cloning a `Request` fails or the merged headers are invalid.\n */\nconst normalizeRequest = (input: FetchInput, options?: ExtendedRequestInit): NormalizedRequest => {\n if (!(input instanceof Request)) {\n const url = input instanceof URL ? input.href : input;\n return {\n options: options ?? EMPTY_OPTIONS,\n url,\n };\n }\n\n const request = new Request(input);\n const { headers, ...rest } = options ?? {};\n const mergedHeaders = mergeHeaders(request.headers, headers);\n // SAFETY: `rest` is `options` with only the `headers` key removed, so it's already structurally an `ExtendedRequestInit` minus `headers`, which is set below.\n const normalizedOptions = { ...rest } as ExtendedRequestInit;\n\n if (mergedHeaders !== undefined) {\n normalizedOptions.headers = mergedHeaders;\n }\n\n return {\n options: normalizedOptions,\n request,\n url: request.url,\n };\n};\n\n/**\n * Copies search params into target, overriding duplicate keys.\n */\nconst mergeSearchParams = (\n target: URLSearchParams,\n source: ExtendedRequestInit[\"searchParams\"] | undefined,\n): void => {\n for (const [key, value] of new URLSearchParams(source)) {\n target.set(key, value);\n }\n};\n\n/**\n * Ensures a URL has a trailing slash for relative URL resolution.\n */\nconst ensureTrailingSlash = (url: string): string => (url.endsWith(\"/\") ? url : `${url}/`);\n\n/**\n * Resolves search params by applying default params, URL params, then request params.\n */\nconst resolveSearchParams = (\n url: string,\n defaultSearchParams: FetchDefaults[\"searchParams\"] | undefined,\n searchParams: ExtendedRequestInit[\"searchParams\"] | undefined,\n): string => {\n if (defaultSearchParams === undefined && searchParams === undefined) {\n return url;\n }\n\n const hashIndex = url.indexOf(\"#\");\n const hasFragment = hashIndex !== -1;\n const urlWithoutHash = hasFragment ? url.slice(0, hashIndex) : url;\n const hash = hasFragment ? url.slice(hashIndex + 1) : \"\";\n const queryIndex = urlWithoutHash.indexOf(\"?\");\n const pathname = queryIndex === -1 ? urlWithoutHash : urlWithoutHash.slice(0, queryIndex);\n const urlSearchParams = queryIndex === -1 ? undefined : urlWithoutHash.slice(queryIndex + 1);\n const resolvedSearchParams = new URLSearchParams();\n\n mergeSearchParams(resolvedSearchParams, defaultSearchParams);\n mergeSearchParams(resolvedSearchParams, urlSearchParams);\n mergeSearchParams(resolvedSearchParams, searchParams);\n\n const resolvedSearch = resolvedSearchParams.toString();\n const fragmentSuffix = hasFragment ? `#${hash}` : \"\";\n\n if (resolvedSearch.length === 0) {\n return `${pathname}${fragmentSuffix}`;\n }\n\n return `${pathname}?${resolvedSearch}${fragmentSuffix}`;\n};\n\n/**\n * Resolves final request URL by applying baseURL and layered search params.\n *\n * Search param precedence:\n * 1. `defaults.searchParams`\n * 2. search params already present in `resourceUrl`\n * 3. per-request `searchParams`\n *\n * @throws {TypeError} When `baseURL` and `resourceUrl` cannot be resolved by\n * `URL`, or when default/per-request search params cannot be converted by\n * `URLSearchParams`.\n */\nconst resolveRequestUrl = (\n resourceUrl: string,\n defaults: FetchDefaults,\n searchParams?: ExtendedRequestInit[\"searchParams\"],\n): string => {\n const url = defaults.baseURL\n ? new URL(resourceUrl, ensureTrailingSlash(defaults.baseURL)).toString()\n : resourceUrl;\n\n return resolveSearchParams(url, defaults.searchParams, searchParams);\n};\n\n/**\n * Normalizes request-level options into a final RequestInit payload and runtime flags.\n *\n * @param options - Request-level options.\n * @param defaults - Client-level defaults.\n * @returns Fully merged request init payload and effective runtime flags.\n */\nconst prepareRequestInit = (options: ExtendedRequestInit, defaults: FetchDefaults) => {\n const {\n headers,\n json,\n searchParams,\n throwOnFetchError = defaults.throwOnFetchError,\n throwOnValidationError = defaults.throwOnValidationError,\n ...rest\n } = options;\n\n const init: RequestInit = { ...rest };\n const mergedHeaders = mergeHeaders(defaults.headers, headers);\n if (mergedHeaders !== undefined) {\n init.headers = mergedHeaders;\n }\n\n if (json !== undefined) {\n if (init.body !== undefined && init.body !== null) {\n throw new TypeError(\"Cannot provide both `body` and `json`.\");\n }\n\n init.body = JSON.stringify(json);\n const requestHeaders = new Headers(init.headers);\n if (!requestHeaders.has(\"Content-Type\")) {\n requestHeaders.set(\"Content-Type\", \"application/json\");\n }\n init.headers = requestHeaders;\n }\n\n return {\n init,\n searchParams,\n throwOnFetchError,\n throwOnValidationError,\n };\n};\n\n/**\n * Logs a fetch response: `debug` for 2xx, `warn` otherwise.\n */\nconst logResponse = (\n logger: Logger | undefined,\n method: string,\n url: string,\n response: Response,\n): void => {\n const context = { method, status: response.status, url };\n if (response.ok) {\n logger?.debug(\"fetch response\", context);\n } else {\n logger?.warn(\"fetch response\", context);\n }\n};\n\n/**\n * Validates the raw JSON payload against `schema`, logging a `fetch\n * validation failed` message at `error` on failure regardless of throw mode.\n *\n * @throws {unknown} Any error thrown by `standardValidate` in throw mode.\n */\nconst validateResponse = async (\n raw: unknown,\n schema: StandardSchemaV1,\n throwOnValidationError: boolean,\n logger: Logger | undefined,\n url: string,\n): Promise<unknown> => {\n if (throwOnValidationError) {\n try {\n return await standardValidate(raw, schema, { throwOnError: true });\n } catch (error) {\n logger?.error(\"fetch validation failed\", { error, url });\n throw error;\n }\n }\n\n const result = await standardValidate(raw, schema, { throwOnError: false });\n if (result.issues) {\n logger?.error(\"fetch validation failed\", { issues: result.issues, url });\n }\n return result;\n};\n\n/**\n * Internal fetch implementation used by both $fetch and createFetch.\n *\n * This function normalizes request input, resolves final URL + query params,\n * executes `fetch`, optionally throws `FetchError`, and optionally validates\n * JSON response payloads using Standard Schema.\n *\n * @param input - Request URL, path, or Request object.\n * @param schema - Optional Standard Schema for response validation.\n * @param options - Optional request options and package-specific flags.\n * @param defaults - Effective client defaults.\n * @returns Raw `Response` when no schema is provided; otherwise validated output.\n * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.\n * @throws {ValidationError} When a schema is provided, validation returns issues, and\n * `throwOnValidationError` is `true`.\n * @throws {TypeError} When both `body` and `json` are provided, when JSON request\n * serialization fails, when request construction fails, when headers/search params are\n * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`\n * implementation rejects network-level failures as `TypeError`.\n * @throws {DOMException} When the runtime rejects an aborted request or response body read\n * as an `AbortError` DOMException.\n * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the\n * response body.\n * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.\n */\nconst fetchInternal = async (\n input: FetchInput,\n schema: StandardSchemaV1 | undefined,\n options: ExtendedRequestInit | undefined,\n defaults: FetchDefaults,\n): Promise<unknown> => {\n const { logger } = defaults;\n const request = normalizeRequest(input, options);\n const { init, searchParams, throwOnFetchError, throwOnValidationError } = prepareRequestInit(\n request.options,\n defaults,\n );\n const url = resolveRequestUrl(request.url, defaults, searchParams);\n const method = init.method ?? \"GET\";\n\n logger?.debug(\"fetch request\", { method, url });\n\n const span = tracer.startSpan(method, {\n attributes: {\n \"http.request.method\": method,\n \"url.full\": url,\n },\n kind: SpanKind.CLIENT,\n });\n const spanContext = trace.setSpan(otelContext.active(), span);\n\n try {\n return await otelContext.with(spanContext, async () => {\n const headers = new Headers(init.headers);\n propagation.inject(spanContext, headers, HEADERS_SETTER);\n init.headers = headers;\n\n const response = request.request\n ? await fetch(new Request(url, request.request), init)\n : await fetch(url, init);\n\n logResponse(logger, method, url, response);\n span.setAttribute(\"http.response.status_code\", response.status);\n if (!response.ok) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n if (throwOnFetchError && !response.ok) {\n throw new FetchError(`HTTP ${response.status}: ${response.statusText}`, response);\n }\n\n if (schema === undefined) {\n return response;\n }\n\n const raw: unknown = await response.json();\n return await validateResponse(raw, schema, throwOnValidationError, logger, url);\n });\n } catch (error) {\n recordSpanError(span, error);\n throw error;\n } finally {\n span.end();\n }\n};\n\n/**\n * Creates an HTTP method helper bound to a fetch function.\n *\n * The returned function mirrors `$Fetch` overloads but forces the provided\n * HTTP method (`GET`, `POST`, etc.) into request options.\n *\n * @param fetchFn - Fetch function to wrap.\n * @param method - HTTP method to enforce.\n * @returns Method-bound fetch function.\n * @throws {unknown} Any error thrown or rejected by `fetchFn` when the returned method-bound\n * fetch function is called.\n *\n * @example\n * const get = createMethod($fetch, \"GET\");\n * const user = await get(\"/users/1\", UserSchema);\n */\nconst createMethod = (fetchFn: $Fetch, method: string): $Fetch => {\n function methodFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & {\n throwOnValidationError: false;\n },\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n function methodFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & {\n throwOnValidationError?: true;\n },\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n function methodFetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\n /**\n * Method-bound `$Fetch` implementation.\n *\n * Resolves schema/option overloads and injects the configured HTTP method.\n */\n async function methodFetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n ): Promise<unknown> {\n if (isStandardSchema(schemaOrOptions)) {\n if (optionsOrUndefined?.throwOnValidationError === false) {\n return await fetchFn(input, schemaOrOptions, {\n ...optionsOrUndefined,\n method,\n throwOnValidationError: false,\n });\n }\n\n const { throwOnValidationError, ...restOptions } = optionsOrUndefined ?? {};\n\n if (throwOnValidationError === true) {\n return await fetchFn(input, schemaOrOptions, {\n ...restOptions,\n method,\n throwOnValidationError: true,\n });\n }\n\n return await fetchFn(input, schemaOrOptions, {\n ...restOptions,\n method,\n });\n }\n\n return await fetchFn(input, {\n ...schemaOrOptions,\n method,\n });\n }\n\n return methodFetch;\n};\n\n/**\n * Type-safe fetch wrapper with Standard Schema validation.\n *\n * - When `throwOnValidationError: true`: validated data of type `TSchema`\n * - When `throwOnValidationError: false`: Standard Schema Result object `{ value?, issues? }`\n * - When `throwOnFetchError: true`: throws `FetchError` on non-ok responses\n *\n * If no schema is provided, returns the raw `Response` object.\n *\n * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.\n * @throws {ValidationError} When a schema is provided, validation returns issues, and\n * `throwOnValidationError` is `true`.\n * @throws {TypeError} When both `body` and `json` are provided, when JSON request\n * serialization fails, when request construction fails, when headers/search params are\n * invalid, when `response.json()` cannot read the body, or when the runtime `fetch`\n * implementation rejects network-level failures as `TypeError`.\n * @throws {DOMException} When the runtime rejects an aborted request or response body read\n * as an `AbortError` DOMException.\n * @throws {SyntaxError} When a schema is provided and `response.json()` cannot parse the\n * response body.\n * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.\n *\n * @example\n * import { z } from \"zod\";\n * import { $fetch } from \"@zap-studio/fetch\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage (schema validation)\n * const user = await $fetch(\"/api/users/1\", UserSchema, { headers: { \"Authorization\": \"Bearer token\" } });\n * console.log(\"Validated user:\", user);\n *\n * // Raw usage (no schema validation and typed Response object)\n * const result = await $fetch(\"/api/data\", { method: \"POST\", body: JSON.stringify({ key: \"value\" }) });\n * const json = await result.json() as ResultType;\n * console.log(\"Raw response data:\", json);\n *\n * // Usage with validation errors returned instead of thrown\n * const result = await $fetch(\"/api/users/1\", UserSchema, { throwOnValidationError: false });\n *\n * if (result.issues) {\n * console.error(\"Validation errors:\", result.issues);\n * } else {\n * console.log(\"Validated user:\", result.value);\n * }\n */\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & { throwOnValidationError: false },\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & { throwOnValidationError?: true },\n): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\nexport async function $fetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\nexport async function $fetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(input, schema, options, GLOBAL_DEFAULTS);\n}\n\n/**\n * Convenience methods for common HTTP verbs.\n *\n * These methods always require a schema for validation.\n * For raw responses without validation, use `$fetch` directly.\n *\n * Each method has the same throw behavior as {@link $fetch}.\n *\n * @example\n * import { z } from \"zod\";\n * import { api } from \"@zap-studio/fetch\";\n *\n * const PostSchema = z.object({\n * id: z.number(),\n * title: z.string(),\n * content: z.string(),\n * });\n *\n * async function fetchPost(postId: number) {\n * const post = await api.get(`https://api.example.com/posts/${postId}`, PostSchema);\n * return post; // post is typed as { id: number; title: string; content: string; }\n * }\n */\nexport const api: ApiMethods = {\n delete: createMethod($fetch, \"DELETE\"),\n get: createMethod($fetch, \"GET\"),\n patch: createMethod($fetch, \"PATCH\"),\n post: createMethod($fetch, \"POST\"),\n put: createMethod($fetch, \"PUT\"),\n};\n\n/**\n * Creates a custom fetch instance with pre-configured defaults.\n *\n * Use this factory to create API clients with a base URL, default headers,\n * and other shared configuration. Each instance is independent.\n *\n * The returned `$fetch` and `api` methods have the same throw behavior as the\n * top-level {@link $fetch} export.\n *\n * @example\n * import { z } from \"zod\";\n * import { createFetch } from \"@zap-studio/fetch\";\n *\n * // Create a configured instance\n * const { $fetch, api } = createFetch({\n * baseURL: \"https://api.example.com\",\n * headers: { \"Authorization\": \"Bearer token\" },\n * });\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Now use relative paths - baseURL is prepended automatically\n * const user = await api.get(\"/users/1\", UserSchema);\n *\n * // Or use $fetch directly\n * const response = await $fetch(\"/users\", UserSchema, { method: \"POST\", json: { name: \"John\" } });\n */\nexport const createFetch = (factoryOptions: Partial<FetchDefaults> = {}): FetchInstance => {\n const defaults: FetchDefaults = {\n ...GLOBAL_DEFAULTS,\n ...factoryOptions,\n baseURL: factoryOptions.baseURL ?? GLOBAL_DEFAULTS.baseURL,\n throwOnFetchError: factoryOptions.throwOnFetchError ?? GLOBAL_DEFAULTS.throwOnFetchError,\n throwOnValidationError:\n factoryOptions.throwOnValidationError ?? GLOBAL_DEFAULTS.throwOnValidationError,\n };\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options: ExtendedRequestInit & { throwOnValidationError: false },\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n input: FetchInput,\n schema: TSchema,\n options?: ExtendedRequestInit & {\n throwOnValidationError?: true;\n },\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n async function customFetch(input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;\n\n async function customFetch(\n input: FetchInput,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit,\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(input, schema, options, defaults);\n }\n\n const customApi = {\n delete: createMethod(customFetch, \"DELETE\"),\n get: createMethod(customFetch, \"GET\"),\n patch: createMethod(customFetch, \"PATCH\"),\n post: createMethod(customFetch, \"POST\"),\n put: createMethod(customFetch, \"PUT\"),\n };\n\n return {\n $fetch: customFetch,\n api: customApi,\n };\n};\n"],"mappings":";;;;;;;;;;ACmBA,MAAa,SAAiB,MAAM,UAAUA,qBAAUC,OAAW;;;;;AAMnE,MAAa,iBAAyC,EACpD,IAAI,SAAS,KAAK,OAAO;CACvB,QAAQ,IAAI,KAAK,KAAK;AACxB,EACF;;;;;;AAOA,MAAa,mBAAmB,MAAY,UAAyB;CACnE,IAAI,iBAAiB,SAAS,OAAO,UAAU,UAC7C,KAAK,gBAAgB,KAAK;CAE5B,KAAK,UAAU,EAAE,MAAM,eAAe,MAAM,CAAC;AAC/C;;;;;;;;;;;;;;ACkBA,MAAa,kBAAiC;CAC5C,SAAS;CACT,mBAAmB;CACnB,wBAAwB;AAC1B;;;;;;;;;AAUA,MAAM,gBAAgB,MAAoB,aAAgD;CACxF,IAAI,SAAS,KAAA,KAAa,aAAa,KAAA,GACrC;CAGF,MAAM,SAAS,IAAI,QAAQ,IAAI;CAC/B,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,QAAQ,QAAQ,CAAC,CAAC,QAAQ,GACvD,OAAO,IAAI,KAAK,KAAK;CAEvB,OAAO;AACT;AAGA,MAAM,gBAAgB,CAAC;;;;;;;;;AAUvB,MAAM,oBAAoB,OAAmB,YAAqD;CAChG,IAAI,EAAE,iBAAiB,UAAU;EAC/B,MAAM,MAAM,iBAAiB,MAAM,MAAM,OAAO;EAChD,OAAO;GACL,SAAS,WAAW;GACpB;EACF;CACF;CAEA,MAAM,UAAU,IAAI,QAAQ,KAAK;CACjC,MAAM,EAAE,SAAS,GAAG,SAAS,WAAW,CAAC;CACzC,MAAM,gBAAgB,aAAa,QAAQ,SAAS,OAAO;CAE3D,MAAM,oBAAoB,EAAE,GAAG,KAAK;CAEpC,IAAI,kBAAkB,KAAA,GACpB,kBAAkB,UAAU;CAG9B,OAAO;EACL,SAAS;EACT;EACA,KAAK,QAAQ;CACf;AACF;;;;AAKA,MAAM,qBACJ,QACA,WACS;CACT,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,MAAM,GACnD,OAAO,IAAI,KAAK,KAAK;AAEzB;;;;AAKA,MAAM,uBAAuB,QAAyB,IAAI,SAAS,GAAG,IAAI,MAAM,GAAG,IAAI;;;;AAKvF,MAAM,uBACJ,KACA,qBACA,iBACW;CACX,IAAI,wBAAwB,KAAA,KAAa,iBAAiB,KAAA,GACxD,OAAO;CAGT,MAAM,YAAY,IAAI,QAAQ,GAAG;CACjC,MAAM,cAAc,cAAc;CAClC,MAAM,iBAAiB,cAAc,IAAI,MAAM,GAAG,SAAS,IAAI;CAC/D,MAAM,OAAO,cAAc,IAAI,MAAM,YAAY,CAAC,IAAI;CACtD,MAAM,aAAa,eAAe,QAAQ,GAAG;CAC7C,MAAM,WAAW,eAAe,KAAK,iBAAiB,eAAe,MAAM,GAAG,UAAU;CACxF,MAAM,kBAAkB,eAAe,KAAK,KAAA,IAAY,eAAe,MAAM,aAAa,CAAC;CAC3F,MAAM,uBAAuB,IAAI,gBAAgB;CAEjD,kBAAkB,sBAAsB,mBAAmB;CAC3D,kBAAkB,sBAAsB,eAAe;CACvD,kBAAkB,sBAAsB,YAAY;CAEpD,MAAM,iBAAiB,qBAAqB,SAAS;CACrD,MAAM,iBAAiB,cAAc,IAAI,SAAS;CAElD,IAAI,eAAe,WAAW,GAC5B,OAAO,GAAG,WAAW;CAGvB,OAAO,GAAG,SAAS,GAAG,iBAAiB;AACzC;;;;;;;;;;;;;AAcA,MAAM,qBACJ,aACA,UACA,iBACW;CACX,MAAM,MAAM,SAAS,UACjB,IAAI,IAAI,aAAa,oBAAoB,SAAS,OAAO,CAAC,CAAC,CAAC,SAAS,IACrE;CAEJ,OAAO,oBAAoB,KAAK,SAAS,cAAc,YAAY;AACrE;;;;;;;;AASA,MAAM,sBAAsB,SAA8B,aAA4B;CACpF,MAAM,EACJ,SACA,MACA,cACA,oBAAoB,SAAS,mBAC7B,yBAAyB,SAAS,wBAClC,GAAG,SACD;CAEJ,MAAM,OAAoB,EAAE,GAAG,KAAK;CACpC,MAAM,gBAAgB,aAAa,SAAS,SAAS,OAAO;CAC5D,IAAI,kBAAkB,KAAA,GACpB,KAAK,UAAU;CAGjB,IAAI,SAAS,KAAA,GAAW;EACtB,IAAI,KAAK,SAAS,KAAA,KAAa,KAAK,SAAS,MAC3C,MAAM,IAAI,UAAU,wCAAwC;EAG9D,KAAK,OAAO,KAAK,UAAU,IAAI;EAC/B,MAAM,iBAAiB,IAAI,QAAQ,KAAK,OAAO;EAC/C,IAAI,CAAC,eAAe,IAAI,cAAc,GACpC,eAAe,IAAI,gBAAgB,kBAAkB;EAEvD,KAAK,UAAU;CACjB;CAEA,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;;;;AAKA,MAAM,eACJ,QACA,QACA,KACA,aACS;CACT,MAAM,UAAU;EAAE;EAAQ,QAAQ,SAAS;EAAQ;CAAI;CACvD,IAAI,SAAS,IACX,QAAQ,MAAM,kBAAkB,OAAO;MAEvC,QAAQ,KAAK,kBAAkB,OAAO;AAE1C;;;;;;;AAQA,MAAM,mBAAmB,OACvB,KACA,QACA,wBACA,QACA,QACqB;CACrB,IAAI,wBACF,IAAI;EACF,OAAO,MAAM,iBAAiB,KAAK,QAAQ,EAAE,cAAc,KAAK,CAAC;CACnE,SAAS,OAAO;EACd,QAAQ,MAAM,2BAA2B;GAAE;GAAO;EAAI,CAAC;EACvD,MAAM;CACR;CAGF,MAAM,SAAS,MAAM,iBAAiB,KAAK,QAAQ,EAAE,cAAc,MAAM,CAAC;CAC1E,IAAI,OAAO,QACT,QAAQ,MAAM,2BAA2B;EAAE,QAAQ,OAAO;EAAQ;CAAI,CAAC;CAEzE,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,gBAAgB,OACpB,OACA,QACA,SACA,aACqB;CACrB,MAAM,EAAE,WAAW;CACnB,MAAM,UAAU,iBAAiB,OAAO,OAAO;CAC/C,MAAM,EAAE,MAAM,cAAc,mBAAmB,2BAA2B,mBACxE,QAAQ,SACR,QACF;CACA,MAAM,MAAM,kBAAkB,QAAQ,KAAK,UAAU,YAAY;CACjE,MAAM,SAAS,KAAK,UAAU;CAE9B,QAAQ,MAAM,iBAAiB;EAAE;EAAQ;CAAI,CAAC;CAE9C,MAAM,OAAO,OAAO,UAAU,QAAQ;EACpC,YAAY;GACV,uBAAuB;GACvB,YAAY;EACd;EACA,MAAM,SAAS;CACjB,CAAC;CACD,MAAM,cAAc,MAAM,QAAQC,QAAY,OAAO,GAAG,IAAI;CAE5D,IAAI;EACF,OAAO,MAAMA,QAAY,KAAK,aAAa,YAAY;GACrD,MAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;GACxC,YAAY,OAAO,aAAa,SAAS,cAAc;GACvD,KAAK,UAAU;GAEf,MAAM,WAAW,QAAQ,UACrB,MAAM,MAAM,IAAI,QAAQ,KAAK,QAAQ,OAAO,GAAG,IAAI,IACnD,MAAM,MAAM,KAAK,IAAI;GAEzB,YAAY,QAAQ,QAAQ,KAAK,QAAQ;GACzC,KAAK,aAAa,6BAA6B,SAAS,MAAM;GAC9D,IAAI,CAAC,SAAS,IACZ,KAAK,UAAU,EAAE,MAAM,eAAe,MAAM,CAAC;GAG/C,IAAI,qBAAqB,CAAC,SAAS,IACjC,MAAM,IAAI,WAAW,QAAQ,SAAS,OAAO,IAAI,SAAS,cAAc,QAAQ;GAGlF,IAAI,WAAW,KAAA,GACb,OAAO;GAGT,MAAM,MAAe,MAAM,SAAS,KAAK;GACzC,OAAO,MAAM,iBAAiB,KAAK,QAAQ,wBAAwB,QAAQ,GAAG;EAChF,CAAC;CACH,SAAS,OAAO;EACd,gBAAgB,MAAM,KAAK;EAC3B,MAAM;CACR,UAAU;EACR,KAAK,IAAI;CACX;AACF;;;;;;;;;;;;;;;;;AAkBA,MAAM,gBAAgB,SAAiB,WAA2B;;;;;;CAwBhE,eAAe,YACb,OACA,iBACA,oBACkB;EAClB,IAAI,iBAAiB,eAAe,GAAG;GACrC,IAAI,oBAAoB,2BAA2B,OACjD,OAAO,MAAM,QAAQ,OAAO,iBAAiB;IAC3C,GAAG;IACH;IACA,wBAAwB;GAC1B,CAAC;GAGH,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,sBAAsB,CAAC;GAE1E,IAAI,2BAA2B,MAC7B,OAAO,MAAM,QAAQ,OAAO,iBAAiB;IAC3C,GAAG;IACH;IACA,wBAAwB;GAC1B,CAAC;GAGH,OAAO,MAAM,QAAQ,OAAO,iBAAiB;IAC3C,GAAG;IACH;GACF,CAAC;EACH;EAEA,OAAO,MAAM,QAAQ,OAAO;GAC1B,GAAG;GACH;EACF,CAAC;CACH;CAEA,OAAO;AACT;AA8DA,eAAsB,OACpB,OACA,iBACA,oBACkB;CAClB,MAAM,CAAC,QAAQ,WAAW,iBAAiB,eAAe,IACtD,CAAC,iBAAiB,kBAAkB,IACpC,CAAC,KAAA,GAAW,eAAe;CAE/B,OAAO,MAAM,cAAc,OAAO,QAAQ,SAAS,eAAe;AACpE;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,MAAkB;CAC7B,QAAQ,aAAa,QAAQ,QAAQ;CACrC,KAAK,aAAa,QAAQ,KAAK;CAC/B,OAAO,aAAa,QAAQ,OAAO;CACnC,MAAM,aAAa,QAAQ,MAAM;CACjC,KAAK,aAAa,QAAQ,KAAK;AACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,eAAe,iBAAyC,CAAC,MAAqB;CACzF,MAAM,WAA0B;EAC9B,GAAG;EACH,GAAG;EACH,SAAS,eAAe,WAAW,gBAAgB;EACnD,mBAAmB,eAAe,qBAAqB,gBAAgB;EACvE,wBACE,eAAe,0BAA0B,gBAAgB;CAC7D;CAkBA,eAAe,YACb,OACA,iBACA,oBACkB;EAClB,MAAM,CAAC,QAAQ,WAAW,iBAAiB,eAAe,IACtD,CAAC,iBAAiB,kBAAkB,IACpC,CAAC,KAAA,GAAW,eAAe;EAE/B,OAAO,MAAM,cAAc,OAAO,QAAQ,SAAS,QAAQ;CAC7D;CAUA,OAAO;EACL,QAAQ;EACR,KAAK;GATL,QAAQ,aAAa,aAAa,QAAQ;GAC1C,KAAK,aAAa,aAAa,KAAK;GACpC,OAAO,aAAa,aAAa,OAAO;GACxC,MAAM,aAAa,aAAa,MAAM;GACtC,KAAK,aAAa,aAAa,KAAK;EAKvB;CACf;AACF"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { FetchError } from "./errors.js";
2
- import { ResultAsync } from "@zap-studio/monads";
3
- import { StandardSchemaV1, ValidationError } from "@zap-studio/validation";
1
+ import { StandardSchemaV1 } from "@zap-studio/validation";
4
2
  import { Logger } from "@zap-studio/logger";
5
3
  //#region src/types.d.ts
6
4
  /**
@@ -157,84 +155,6 @@ interface $Fetch {
157
155
  */
158
156
  (input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;
159
157
  }
160
- /**
161
- * `ExtendedRequestInit` minus `throwOnFetchError`/`throwOnValidationError`,
162
- * which don't apply to the `Result`-returning API — it always returns a
163
- * `Result` instead of throwing.
164
- *
165
- * Built from `RequestBodyInit | JsonBodyInit` directly rather than
166
- * `Omit<ExtendedRequestInit, ...>`, since `Omit` doesn't distribute over that
167
- * union and would silently drop the `body`/`json` mutual exclusivity.
168
- *
169
- * @example
170
- * const options: FetchResultRequestInit = { method: "POST", json: { name: "Ada" } };
171
- */
172
- type FetchResultRequestInit = (RequestBodyInit | JsonBodyInit) & Omit<CustomRequestInit, "throwOnFetchError" | "throwOnValidationError">;
173
- /**
174
- * `Result`-returning counterpart to {@link $Fetch}, for consumers who prefer
175
- * explicit `Result`/`ResultAsync` values (from `@zap-studio/monads`) over
176
- * throw/catch.
177
- *
178
- * @example
179
- * import { isOk } from "@zap-studio/monads";
180
- *
181
- * const UserSchema = z.object({ id: z.number(), name: z.string() });
182
- * const fetchUser: $FetchResult = $fetchResult;
183
- * const result = await fetchUser("/users/1", UserSchema);
184
- *
185
- * if (isOk(result)) {
186
- * console.log(result.value);
187
- * }
188
- */
189
- interface $FetchResult {
190
- /**
191
- * Fetch with schema validation, returning a `Result`.
192
- * @param input - URL or path to fetch
193
- * @param schema - Standard Schema for response validation
194
- * @param options - Extended request options, minus the throw flags
195
- * @returns A `ResultAsync` resolving to `Ok` with the validated value, or `Err` with a
196
- * `FetchError` (non-ok response) or `ValidationError` (validation issues).
197
- * @throws {TypeError} When request construction, JSON request serialization, headers,
198
- * search params, native `fetch`, or `response.json()` body reading fail with a
199
- * `TypeError`.
200
- * @throws {DOMException} When native `fetch` or `response.json()` rejects an aborted
201
- * request/body read as an `AbortError` DOMException.
202
- * @throws {SyntaxError} When `response.json()` cannot parse the response body.
203
- * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator
204
- * that isn't a `ValidationError`.
205
- */
206
- <TSchema extends StandardSchemaV1>(input: FetchInput, schema: TSchema, options?: FetchResultRequestInit): ResultAsync<StandardSchemaV1.InferOutput<TSchema>, FetchError | ValidationError>;
207
- /**
208
- * Fetch without schema validation, returning a `Result`.
209
- * @param input - URL or path to fetch
210
- * @param options - Extended request options, minus the throw flags
211
- * @returns A `ResultAsync` resolving to `Ok` with the raw `Response`, or `Err` with a
212
- * `FetchError` on a non-ok response.
213
- * @throws {TypeError} When request construction, JSON request serialization, headers,
214
- * search params, or native `fetch` fail with a `TypeError`.
215
- * @throws {DOMException} When native `fetch` rejects an aborted request as an
216
- * `AbortError` DOMException.
217
- */
218
- (input: FetchInput, options?: FetchResultRequestInit): ResultAsync<Response, FetchError>;
219
- }
220
- /**
221
- * `Result`-returning counterpart to {@link ApiMethods}.
222
- *
223
- * @example
224
- * const result = await apiResult.get("/users/1", UserSchema);
225
- */
226
- interface ApiResultMethods {
227
- /** DELETE method, `Result`-returning */
228
- delete: $FetchResult;
229
- /** GET method, `Result`-returning */
230
- get: $FetchResult;
231
- /** PATCH method, `Result`-returning */
232
- patch: $FetchResult;
233
- /** POST method, `Result`-returning */
234
- post: $FetchResult;
235
- /** PUT method, `Result`-returning */
236
- put: $FetchResult;
237
- }
238
158
  /**
239
159
  * Normalized representation used by internal request execution.
240
160
  *
@@ -291,19 +211,11 @@ interface FetchInstance {
291
211
  * Configured `$fetch` function.
292
212
  */
293
213
  $fetch: $Fetch;
294
- /**
295
- * Configured `Result`-returning `$fetch` function.
296
- */
297
- $fetchResult: $FetchResult;
298
214
  /**
299
215
  * Configured HTTP method-specific fetch functions.
300
216
  */
301
217
  api: ApiMethods;
302
- /**
303
- * Configured HTTP method-specific `Result`-returning fetch functions.
304
- */
305
- apiResult: ApiResultMethods;
306
218
  }
307
219
  //#endregion
308
- export { $Fetch, $FetchResult, ApiMethods, ApiResultMethods, ExtendedRequestInit, FetchDefaults, FetchInput, FetchInstance, FetchResultRequestInit, NormalizedRequest };
220
+ export { $Fetch, ApiMethods, ExtendedRequestInit, FetchDefaults, FetchInput, FetchInstance, NormalizedRequest };
309
221
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;;KAmBY,aAAa,kBAAkB;KAEtC,uBAAuB,6BAA6B;KAEpD,kBAAkB;EACrB;;KAGG,eAAe,KAAK;;;;;EAKvB;EACA;;UAGQ;;;;;EAKR,eAAe;;;;;EAKf;;;;;EAKA;;;;;;;;;;;;KAaU,uBAAuB,kBAAkB,gBAAgB;;;;;;;;;;;UAYpD;;;;;EAKf;;;;;EAKA,UAAU;;;;;EAKV,eAAe;;;;;EAKf;;;;;EAKA;;;;;;;;EAQA,SAAS;;;;;;;;;;;;UAaM;;;;;;;;;;;;;;;;GAgBd,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,SAAS;IAAwB;MAChC,QAAQ,iBAAiB,OAAO,iBAAiB,YAAY;;;;;;;;;;;;;;;;;GAkB/D,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,UAAU;IACR;MAED,QAAQ,iBAAiB,YAAY;;;;;;;;;;;;GAavC,OAAO,YAAY,UAAU,sBAAsB,QAAQ;;;;;;;;;;;;;;KAelD,0BAA0B,kBAAkB,gBACtD,KAAK;;;;;;;;;;;;;;;;;UAkBU;;;;;;;;;;;;;;;;;GAiBd,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,UAAU,yBACT,YAAY,iBAAiB,YAAY,UAAU,aAAa;;;;;;;;;;;;GAalE,OAAO,YAAY,UAAU,yBAAyB,YAAY,UAAU;;;;;;;;UAS9D;;EAEf,QAAQ;;EAER,KAAK;;EAEL,OAAO;;EAEP,MAAM;;EAEN,KAAK;;;;;;;;;;;UAYU;;EAEf;;EAEA,UAAU;;EAEV,SAAS;;;;;;;;UASM;;;;EAIf,QAAQ;;;;EAIR,KAAK;;;;EAIL,OAAO;;;;EAIP,MAAM;;;;EAIN,KAAK;;;;;;;;UASU;;;;EAIf,QAAQ;;;;EAIR,cAAc;;;;EAId,KAAK;;;;EAIL,WAAW"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;KAgBY,aAAa,kBAAkB;KAEtC,uBAAuB,6BAA6B;KAEpD,kBAAkB;EACrB;;KAGG,eAAe,KAAK;;;;;EAKvB;EACA;;UAGQ;;;;;EAKR,eAAe;;;;;EAKf;;;;;EAKA;;;;;;;;;;;;KAaU,uBAAuB,kBAAkB,gBAAgB;;;;;;;;;;;UAYpD;;;;;EAKf;;;;;EAKA,UAAU;;;;;EAKV,eAAe;;;;;EAKf;;;;;EAKA;;;;;;;;EAQA,SAAS;;;;;;;;;;;;UAaM;;;;;;;;;;;;;;;;GAgBd,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,SAAS;IAAwB;MAChC,QAAQ,iBAAiB,OAAO,iBAAiB,YAAY;;;;;;;;;;;;;;;;;GAkB/D,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,UAAU;IACR;MAED,QAAQ,iBAAiB,YAAY;;;;;;;;;;;;GAavC,OAAO,YAAY,UAAU,sBAAsB,QAAQ;;;;;;;;;;;UAY7C;;EAEf;;EAEA,UAAU;;EAEV,SAAS;;;;;;;;UASM;;;;EAIf,QAAQ;;;;EAIR,KAAK;;;;EAIL,OAAO;;;;EAIP,MAAM;;;;EAIN,KAAK;;;;;;;;UASU;;;;EAIf,QAAQ;;;;EAIR,KAAK"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-studio/fetch",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "private": false,
5
5
  "description": "A type-safe, tree-shakeable fetch wrapper for HTTP requests with runtime schema validation.",
6
6
  "keywords": [
@@ -46,8 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@zap-studio/monads": "1.0.0",
50
- "@zap-studio/validation": "1.1.0"
49
+ "@zap-studio/validation": "1.1.1"
51
50
  },
52
51
  "devDependencies": {
53
52
  "@opentelemetry/api": "^1.9.0",