@emeryld/rrroutes-client 2.2.15 → 2.2.17

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
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ HttpError: () => HttpError,
34
35
  SocketClient: () => SocketClient,
35
36
  buildRoomPayloadSchema: () => buildRoomPayloadSchema,
36
37
  buildRouter: () => buildRouter,
@@ -44,6 +45,19 @@ __export(index_exports, {
44
45
  module.exports = __toCommonJS(index_exports);
45
46
 
46
47
  // src/routesV3.client.fetch.ts
48
+ var HttpError = class extends Error {
49
+ constructor(args) {
50
+ const { res, url, body } = args;
51
+ super(`[${res.status}] ${res.statusText}${body ? ` - ${body}` : ""}`);
52
+ this.message = `${this.message}`;
53
+ this.name = "HttpError";
54
+ this.status = res.status;
55
+ this.statusText = res.statusText;
56
+ this.url = url;
57
+ this.body = body;
58
+ this.headers = res.headers ? Object.fromEntries(res.headers.entries()) : {};
59
+ }
60
+ };
47
61
  var defaultFetcher = async (req) => {
48
62
  const headers = { ...req.headers ?? {} };
49
63
  const isFormData = typeof FormData !== "undefined" && req.body instanceof FormData;
@@ -58,13 +72,24 @@ var defaultFetcher = async (req) => {
58
72
  });
59
73
  const text = await res.text();
60
74
  if (!res.ok) {
61
- const snippet = text.slice(0, 400);
62
- throw new Error(`[${res.status}] ${res.statusText} \u2014 ${snippet}`);
75
+ throw new HttpError({
76
+ res,
77
+ url: req.url,
78
+ body: text
79
+ });
63
80
  }
64
81
  try {
65
- return JSON.parse(text);
82
+ return {
83
+ data: JSON.parse(text),
84
+ headers: res.headers ? Object.fromEntries(res.headers.entries()) : {},
85
+ status: res.status
86
+ };
66
87
  } catch {
67
- return text;
88
+ return {
89
+ data: text,
90
+ headers: res.headers ? Object.fromEntries(res.headers.entries()) : {},
91
+ status: res.status
92
+ };
68
93
  }
69
94
  };
70
95
 
@@ -189,7 +214,9 @@ function getZodShape(schema) {
189
214
  function augmentFeedQuerySchema(schema) {
190
215
  if (!schema) return defaultFeedQuerySchema;
191
216
  if (!(schema instanceof import_zod.z.ZodObject)) {
192
- console.warn("Feed queries must be a ZodObject; default pagination applied.");
217
+ console.warn(
218
+ "Feed queries must be a ZodObject; default pagination applied."
219
+ );
193
220
  return defaultFeedQuerySchema;
194
221
  }
195
222
  return schema.extend(paginationQueryShape);
@@ -554,9 +581,77 @@ function createRouteClient(opts) {
554
581
  fetch: fetchMutation
555
582
  };
556
583
  }
584
+ const fetchRaw = async (input) => {
585
+ const { path, method, query, body, params } = input;
586
+ if (!path || typeof path !== "string") {
587
+ throw new Error("fetch(path, ...) requires a non-empty string path.");
588
+ }
589
+ if (!method) {
590
+ throw new Error("fetch(path, method, ...) requires an HTTP method.");
591
+ }
592
+ const methodLower = String(method).toLowerCase();
593
+ const methodUpper = toUpper(methodLower);
594
+ const flatQuery = normalizeFlatQuery(query);
595
+ const search = toSearchString(flatQuery);
596
+ const compiledPath = compileRawPath(path, params);
597
+ const url = `${baseUrl ?? ""}${compiledPath}${search}`;
598
+ const leafLabel = `${methodUpper} ${path}`;
599
+ const startedAt = Date.now();
600
+ const detail = isVerboseDebug ? { params, query: flatQuery } : void 0;
601
+ emitDebug(
602
+ decorateDebugEvent(
603
+ {
604
+ type: "fetch",
605
+ stage: "start",
606
+ method: methodUpper,
607
+ url,
608
+ leaf: leafLabel,
609
+ ...body !== void 0 ? { body } : {}
610
+ },
611
+ detail
612
+ )
613
+ );
614
+ try {
615
+ const out = await fetcher(
616
+ body === void 0 ? { url, method: methodUpper } : { url, method: methodUpper, body }
617
+ );
618
+ emitDebug(
619
+ decorateDebugEvent(
620
+ {
621
+ type: "fetch",
622
+ stage: "success",
623
+ method: methodUpper,
624
+ url,
625
+ leaf: leafLabel,
626
+ durationMs: Date.now() - startedAt
627
+ },
628
+ isVerboseDebug ? { params, query: flatQuery, output: out } : void 0
629
+ )
630
+ );
631
+ return out;
632
+ } catch (error) {
633
+ emitDebug(
634
+ decorateDebugEvent(
635
+ {
636
+ type: "fetch",
637
+ stage: "error",
638
+ method: methodUpper,
639
+ url,
640
+ leaf: leafLabel,
641
+ durationMs: Date.now() - startedAt,
642
+ ...body !== void 0 ? { body } : {},
643
+ error
644
+ },
645
+ detail
646
+ )
647
+ );
648
+ throw error;
649
+ }
650
+ };
557
651
  return {
558
652
  queryClient,
559
653
  invalidate,
654
+ fetch: fetchRaw,
560
655
  build: buildInternal
561
656
  };
562
657
  }
@@ -578,6 +673,71 @@ function toFormData(body) {
578
673
  }
579
674
  return fd;
580
675
  }
