@jay-framework/stack-client-runtime 0.16.3 → 0.16.4

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
@@ -332,18 +332,46 @@ let globalOptions = {};
332
332
  function setActionCallerOptions(options) {
333
333
  globalOptions = { ...globalOptions, ...options };
334
334
  }
335
+ function isBlobLike(value) {
336
+ if (typeof value !== "object" || value === null)
337
+ return false;
338
+ if (typeof Blob !== "undefined" && value instanceof Blob)
339
+ return true;
340
+ const b = value;
341
+ return typeof b.size === "number" && !Number.isNaN(b.size) && typeof b.arrayBuffer === "function" && typeof b.slice === "function";
342
+ }
343
+ function isPlainRecord(value) {
344
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !isBlobLike(value);
345
+ }
346
+ function blobPartFilename(blob, fallback) {
347
+ if (typeof File !== "undefined" && blob instanceof File && blob.name)
348
+ return blob.name;
349
+ return fallback;
350
+ }
351
+ function isRecordOfBlobs(value) {
352
+ if (!isPlainRecord(value))
353
+ return false;
354
+ const vals = Object.values(value);
355
+ if (vals.length === 0)
356
+ return false;
357
+ for (const v of vals) {
358
+ if (!isBlobLike(v))
359
+ return false;
360
+ }
361
+ return true;
362
+ }
335
363
  function buildFormData(input) {
336
364
  const formData = new FormData();
337
365
  const jsonFields = {};
338
366
  for (const [key, value] of Object.entries(input)) {
339
- if (value instanceof Blob) {
340
- const name = value instanceof File ? value.name : `${key}.bin`;
367
+ if (isBlobLike(value)) {
368
+ const name = blobPartFilename(value, `${key}.bin`);
341
369
  formData.append(key, value, name);
342
- } else if (Array.isArray(value) && value.some((v) => v instanceof Blob)) {
370
+ } else if (Array.isArray(value) && value.some((v) => isBlobLike(v))) {
343
371
  const nonFiles = [];
344
372
  for (const item of value) {
345
- if (item instanceof Blob) {
346
- const name = item instanceof File ? item.name : `${key}.bin`;
373
+ if (isBlobLike(item)) {
374
+ const name = blobPartFilename(item, `${key}.bin`);
347
375
  formData.append(key, item, name);
348
376
  } else {
349
377
  nonFiles.push(item);
@@ -352,6 +380,11 @@ function buildFormData(input) {
352
380
  if (nonFiles.length > 0) {
353
381
  jsonFields[key] = nonFiles;
354
382
  }
383
+ } else if (isRecordOfBlobs(value)) {
384
+ for (const [subKey, blob] of Object.entries(value)) {
385
+ const name = blobPartFilename(blob, `${subKey}.bin`);
386
+ formData.append(`${key}.${subKey}`, blob, name);
387
+ }
355
388
  } else {
356
389
  jsonFields[key] = value;
357
390
  }
@@ -365,9 +398,11 @@ function hasFiles(input) {
365
398
  if (typeof input !== "object" || input === null)
366
399
  return false;
367
400
  for (const value of Object.values(input)) {
368
- if (value instanceof Blob)
401
+ if (isBlobLike(value))
402
+ return true;
403
+ if (Array.isArray(value) && value.some((v) => isBlobLike(v)))
369
404
  return true;
370
- if (Array.isArray(value) && value.some((v) => v instanceof Blob))
405
+ if (isRecordOfBlobs(value))
371
406
  return true;
372
407
  }
373
408
  return false;
package/dist/index.js CHANGED
@@ -330,18 +330,46 @@ let globalOptions = {};
330
330
  function setActionCallerOptions(options) {
331
331
  globalOptions = { ...globalOptions, ...options };
332
332
  }
333
+ function isBlobLike(value) {
334
+ if (typeof value !== "object" || value === null)
335
+ return false;
336
+ if (typeof Blob !== "undefined" && value instanceof Blob)
337
+ return true;
338
+ const b = value;
339
+ return typeof b.size === "number" && !Number.isNaN(b.size) && typeof b.arrayBuffer === "function" && typeof b.slice === "function";
340
+ }
341
+ function isPlainRecord(value) {
342
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !isBlobLike(value);
343
+ }
344
+ function blobPartFilename(blob, fallback) {
345
+ if (typeof File !== "undefined" && blob instanceof File && blob.name)
346
+ return blob.name;
347
+ return fallback;
348
+ }
349
+ function isRecordOfBlobs(value) {
350
+ if (!isPlainRecord(value))
351
+ return false;
352
+ const vals = Object.values(value);
353
+ if (vals.length === 0)
354
+ return false;
355
+ for (const v of vals) {
356
+ if (!isBlobLike(v))
357
+ return false;
358
+ }
359
+ return true;
360
+ }
333
361
  function buildFormData(input) {
334
362
  const formData = new FormData();
335
363
  const jsonFields = {};
336
364
  for (const [key, value] of Object.entries(input)) {
337
- if (value instanceof Blob) {
338
- const name = value instanceof File ? value.name : `${key}.bin`;
365
+ if (isBlobLike(value)) {
366
+ const name = blobPartFilename(value, `${key}.bin`);
339
367
  formData.append(key, value, name);
340
- } else if (Array.isArray(value) && value.some((v) => v instanceof Blob)) {
368
+ } else if (Array.isArray(value) && value.some((v) => isBlobLike(v))) {
341
369
  const nonFiles = [];
342
370
  for (const item of value) {
343
- if (item instanceof Blob) {
344
- const name = item instanceof File ? item.name : `${key}.bin`;
371
+ if (isBlobLike(item)) {
372
+ const name = blobPartFilename(item, `${key}.bin`);
345
373
  formData.append(key, item, name);
346
374
  } else {
347
375
  nonFiles.push(item);
@@ -350,6 +378,11 @@ function buildFormData(input) {
350
378
  if (nonFiles.length > 0) {
351
379
  jsonFields[key] = nonFiles;
352
380
  }
381
+ } else if (isRecordOfBlobs(value)) {
382
+ for (const [subKey, blob] of Object.entries(value)) {
383
+ const name = blobPartFilename(blob, `${subKey}.bin`);
384
+ formData.append(`${key}.${subKey}`, blob, name);
385
+ }
353
386
  } else {
354
387
  jsonFields[key] = value;
355
388
  }
@@ -363,9 +396,11 @@ function hasFiles(input) {
363
396
  if (typeof input !== "object" || input === null)
364
397
  return false;
365
398
  for (const value of Object.values(input)) {
366
- if (value instanceof Blob)
399
+ if (isBlobLike(value))
400
+ return true;
401
+ if (Array.isArray(value) && value.some((v) => isBlobLike(v)))
367
402
  return true;
368
- if (Array.isArray(value) && value.some((v) => v instanceof Blob))
403
+ if (isRecordOfBlobs(value))
369
404
  return true;
370
405
  }
371
406
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/stack-client-runtime",
3
- "version": "0.16.3",
3
+ "version": "0.16.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -27,15 +27,15 @@
27
27
  "test:watch": "vitest"
28
28
  },
29
29
  "dependencies": {
30
- "@jay-framework/component": "^0.16.3",
31
- "@jay-framework/fullstack-component": "^0.16.3",
32
- "@jay-framework/runtime": "^0.16.3",
33
- "@jay-framework/runtime-automation": "^0.16.3",
34
- "@jay-framework/view-state-merge": "^0.16.3"
30
+ "@jay-framework/component": "^0.16.4",
31
+ "@jay-framework/fullstack-component": "^0.16.4",
32
+ "@jay-framework/runtime": "^0.16.4",
33
+ "@jay-framework/runtime-automation": "^0.16.4",
34
+ "@jay-framework/view-state-merge": "^0.16.4"
35
35
  },
36
36
  "devDependencies": {
37
- "@jay-framework/dev-environment": "^0.16.3",
38
- "@jay-framework/jay-cli": "^0.16.3",
37
+ "@jay-framework/dev-environment": "^0.16.4",
38
+ "@jay-framework/jay-cli": "^0.16.4",
39
39
  "@types/express": "^5.0.2",
40
40
  "@types/node": "^22.15.21",
41
41
  "nodemon": "^3.0.3",