@emeryld/rrroutes-client 2.5.5 → 2.5.7

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
@@ -160,13 +160,84 @@ function buildUrl(leaf, baseUrl, params, query) {
160
160
  const url = `${baseUrl ?? ""}${path}${toSearchString(normalizedQuery)}`;
161
161
  return { url, normalizedQuery, normalizedParams };
162
162
  }
163
- function toFormData(body) {
163
+ function isBlobLike(value) {
164
+ return typeof Blob !== "undefined" && value instanceof Blob;
165
+ }
166
+ function assertFileFieldValue(sourceKey, targetField, value) {
167
+ if (value == null) return;
168
+ if (isBlobLike(value)) return;
169
+ if (typeof FileList !== "undefined" && value instanceof FileList) {
170
+ for (const item of Array.from(value)) {
171
+ if (!isBlobLike(item)) {
172
+ throw new Error(
173
+ `Multipart field "${sourceKey}" must contain Blob/File values for "${targetField}".`
174
+ );
175
+ }
176
+ }
177
+ return;
178
+ }
179
+ if (Array.isArray(value)) {
180
+ for (const item of value) {
181
+ if (!isBlobLike(item)) {
182
+ throw new Error(
183
+ `Multipart field "${sourceKey}" must contain Blob/File values for "${targetField}".`
184
+ );
185
+ }
186
+ }
187
+ return;
188
+ }
189
+ throw new Error(
190
+ `Multipart field "${sourceKey}" must be Blob/File, Blob[] or FileList.`
191
+ );
192
+ }
193
+ function splitMultipartBody(body, fields) {
194
+ if (!body || typeof body !== "object" || Array.isArray(body) || !fields) {
195
+ return {
196
+ regularBody: body,
197
+ multipartFiles: {}
198
+ };
199
+ }
200
+ const fieldByInputKey = /* @__PURE__ */ new Map();
201
+ for (const field of fields) {
202
+ fieldByInputKey.set(`file${field.name}`, field.name);
203
+ fieldByInputKey.set(field.name, field.name);
204
+ }
205
+ const regularBody = {};
206
+ const multipartFiles = {};
207
+ for (const [key, value] of Object.entries(body)) {
208
+ const resolvedFieldName = fieldByInputKey.get(key);
209
+ if (!resolvedFieldName) {
210
+ regularBody[key] = value;
211
+ continue;
212
+ }
213
+ assertFileFieldValue(key, resolvedFieldName, value);
214
+ multipartFiles[resolvedFieldName] = value;
215
+ }
216
+ return { regularBody, multipartFiles };
217
+ }
218
+ function toFormData(body, fields) {
219
+ const fileFieldNames = new Set((fields ?? []).map((field) => field.name));
164
220
  const fd = new FormData();
165
221
  for (const [k, v] of Object.entries(body ?? {})) {
166
222
  if (v == null) continue;
167
- if (Array.isArray(v))
168
- v.forEach((item, i) => fd.append(`${k}[${i}]`, item));
169
- else fd.append(k, v);
223
+ if (fileFieldNames.has(k)) {
224
+ assertFileFieldValue(`file${k}`, k, v);
225
+ }
226
+ if (Array.isArray(v)) {
227
+ for (const item of v) {
228
+ if (item == null) continue;
229
+ fd.append(k, item);
230
+ }
231
+ continue;
232
+ }
233
+ if (typeof FileList !== "undefined" && v instanceof FileList) {
234
+ for (const item of Array.from(v)) {
235
+ if (item == null) continue;
236
+ fd.append(k, item);
237
+ }
238
+ continue;
239
+ }
240
+ fd.append(k, v);
170
241
  }
171
242
  return fd;
172
243
  }
@@ -292,13 +363,23 @@ function buildGetLeaf(leaf, rqOpts, env) {
292
363
  query
293
364
  );
294
365
  let payload;
295
- const acceptsBody = Boolean(leafCfg.bodySchema);
366
+ const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
367
+ const acceptsBody = Boolean(leafCfg.bodySchema || isMultipart);
296
368
  const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
297
369
  if (typeof options?.body !== "undefined") {
298
- const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract2.lowProfileParse)(leafCfg.bodySchema, options.body) : void 0;
299
- const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
370
+ const { regularBody, multipartFiles } = splitMultipartBody(
371
+ options.body,
372
+ leafCfg.bodyFiles
373
+ );
374
+ const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract2.lowProfileParse)(leafCfg.bodySchema, regularBody) : regularBody;
300
375
  if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
301
- payload = toFormData(normalizedBody);
376
+ payload = toFormData(
377
+ {
378
+ ...normalizedBody,
379
+ ...multipartFiles
380
+ },
381
+ leafCfg.bodyFiles
382
+ );
302
383
  } else {
303
384
  payload = normalizedBody;
304
385
  }
@@ -555,13 +636,23 @@ function buildInfiniteGetLeaf(leaf, rqOpts, env) {
555
636
  query
556
637
  );
557
638
  let payload;
558
- const acceptsBody = Boolean(leafCfg.bodySchema);
639
+ const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
640
+ const acceptsBody = Boolean(leafCfg.bodySchema || isMultipart);
559
641
  const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
560
642
  if (typeof options?.body !== "undefined") {
561
- const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract3.lowProfileParse)(leafCfg.bodySchema, options.body) : void 0;
562
- const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
643
+ const { regularBody, multipartFiles } = splitMultipartBody(
644
+ options.body,
645
+ leafCfg.bodyFiles
646
+ );
647
+ const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract3.lowProfileParse)(leafCfg.bodySchema, regularBody) : regularBody;
563
648
  if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
564
- payload = toFormData(normalizedBody);
649
+ payload = toFormData(
650
+ {
651
+ ...normalizedBody,
652
+ ...multipartFiles
653
+ },
654
+ leafCfg.bodyFiles
655
+ );
565
656
  } else {
566
657
  payload = normalizedBody;
567
658
  }
@@ -853,13 +944,23 @@ function buildMutationLeaf(leaf, rqOpts, env) {
853
944
  query
854
945
  );
855
946
  let payload;
856
- const acceptsBody = Boolean(leafCfg.bodySchema);
947
+ const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
948
+ const acceptsBody = Boolean(leafCfg.bodySchema || isMultipart);
857
949
  const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
858
950
  if (typeof options?.body !== "undefined") {
859
- const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract4.lowProfileParse)(leafCfg.bodySchema, options.body) : void 0;
860
- const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
951
+ const { regularBody, multipartFiles } = splitMultipartBody(
952
+ options.body,
953
+ leafCfg.bodyFiles
954
+ );
955
+ const normalizedBody = leafCfg.bodySchema ? (0, import_rrroutes_contract4.lowProfileParse)(leafCfg.bodySchema, regularBody) : regularBody;
861
956
  if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
862
- payload = toFormData(normalizedBody);
957
+ payload = toFormData(
958
+ {
959
+ ...normalizedBody,
960
+ ...multipartFiles
961
+ },
962
+ leafCfg.bodyFiles
963
+ );
863
964
  } else {
864
965
  payload = normalizedBody;
865
966
  }