676
+ function getPathParamNames(path) {
677
+ const names = /* @__PURE__ */ new Set();
678
+ const re = /:([A-Za-z0-9_]+)/g;
679
+ let match;
680
+ while ((match = re.exec(path)) !== null) {
681
+ names.add(match[1]);
682
+ }
683
+ return names;
684
+ }
685
+ function normalizeFlatQuery(query) {
686
+ if (query == null) return void 0;
687
+ if (typeof query !== "object" || Array.isArray(query)) {
688
+ throw new Error("Query must be a plain object (Record<string, string>).");
689
+ }
690
+ const result = {};
691
+ for (const [k, v] of Object.entries(query)) {
692
+ if (v == null) continue;
693
+ if (typeof v !== "string") {
694
+ throw new Error(
695
+ `Query param "${k}" must be a string; received type "${typeof v}".`
696
+ );
697
+ }
698
+ result[k] = v;
699
+ }
700
+ return Object.keys(result).length > 0 ? result : void 0;
701
+ }
702
+ function compileRawPath(path, params) {
703
+ const placeholders = getPathParamNames(path);
704
+ if (!params || typeof params !== "object" || Array.isArray(params)) {
705
+ if (placeholders.size > 0) {
706
+ throw new Error(
707
+ `Missing path parameters for "${path}": ${[...placeholders].join(
708
+ ", "
709
+ )}`
710
+ );
711
+ }
712
+ return path;
713
+ }
714
+ const paramObj = params;
715
+ const providedNames = new Set(Object.keys(paramObj));
716
+ for (const name of providedNames) {
717
+ if (!placeholders.has(name)) {
718
+ throw new Error(
719
+ `Unexpected path parameter "${name}" for template "${path}".`
720
+ );
721
+ }
722
+ const value = paramObj[name];
723
+ if (value != null && (typeof value === "object" || Array.isArray(value))) {
724
+ throw new Error(
725
+ `Path parameter "${name}" must be a primitive; received "${typeof value}".`
726
+ );
727
+ }
728
+ }
729
+ for (const name of placeholders) {
730
+ if (!providedNames.has(name)) {
731
+ throw new Error(
732
+ `Missing value for path parameter "${name}" in template "${path}".`
733
+ );
734
+ }
735
+ }
736
+ if (placeholders.size === 0) {
737
+ return path;
738
+ }
739
+ return (0, import_rrroutes_contract.compilePath)(path, paramObj);
740
+ }
581
741
 
582
742
  // src/sockets/socket.client.sys.ts
583
743
  var import_zod2 = require("zod");
@@ -1599,6 +1759,7 @@ var SocketClient = class {
1599
1759
  };
1600
1760
  // Annotate the CommonJS export names for ESM import in node:
1601
1761
  0 && (module.exports = {
1762
+ HttpError,
1602
1763
  SocketClient,
1603
1764
  buildRoomPayloadSchema,
1604
1765
  buildRouter,