zlient 2.1.10 → 3.0.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/dist/index.cjs CHANGED
@@ -1,28 +1,4 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
24
- const zod = __toESM(require("zod"));
25
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
26
2
  //#region lib/auth.ts
27
3
  /**
28
4
  * No-op authentication provider (no authentication applied).
@@ -96,7 +72,6 @@ var BearerTokenAuth = class {
96
72
  };
97
73
  }
98
74
  };
99
-
100
75
  //#endregion
101
76
  //#region lib/types.ts
102
77
  const HTTPMethod = {
@@ -185,23 +160,20 @@ const HTTPStatusCode = {
185
160
  * ```
186
161
  */
187
162
  var ApiError = class ApiError extends Error {
188
- status;
189
- details;
190
- zodError;
191
163
  constructor(message, options) {
192
164
  super(message);
193
165
  this.name = "ApiError";
194
166
  this.status = options?.status;
195
167
  this.details = options?.details;
196
168
  this.cause = options?.cause;
197
- this.zodError = options?.zodError;
169
+ this.validationIssues = options?.validationIssues;
198
170
  if (Error.captureStackTrace) Error.captureStackTrace(this, ApiError);
199
171
  }
200
172
  /**
201
- * Check if this is a validation error (has zodError)
173
+ * Check if this is a validation error (has validationIssues)
202
174
  */
203
175
  isValidationError() {
204
- return !!this.zodError;
176
+ return !!this.validationIssues && this.validationIssues.length > 0;
205
177
  }
206
178
  /**
207
179
  * Check if this is a client error (4xx status)
@@ -224,7 +196,7 @@ var ApiError = class ApiError extends Error {
224
196
  message: this.message,
225
197
  status: this.status,
226
198
  details: this.details,
227
- zodError: this.zodError?.issues,
199
+ validationIssues: this.validationIssues,
228
200
  stack: this.stack
229
201
  };
230
202
  }
@@ -242,15 +214,6 @@ var SchemaDefinitionError = class SchemaDefinitionError extends Error {
242
214
  }
243
215
  };
244
216
  /**
245
- * Schema for paginated responses
246
- */
247
- const PaginationSchema = zod.z.object({
248
- items: zod.z.array(zod.z.unknown()),
249
- total: zod.z.number().int().nonnegative(),
250
- page: zod.z.number().int().nonnegative(),
251
- pageSize: zod.z.number().int().positive()
252
- });
253
- /**
254
217
  * Converts query parameters to a URL query string.
255
218
  * Filters out undefined values automatically.
256
219
  *
@@ -266,8 +229,8 @@ const PaginationSchema = zod.z.object({
266
229
  function toQueryString(q) {
267
230
  if (!q) return "";
268
231
  if (q instanceof URLSearchParams) {
269
- const s$1 = q.toString();
270
- return s$1 ? `?${s$1}` : "";
232
+ const s = q.toString();
233
+ return s ? `?${s}` : "";
271
234
  }
272
235
  const params = new URLSearchParams();
273
236
  Object.entries(q).forEach(([k, v]) => {
@@ -276,36 +239,88 @@ function toQueryString(q) {
276
239
  const s = params.toString();
277
240
  return s ? `?${s}` : "";
278
241
  }
279
-
280
242
  //#endregion
281
243
  //#region lib/validation.ts
282
244
  /**
283
- * Parse data with a Zod schema, throwing an ApiError on validation failure.
245
+ * Safely parse/validate data with any Standard Schema-compatible library (Zod, Valibot, ArkType, etc.).
246
+ * Returns a result object with success status and data or issues.
247
+ *
248
+ * @param schema - A Standard Schema-compatible validator
249
+ * @param data - Data to validate
250
+ * @returns Result object with success flag and data/issues
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * // Works with Zod
255
+ * import { z } from 'zod';
256
+ * const result = await safeParse(z.object({ name: z.string() }), userData);
257
+ *
258
+ * // Works with Valibot
259
+ * import * as v from 'valibot';
260
+ * const result = await safeParse(v.object({ name: v.string() }), userData);
261
+ *
262
+ * // Works with ArkType
263
+ * import { type } from 'arktype';
264
+ * const result = await safeParse(type({ name: 'string' }), userData);
265
+ *
266
+ * if (result.success) {
267
+ * console.log(result.data);
268
+ * } else {
269
+ * console.error(result.issues);
270
+ * }
271
+ * ```
272
+ */
273
+ async function safeParse(schema, data) {
274
+ const result = await schema["~standard"].validate(data);
275
+ if (result.issues) return {
276
+ success: false,
277
+ issues: result.issues
278
+ };
279
+ return {
280
+ success: true,
281
+ data: result.value
282
+ };
283
+ }
284
+ /**
285
+ * Parse/validate data with any Standard Schema-compatible library, throwing an ApiError on failure.
284
286
  * Use this when you want to fail fast on invalid data.
285
287
  *
286
- * @param schema - Zod schema to validate against
288
+ * @param schema - A Standard Schema-compatible validator
287
289
  * @param data - Data to validate
288
290
  * @returns Validated and typed data
289
- * @throws {ApiError} If validation fails
291
+ * @throws {ApiError} If validation fails (with validationIssues property)
290
292
  *
291
293
  * @example
292
294
  * ```ts
295
+ * // Works with any Standard Schema-compatible library
293
296
  * try {
294
- * const user = parseOrThrow(UserSchema, userData);
297
+ * const user = await parseOrThrow(UserSchema, userData);
295
298
  * console.log(user);
296
299
  * } catch (error) {
297
- * if (error instanceof ApiError && error.zodError) {
298
- * console.error('Validation failed:', error.zodError.issues);
300
+ * if (error instanceof ApiError && error.isValidationError()) {
301
+ * console.error('Validation failed:', error.validationIssues);
299
302
  * }
300
303
  * }
301
304
  * ```
302
305
  */
303
- function parseOrThrow(schema, data) {
304
- const res = schema.safeParse(data);
305
- if (!res.success) throw new ApiError("Response validation failed", { zodError: res.error });
306
- return res.data;
306
+ async function parseOrThrow(schema, data) {
307
+ const result = await schema["~standard"].validate(data);
308
+ if (result.issues) throw new ApiError(`Validation failed: ${result.issues.map((issue) => issue.message).join(", ")}`, { validationIssues: result.issues });
309
+ return result.value;
310
+ }
311
+ /**
312
+ * Type guard to check if a value is a Standard Schema-compatible validator.
313
+ * Handles both object-based schemas (Zod, Valibot) and function-based schemas (ArkType).
314
+ *
315
+ * @param value - Value to check
316
+ * @returns True if the value implements Standard Schema v1
317
+ */
318
+ function isStandardSchema(value) {
319
+ if (value === null || value === void 0) return false;
320
+ if (typeof value !== "object" && typeof value !== "function") return false;
321
+ const schema = value;
322
+ return "~standard" in schema && typeof schema["~standard"] === "object" && schema["~standard"] !== null && schema["~standard"].version === 1 && typeof schema["~standard"].validate === "function";
307
323
  }
308
-
309
324
  //#endregion
310
325
  //#region lib/endpoint/base-endpoint.ts
311
326
  var EndpointImpl = class {
@@ -314,21 +329,17 @@ var EndpointImpl = class {
314
329
  this.config = config;
315
330
  }
316
331
  async call(params) {
317
- const { data, query, pathParams, headers, signal } = params;
332
+ const { data, query, pathParams, signal } = params;
333
+ const headers = "headers" in params ? params.headers : void 0;
318
334
  const skipRequestValidation = this.config.advanced?.skipRequestValidation ?? false;
319
335
  const skipResponseValidation = this.config.advanced?.skipResponseValidation ?? false;
320
- if (!skipRequestValidation && this.config.request && data !== void 0) {
321
- const parsed = this.config.request.safeParse(data);
322
- if (!parsed.success) throw parsed.error;
323
- }
324
- if (!skipRequestValidation && this.config.query && query !== void 0) {
325
- const parsed = this.config.query.safeParse(query);
326
- if (!parsed.success) throw parsed.error;
327
- }
328
- if (!skipRequestValidation && this.config.pathParams && pathParams !== void 0) {
329
- const parsed = this.config.pathParams.safeParse(pathParams);
330
- if (!parsed.success) throw parsed.error;
336
+ if (this.config.mustHeaderKeys && this.config.mustHeaderKeys.length > 0) {
337
+ const missingHeaders = this.config.mustHeaderKeys.filter((key) => !headers || !(key in headers));
338
+ if (missingHeaders.length > 0) throw new Error(`Missing required header(s): ${missingHeaders.join(", ")}`);
331
339
  }
340
+ if (!skipRequestValidation && this.config.request && data !== void 0) await parseOrThrow(this.config.request, data);
341
+ if (!skipRequestValidation && this.config.query && query !== void 0) await parseOrThrow(this.config.query, query);
342
+ if (!skipRequestValidation && this.config.pathParams && pathParams !== void 0) await parseOrThrow(this.config.pathParams, pathParams);
332
343
  if (this.config.request && data === void 0) throw new Error("Missing required request body (data)");
333
344
  if (this.config.pathParams && pathParams === void 0) throw new Error("Missing required path parameters (pathParams)");
334
345
  let pathStr;
@@ -346,24 +357,23 @@ var EndpointImpl = class {
346
357
  });
347
358
  const schema = this.config.response;
348
359
  if (skipResponseValidation) return responseData;
349
- if (schema instanceof zod.z.ZodType) return parseOrThrow(schema, responseData);
360
+ if (isStandardSchema(schema)) return await parseOrThrow(schema, responseData);
350
361
  const specificSchema = schema[status];
351
362
  if (!specificSchema) throw new SchemaDefinitionError(status);
352
- return parseOrThrow(specificSchema, responseData);
363
+ return await parseOrThrow(specificSchema, responseData);
353
364
  }
354
365
  };
355
-
356
366
  //#endregion
357
367
  //#region lib/logger.ts
358
368
  /**
359
369
  * Log levels for structured logging.
360
370
  */
361
- let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
362
- LogLevel$1["DEBUG"] = "debug";
363
- LogLevel$1["INFO"] = "info";
364
- LogLevel$1["WARN"] = "warn";
365
- LogLevel$1["ERROR"] = "error";
366
- return LogLevel$1;
371
+ let LogLevel = /* @__PURE__ */ function(LogLevel) {
372
+ LogLevel["DEBUG"] = "debug";
373
+ LogLevel["INFO"] = "info";
374
+ LogLevel["WARN"] = "warn";
375
+ LogLevel["ERROR"] = "error";
376
+ return LogLevel;
367
377
  }({});
368
378
  /**
369
379
  * Default console logger implementation.
@@ -380,9 +390,7 @@ var ConsoleLogger = class {
380
390
  LogLevel.WARN,
381
391
  LogLevel.ERROR
382
392
  ];
383
- const entryLevelIndex = levels.indexOf(entry.level);
384
- const minLevelIndex = levels.indexOf(this.minLevel);
385
- if (entryLevelIndex < minLevelIndex) return;
393
+ if (levels.indexOf(entry.level) < levels.indexOf(this.minLevel)) return;
386
394
  const output = {
387
395
  ...entry,
388
396
  error: entry.error ? {
@@ -425,7 +433,7 @@ var LoggerUtil = class {
425
433
  this.logger.log({
426
434
  level: LogLevel.DEBUG,
427
435
  message,
428
- timestamp: new Date().toISOString(),
436
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
429
437
  context
430
438
  });
431
439
  }
@@ -433,7 +441,7 @@ var LoggerUtil = class {
433
441
  this.logger.log({
434
442
  level: LogLevel.INFO,
435
443
  message,
436
- timestamp: new Date().toISOString(),
444
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
437
445
  context
438
446
  });
439
447
  }
@@ -441,7 +449,7 @@ var LoggerUtil = class {
441
449
  this.logger.log({
442
450
  level: LogLevel.WARN,
443
451
  message,
444
- timestamp: new Date().toISOString(),
452
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
445
453
  context
446
454
  });
447
455
  }
@@ -449,13 +457,12 @@ var LoggerUtil = class {
449
457
  this.logger.log({
450
458
  level: LogLevel.ERROR,
451
459
  message,
452
- timestamp: new Date().toISOString(),
460
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
453
461
  context,
454
462
  error
455
463
  });
456
464
  }
457
465
  };
458
-
459
466
  //#endregion
460
467
  //#region lib/metrics.ts
461
468
  /**
@@ -469,9 +476,8 @@ var NoOpMetricsCollector = class {
469
476
  * Stores metrics in memory with configurable retention.
470
477
  */
471
478
  var InMemoryMetricsCollector = class {
472
- metrics = [];
473
- maxEntries;
474
479
  constructor(maxEntries = 1e3) {
480
+ this.metrics = [];
475
481
  this.maxEntries = maxEntries;
476
482
  }
477
483
  collect(metrics) {
@@ -530,7 +536,6 @@ var ConsoleMetricsCollector = class {
530
536
  console.log("[METRICS]", JSON.stringify(metrics));
531
537
  }
532
538
  };
533
-
534
539
  //#endregion
535
540
  //#region lib/http/http-client.ts
536
541
  /**
@@ -550,16 +555,6 @@ var ConsoleMetricsCollector = class {
550
555
  * ```
551
556
  */
552
557
  var HttpClient = class {
553
- fetchImpl;
554
- baseUrls;
555
- headers;
556
- interceptors;
557
- retry;
558
- timeoutMs;
559
- auth;
560
- logger;
561
- metrics;
562
- onUnauthenticated;
563
558
  /**
564
559
  * Creates a new HTTP client instance.
565
560
  *
@@ -700,8 +695,7 @@ var HttpClient = class {
700
695
  */
701
696
  async request(method, path, body, options) {
702
697
  const startTime = Date.now();
703
- const base = this.resolveBaseUrl(options?.baseUrlKey);
704
- let url = `${base}${path}${toQueryString(options?.query)}`;
698
+ let url = `${this.resolveBaseUrl(options?.baseUrlKey)}${path}${toQueryString(options?.query)}`;
705
699
  this.logger.debug("HTTP request initiated", {
706
700
  method,
707
701
  path,
@@ -739,7 +733,7 @@ var HttpClient = class {
739
733
  while (true) {
740
734
  let timeoutId;
741
735
  if (this.timeoutMs && !options?.signal) timeoutId = setTimeout(() => {
742
- const timeoutError = new Error("Request timeout");
736
+ const timeoutError = /* @__PURE__ */ new Error("Request timeout");
743
737
  timeoutError.name = "TimeoutError";
744
738
  controller.abort(timeoutError);
745
739
  }, this.timeoutMs);
@@ -756,8 +750,7 @@ var HttpClient = class {
756
750
  const req = new Request(url, init);
757
751
  const res = await this.fetchImpl(req);
758
752
  if (res.status === 401 && this.onUnauthenticated && !refreshAttempted) {
759
- const shouldRetry = await this.onUnauthenticated(res.clone());
760
- if (shouldRetry) {
753
+ if (await this.onUnauthenticated(res.clone())) {
761
754
  refreshAttempted = true;
762
755
  if (timeoutId) clearTimeout(timeoutId);
763
756
  continue;
@@ -782,7 +775,7 @@ var HttpClient = class {
782
775
  path,
783
776
  status: res.status,
784
777
  durationMs: duration,
785
- timestamp: new Date().toISOString(),
778
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
786
779
  success: true
787
780
  });
788
781
  return {
@@ -801,7 +794,7 @@ var HttpClient = class {
801
794
  path,
802
795
  status: error instanceof ApiError ? error.status : void 0,
803
796
  durationMs: duration,
804
- timestamp: new Date().toISOString(),
797
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
805
798
  success: false,
806
799
  error: error instanceof Error ? error.message : String(error)
807
800
  });
@@ -817,8 +810,7 @@ var HttpClient = class {
817
810
  if (errorName === "AbortError" || errorName === "TimeoutError") return false;
818
811
  }
819
812
  if (error instanceof ApiError && error.status) {
820
- const retryCodes = this.retry.retryStatusCodes;
821
- if (retryCodes?.some((codeKey) => HTTPStatusCode[codeKey] === error.status)) return true;
813
+ if (this.retry.retryStatusCodes?.some((codeKey) => HTTPStatusCode[codeKey] === error.status)) return true;
822
814
  }
823
815
  return false;
824
816
  };
@@ -882,121 +874,57 @@ var HttpClient = class {
882
874
  }
883
875
  /**
884
876
  * Create a strongly-typed endpoint builder.
877
+ * Works with any Standard Schema-compatible library (Zod, Valibot, ArkType, etc.)
878
+ *
879
+ * @param config - Endpoint configuration with schemas
880
+ * @returns Endpoint call function
881
+ *
882
+ * @example
883
+ * ```ts
884
+ * // With Zod
885
+ * import { z } from 'zod';
886
+ * const getUser = client.createEndpoint({
887
+ * method: 'GET',
888
+ * path: '/users/:id',
889
+ * response: z.object({ id: z.string(), name: z.string() }),
890
+ * pathParams: z.object({ id: z.string() }),
891
+ * });
885
892
  *
886
- * @param config - Endpoint configuration
887
- * @returns Endpoint instance
893
+ * // With Valibot
894
+ * import * as v from 'valibot';
895
+ * const getUser = client.createEndpoint({
896
+ * method: 'GET',
897
+ * path: '/users/:id',
898
+ * response: v.object({ id: v.string(), name: v.string() }),
899
+ * pathParams: v.object({ id: v.string() }),
900
+ * });
901
+ * ```
888
902
  */
889
903
  createEndpoint(config) {
890
904
  const endpoint = new EndpointImpl(this, config);
891
905
  return (params) => endpoint.call(params);
892
906
  }
893
907
  };
894
-
895
- //#endregion
896
- //#region lib/schemas/common.ts
897
- /**
898
- * Common ID type that supports strings, numbers, or UUIDs.
899
- * Use this for entity identifiers in your schemas.
900
- *
901
- * @example
902
- * ```ts
903
- * const UserSchema = z.object({ id: Id, name: z.string() });
904
- * ```
905
- */
906
- const Id = zod.z.union([
907
- zod.z.string().min(1),
908
- zod.z.number(),
909
- zod.z.uuid({ version: "v4" })
910
- ]);
911
- /**
912
- * Common timestamp fields for entities.
913
- * Use this for database models with creation/update tracking.
914
- *
915
- * @example
916
- * ```ts
917
- * const UserSchema = z.object({
918
- * id: Id,
919
- * name: z.string(),
920
- * ...Timestamps.shape
921
- * });
922
- * ```
923
- */
924
- const Timestamps = zod.z.object({
925
- createdAt: zod.z.iso.datetime(),
926
- updatedAt: zod.z.iso.datetime()
927
- });
928
- /**
929
- * Metadata information typically included in API responses.
930
- * Contains request tracking and debugging information.
931
- */
932
- const Meta = zod.z.object({ timestamp: zod.z.iso.datetime().optional() });
933
- /**
934
- * Detailed error information for a specific field or path.
935
- */
936
- const ErrorDetail = zod.z.object({
937
- path: zod.z.string().optional(),
938
- message: zod.z.string()
939
- });
940
- /**
941
- * Standard API error response schema.
942
- * Use this for consistent error handling across your API.
943
- */
944
- const ApiErrorSchema = zod.z.object({
945
- code: zod.z.string(),
946
- message: zod.z.string(),
947
- details: zod.z.array(ErrorDetail).optional()
948
- });
949
- /**
950
- * Generic envelope wrapper for API responses.
951
- * Provides consistent structure with success flag, data, error, and metadata.
952
- *
953
- * @param inner - Zod schema for the response data
954
- * @returns Envelope schema wrapping the inner schema
955
- *
956
- * @example
957
- * ```ts
958
- * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));
959
- *
960
- * // Response structure:
961
- * // {
962
- * // success: true,
963
- * // data: { id: 1, name: 'John' },
964
- * // meta: { timestamp: '...' }
965
- * // }
966
- * ```
967
- */
968
- const Envelope = (inner, meta) => {
969
- return zod.z.object({
970
- success: zod.z.boolean(),
971
- data: inner.optional().nullable(),
972
- error: ApiErrorSchema.optional(),
973
- meta: meta !== void 0 ? meta : Meta.optional()
974
- });
975
- };
976
-
977
908
  //#endregion
978
909
  exports.ApiError = ApiError;
979
- exports.ApiErrorSchema = ApiErrorSchema;
980
910
  exports.ApiKeyAuth = ApiKeyAuth;
981
911
  exports.BearerTokenAuth = BearerTokenAuth;
982
912
  exports.ConsoleLogger = ConsoleLogger;
983
913
  exports.ConsoleMetricsCollector = ConsoleMetricsCollector;
984
914
  exports.EndpointImpl = EndpointImpl;
985
- exports.Envelope = Envelope;
986
- exports.ErrorDetail = ErrorDetail;
987
915
  exports.HTTPMethod = HTTPMethod;
988
916
  exports.HTTPStatusCode = HTTPStatusCode;
989
917
  exports.HttpClient = HttpClient;
990
- exports.Id = Id;
991
918
  exports.InMemoryMetricsCollector = InMemoryMetricsCollector;
992
919
  exports.LogLevel = LogLevel;
993
920
  exports.LoggerUtil = LoggerUtil;
994
- exports.Meta = Meta;
995
921
  exports.NoAuth = NoAuth;
996
922
  exports.NoOpLogger = NoOpLogger;
997
923
  exports.NoOpMetricsCollector = NoOpMetricsCollector;
998
- exports.PaginationSchema = PaginationSchema;
999
924
  exports.SchemaDefinitionError = SchemaDefinitionError;
1000
- exports.Timestamps = Timestamps;
925
+ exports.isStandardSchema = isStandardSchema;
926
+ exports.parseOrThrow = parseOrThrow;
927
+ exports.safeParse = safeParse;
1001
928
  exports.toQueryString = toQueryString;
929
+
1002
930
  //# sourceMappingURL=index.cjs.map