@masters-union/union-stack 0.3.15 → 0.3.16

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.
Files changed (47) hide show
  1. package/dist/cdn/loader.v1.global.js +2 -2
  2. package/dist/cdn/loader.v1.global.js.map +1 -1
  3. package/dist/{chunk-WQ5VYKST.cjs → chunk-3FCZBKNN.cjs} +8 -7
  4. package/dist/chunk-3FCZBKNN.cjs.map +1 -0
  5. package/dist/{chunk-U5MLTERT.js → chunk-7NJTA5ZD.js} +6 -55
  6. package/dist/chunk-7NJTA5ZD.js.map +1 -0
  7. package/dist/{chunk-ZOJLHPVE.cjs → chunk-EBE7EIOZ.cjs} +14 -64
  8. package/dist/chunk-EBE7EIOZ.cjs.map +1 -0
  9. package/dist/chunk-GTE65IAM.cjs +58 -0
  10. package/dist/chunk-GTE65IAM.cjs.map +1 -0
  11. package/dist/{chunk-IX6AZKPO.js → chunk-OZGVTEMZ.js} +4 -3
  12. package/dist/chunk-OZGVTEMZ.js.map +1 -0
  13. package/dist/chunk-XBQENFBZ.js +54 -0
  14. package/dist/chunk-XBQENFBZ.js.map +1 -0
  15. package/dist/{client-C0qMOfb3.d.ts → client-BCLIIiX2.d.ts} +1 -1
  16. package/dist/{client-DOTa3Mai.d.cts → client-CSZ-4GVl.d.cts} +1 -1
  17. package/dist/index.cjs +5 -4
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +4 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/node.cjs +8 -7
  24. package/dist/node.cjs.map +1 -1
  25. package/dist/node.d.cts +2 -2
  26. package/dist/node.d.ts +2 -2
  27. package/dist/node.js +2 -1
  28. package/dist/node.js.map +1 -1
  29. package/dist/picker.cjs +9 -2
  30. package/dist/picker.cjs.map +1 -1
  31. package/dist/picker.d.cts +3 -3
  32. package/dist/picker.d.ts +3 -3
  33. package/dist/picker.js +9 -2
  34. package/dist/picker.js.map +1 -1
  35. package/dist/react.cjs +4 -3
  36. package/dist/react.cjs.map +1 -1
  37. package/dist/react.d.cts +4 -4
  38. package/dist/react.d.ts +4 -4
  39. package/dist/react.js +3 -2
  40. package/dist/react.js.map +1 -1
  41. package/dist/{types-ZCfjNZls.d.ts → types-BWs1slkL.d.cts} +1 -1
  42. package/dist/{types-ZCfjNZls.d.cts → types-BWs1slkL.d.ts} +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-IX6AZKPO.js.map +0 -1
  45. package/dist/chunk-U5MLTERT.js.map +0 -1
  46. package/dist/chunk-WQ5VYKST.cjs.map +0 -1
  47. package/dist/chunk-ZOJLHPVE.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["UnionStackClient"],"mappings":";;;;;;AAGO,IAAM,UAAA,GAAa;AAAA,EACxB,KAAK,GAAA,EAAqC;AACxC,IAAA,OAAO,IAAIA,mCAAiB,GAAG,CAAA;AAAA,EACjC;AACF","file":"index.cjs","sourcesContent":["import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["UnionStackClient"],"mappings":";;;;;;;AAGO,IAAM,UAAA,GAAa;AAAA,EACxB,KAAK,GAAA,EAAqC;AACxC,IAAA,OAAO,IAAIA,mCAAiB,GAAG,CAAA;AAAA,EACjC;AACF","file":"index.cjs","sourcesContent":["import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { U as UnionStackClient } from './client-DOTa3Mai.cjs';
2
- import { C as ClientConfig } from './types-ZCfjNZls.cjs';
3
- export { B as BatchUploadOptions, P as PickResponse, a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode, d as UploadOptions, e as UploadedFile } from './types-ZCfjNZls.cjs';
1
+ import { U as UnionStackClient } from './client-CSZ-4GVl.cjs';
2
+ import { C as ClientConfig } from './types-BWs1slkL.cjs';
3
+ export { B as BatchUploadOptions, P as PickResponse, a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode, d as UploadOptions, e as UploadedFile } from './types-BWs1slkL.cjs';
4
4
 
5
5
  declare const UnionStack: {
6
6
  init(cfg: ClientConfig): UnionStackClient;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { U as UnionStackClient } from './client-C0qMOfb3.js';
2
- import { C as ClientConfig } from './types-ZCfjNZls.js';
3
- export { B as BatchUploadOptions, P as PickResponse, a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode, d as UploadOptions, e as UploadedFile } from './types-ZCfjNZls.js';
1
+ import { U as UnionStackClient } from './client-BCLIIiX2.js';
2
+ import { C as ClientConfig } from './types-BWs1slkL.js';
3
+ export { B as BatchUploadOptions, P as PickResponse, a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode, d as UploadOptions, e as UploadedFile } from './types-BWs1slkL.js';
4
4
 
5
5
  declare const UnionStack: {
6
6
  init(cfg: ClientConfig): UnionStackClient;
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import { UnionStackClient } from './chunk-IX6AZKPO.js';
2
- export { UnionStackClient } from './chunk-IX6AZKPO.js';
3
- import './chunk-U5MLTERT.js';
1
+ import { UnionStackClient } from './chunk-OZGVTEMZ.js';
2
+ export { UnionStackClient } from './chunk-OZGVTEMZ.js';
3
+ import './chunk-7NJTA5ZD.js';
4
+ import './chunk-XBQENFBZ.js';
4
5
 
5
6
  // src/index.ts
6
7
  var UnionStack = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAGO,IAAM,UAAA,GAAa;AAAA,EACxB,KAAK,GAAA,EAAqC;AACxC,IAAA,OAAO,IAAI,iBAAiB,GAAG,CAAA;AAAA,EACjC;AACF","file":"index.js","sourcesContent":["import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAGO,IAAM,UAAA,GAAa;AAAA,EACxB,KAAK,GAAA,EAAqC;AACxC,IAAA,OAAO,IAAI,iBAAiB,GAAG,CAAA;AAAA,EACjC;AACF","file":"index.js","sourcesContent":["import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"]}
package/dist/node.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkZOJLHPVE_cjs = require('./chunk-ZOJLHPVE.cjs');
3
+ var chunkEBE7EIOZ_cjs = require('./chunk-EBE7EIOZ.cjs');
4
+ var chunkGTE65IAM_cjs = require('./chunk-GTE65IAM.cjs');
4
5
  var path = require('path');
5
6
  var promises = require('fs/promises');
6
7
  var fs = require('fs');
@@ -97,7 +98,7 @@ async function resolveSource(source, opts = {}) {
97
98
  const blob = openAsBlob2 ? await openAsBlob2(source, { type: mimetype }) : new Blob([toBlobPart(await promises.readFile(source))], { type: mimetype });
98
99
  return { blob, filename, mimetype };
99
100
  } catch (cause) {
100
- throw chunkZOJLHPVE_cjs.makeError("VALIDATION", `Could not read file at "${source}".`, {
101
+ throw chunkGTE65IAM_cjs.makeError("VALIDATION", `Could not read file at "${source}".`, {
101
102
  retryable: false,
102
103
  cause
103
104
  });
@@ -120,7 +121,7 @@ async function resolveSource(source, opts = {}) {
120
121
  const mimetype = opts.mimeType || mimeFromName(filename);
121
122
  return { blob: new Blob([toBlobPart(source)], { type: mimetype }), filename, mimetype };
122
123
  }
123
- throw chunkZOJLHPVE_cjs.makeError(
124
+ throw chunkGTE65IAM_cjs.makeError(
124
125
  "VALIDATION",
125
126
  "Unsupported upload source. Pass a file path, Buffer, Uint8Array, ArrayBuffer, Blob, or Readable stream.",
126
127
  { retryable: false }
@@ -133,7 +134,7 @@ var DEFAULT_FILE_CONCURRENCY = 5;
133
134
  var UnionStackNodeClient = class {
134
135
  constructor(cfg) {
135
136
  if (!cfg?.apiKey) {
136
- throw chunkZOJLHPVE_cjs.makeError("CONFIG", 'apiKey is required. Pass { apiKey: "unionstack_live_\u2026" }.', {
137
+ throw chunkGTE65IAM_cjs.makeError("CONFIG", 'apiKey is required. Pass { apiKey: "unionstack_live_\u2026" }.', {
137
138
  retryable: false
138
139
  });
139
140
  }
@@ -144,9 +145,9 @@ var UnionStackNodeClient = class {
144
145
  skipConfigPrefetch: true,
145
146
  // Tag the traffic as server-to-server ("node/…") so cdn-be can tell it
146
147
  // apart from browser SDK calls ("js/…").
147
- sdkHeader: chunkZOJLHPVE_cjs.NODE_SDK_VERSION_HEADER
148
+ sdkHeader: chunkEBE7EIOZ_cjs.NODE_SDK_VERSION_HEADER
148
149
  };
149
- this.uploader = new chunkZOJLHPVE_cjs.Uploader(this.cfg);
150
+ this.uploader = new chunkEBE7EIOZ_cjs.Uploader(this.cfg);
150
151
  }
151
152
  /**
152
153
  * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a
@@ -168,7 +169,7 @@ var UnionStackNodeClient = class {
168
169
  */
169
170
  async uploadMany(sources, opts = {}) {
170
171
  if (!Array.isArray(sources) || sources.length === 0) {
171
- const err = chunkZOJLHPVE_cjs.makeError("VALIDATION", "uploadMany requires a non-empty array of sources.", {
172
+ const err = chunkGTE65IAM_cjs.makeError("VALIDATION", "uploadMany requires a non-empty array of sources.", {
172
173
  retryable: false
173
174
  });
174
175
  opts.onError?.(err);
package/dist/node.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/node/source.ts","../src/node/index.ts"],"names":["extname","openAsBlob","fs","basename","readFile","makeError","NODE_SDK_VERSION_HEADER","Uploader"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAM,WAAA,GAAsC;AAAA;AAAA,EAE1C,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,WAAA;AAAA,EAC9D,IAAA,EAAM,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,eAAA;AAAA,EAAiB,GAAA,EAAK,WAAA;AAAA,EACnE,GAAA,EAAK,cAAA;AAAA,EAAgB,IAAA,EAAM,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,YAAA;AAAA;AAAA,EAElE,GAAA,EAAK,iBAAA;AAAA,EAAmB,GAAA,EAAK,YAAA;AAAA,EAAc,GAAA,EAAK,UAAA;AAAA,EAAY,EAAA,EAAI,eAAA;AAAA,EAChE,IAAA,EAAM,kBAAA;AAAA,EAAoB,GAAA,EAAK,iBAAA;AAAA,EAAmB,IAAA,EAAM,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA;AAAA,EAE1E,GAAA,EAAK,oBAAA;AAAA,EACL,IAAA,EAAM,yEAAA;AAAA,EACN,GAAA,EAAK,0BAAA;AAAA,EACL,IAAA,EAAM,mEAAA;AAAA,EACN,GAAA,EAAK,+BAAA;AAAA,EACL,IAAA,EAAM,2EAAA;AAAA;AAAA,EAEN,GAAA,EAAK,WAAA;AAAA,EAAa,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,iBAAA;AAAA,EAAmB,GAAA,EAAK,kBAAA;AAAA,EACnE,GAAA,EAAK,YAAA;AAAA,EAAc,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA;AAAA,EAE5D,GAAA,EAAK,iBAAA;AAAA,EAAmB,EAAA,EAAI,kBAAA;AAAA,EAAoB,GAAA,EAAK;AACvD,CAAA;AAEA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,MAAM,MAAMA,YAAA,CAAQ,IAAI,EAAE,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AAC/C,EAAA,OAAO,WAAA,CAAY,GAAG,CAAA,IAAK,0BAAA;AAC7B;AAOA,IAAMC,WAAAA,GAA4DC,aAAA,CAAA,UAAA;AAKlE,SAAS,WAAW,IAAA,EAA+C;AACjE,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,WAAW,CAAA,EAA2B;AAC7C,EAAA,OACE,CAAC,CAAC,CAAA,IACF,OAAQ,EAAe,IAAA,KAAS,UAAA,IAChC,OAAQ,CAAA,CAAyB,IAAA,KAAS,UAAA;AAE9C;AAEA,eAAe,eAAe,MAAA,EAAmC;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GACjB,QACA,OAAO,KAAA,KAAU,QAAA,GACf,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,GACjB,MAAA,CAAO,KAAK,KAAmB;AAAA,KACvC;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC7B;AAOA,eAAsB,aAAA,CACpB,MAAA,EACA,IAAA,GAAiD,EAAC,EACzB;AAEzB,EAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAYC,aAAA,CAAS,MAAM,CAAA,IAAK,UAAA;AACtD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAOF,cACT,MAAMA,WAAAA,CAAW,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,GAC3C,IAAI,KAAK,CAAC,UAAA,CAAW,MAAMG,iBAAA,CAAS,MAAM,CAAC,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AACrE,MAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,QAAA,EAAS;AAAA,IACpC,SAAS,KAAA,EAAO;AACd,MAAA,MAAMC,2BAAA,CAAU,YAAA,EAAc,CAAA,wBAAA,EAA2B,MAAM,CAAA,EAAA,CAAA,EAAM;AAAA,QACnE,SAAA,EAAW,KAAA;AAAA,QACX;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,IAAI,OAAO,IAAA,KAAS,WAAA,IAAe,MAAA,YAAkB,IAAA,EAAM;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAa,MAAA,CAAoC,IAAA,IAAQ,UAAA;AAC/E,IAAA,MAAM,WAAW,IAAA,CAAK,QAAA,IAAY,MAAA,CAAO,IAAA,IAAQ,aAAa,QAAQ,CAAA;AAEtE,IAAA,MAAM,OACJ,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,QAAA,KAAa,OAAO,IAAA,GACtC,IAAI,IAAA,CAAK,CAAC,MAAM,CAAA,EAAG,EAAE,MAAM,IAAA,CAAK,QAAA,EAAU,CAAA,GAC1C,MAAA;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,QAAA,EAAS;AAAA,EACpC;AAGA,EAAA,IAAI,UAAA,CAAW,MAAM,CAAA,EAAG;AACtB,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,UAAA;AAClC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,MAAM,GAAA,GAAM,MAAM,cAAA,CAAe,MAAM,CAAA;AACvC,IAAA,OAAO,EAAE,IAAA,EAAM,IAAI,IAAA,CAAK,CAAC,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,EAAG,UAAU,QAAA,EAAS;AAAA,EACrF;AAGA,EAAA,IAAI,MAAA,YAAkB,WAAA,IAAe,WAAA,CAAY,MAAA,CAAO,MAAM,CAAA,EAAG;AAC/D,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,UAAA;AAClC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,OAAO,EAAE,IAAA,EAAM,IAAI,IAAA,CAAK,CAAC,UAAA,CAAW,MAAM,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,EAAG,UAAU,QAAA,EAAS;AAAA,EACxF;AAEA,EAAA,MAAMA,2BAAA;AAAA,IACJ,YAAA;AAAA,IACA,yGAAA;AAAA,IACA,EAAE,WAAW,KAAA;AAAM,GACrB;AACF;;;ACtIA,IAAM,QAAA,GAAW,gCAAA;AAKjB,IAAM,wBAAA,GAA2B,CAAA;AAiB1B,IAAM,uBAAN,MAA2B;AAAA,EAIhC,YAAY,GAAA,EAAmB;AAG7B,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAMA,2BAAA,CAAU,UAAU,gEAAA,EAA6D;AAAA,QACrF,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AACA,IAAA,IAAA,CAAK,GAAA,GAAM;AAAA,MACT,GAAG,GAAA;AAAA,MACH,OAAA,EAAS,QAAA;AAAA;AAAA,MAET,kBAAA,EAAoB,IAAA;AAAA;AAAA;AAAA,MAGpB,SAAA,EAAWC;AAAA,KACb;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAIC,0BAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAA,CAAO,MAAA,EAA0B,IAAA,GAAsB,EAAC,EAA0B;AACtF,IAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,MAAA,EAAQ,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,CAAA;AACjG,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,QAAA,CAAS,IAAA,EAAM;AAAA,MACzC,GAAG,IAAA;AAAA,MACH,UAAU,QAAA,CAAS,QAAA;AAAA,MACnB,UAAU,QAAA,CAAS;AAAA,KACpB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAA,CAAW,OAAA,EAA6B,IAAA,GAA2B,EAAC,EAA0B;AAClG,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnD,MAAA,MAAM,GAAA,GAAMF,2BAAA,CAAU,YAAA,EAAc,mDAAA,EAAqD;AAAA,QACvF,SAAA,EAAW;AAAA,OACZ,CAAA;AACD,MAAA,IAAA,CAAK,UAAU,GAAG,CAAA;AAClB,MAAA,MAAM,GAAA;AAAA,IACR;AAEA,IAAA,MAAM,gBAAgC,EAAC;AACvC,IAAA,MAAM,cAA+D,EAAC;AAEtE,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,MAAM,SAAS,YAA2B;AACxC,MAAA,OAAO,IAAA,EAAM;AACX,QAAA,MAAM,CAAA,GAAI,MAAA,EAAA;AACV,QAAA,IAAI,CAAA,IAAK,QAAQ,MAAA,EAAQ;AAEzB,QAAA,IAAI,QAAA;AACJ,QAAA,IAAI;AACF,UAAA,QAAA,GAAW,MAAM,aAAA,CAAc,OAAA,CAAQ,CAAC,CAAA,EAAG;AAAA,YACzC,UAAU,IAAA,CAAK,QAAA;AAAA,YACf,UAAU,IAAA,CAAK;AAAA,WAChB,CAAA;AAAA,QACH,SAAS,GAAA,EAAK;AACZ,UAAA,WAAA,CAAY,IAAA,CAAK,EAAE,IAAA,EAAM,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA,EAAG,KAAA,EAAO,GAAA,EAAoB,CAAA;AAC7F,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,MAAA,GAAqB;AAAA,UACzB,QAAA,EAAU,OAAO,CAAC,CAAA;AAAA,UAClB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,IAAA,EAAM,SAAS,IAAA,CAAK,IAAA;AAAA,UACpB,MAAA,EAAQ;AAAA,SACV;AACA,QAAA,IAAI;AACF,UAAA,MAAM,WAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,SAAS,IAAA,EAAM;AAAA,YACzD,GAAG,IAAA;AAAA,YACH,UAAU,QAAA,CAAS,QAAA;AAAA,YACnB,UAAU,QAAA,CAAS;AAAA,WACpB,CAAA;AACD,UAAA,QAAA,CAAS,WAAW,MAAA,CAAO,QAAA;AAC3B,UAAA,aAAA,CAAc,KAAK,QAAQ,CAAA;AAAA,QAC7B,SAAS,GAAA,EAAK;AACZ,UAAA,WAAA,CAAY,KAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,KAAoB,CAAA;AAAA,QAC9D;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,wBAAA,EAA0B,OAAA,CAAQ,MAAM,CAAC,CAAA;AAC3E,IAAA,MAAM,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAK,EAAG,MAAM,CAAC,CAAA;AAEtD,IAAA,MAAM,MAAA,GAAuB,EAAE,aAAA,EAAe,WAAA,EAAY;AAC1D,IAAA,IAAA,CAAK,eAAe,MAAM,CAAA;AAC1B,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,MAAA,GAAyC;AAC3C,IAAA,OAAO,IAAA,CAAK,GAAA;AAAA,EACd;AACF;AAGA,SAAS,kBAAA,CACP,MAAA,EACA,KAAA,EACA,IAAA,EACY;AACZ,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,OAAO,KAAK,CAAA;AAAA,IACtB,QAAA,EAAU,KAAK,QAAA,KAAa,OAAO,WAAW,QAAA,GAAWF,aAAAA,CAAS,MAAM,CAAA,GAAI,UAAA,CAAA;AAAA,IAC5E,QAAA,EAAU,KAAK,QAAA,IAAY,0BAAA;AAAA,IAC3B,IAAA,EAAM,CAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACV;AACF;AAEO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,KAAK,GAAA,EAAyC;AAC5C,IAAA,OAAO,IAAI,qBAAqB,GAAG,CAAA;AAAA,EACrC;AACF","file":"node.cjs","sourcesContent":["import { basename, extname } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport * as fs from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { makeError } from '../errors.js';\n\n/**\n * Anything the Node client knows how to turn into an upload.\n *\n * • `string` — path to a file on disk (absolute or relative to cwd)\n * • `Buffer` / typed arr — raw bytes already in memory\n * • `ArrayBuffer` — raw bytes\n * • `Blob` / `File` — Web file objects (Node 18+ has `Blob`, 20+ has `File`)\n * • `Readable` — a Node stream (buffered in full before upload, since\n * the multipart protocol needs the total size up front)\n */\nexport type NodeUploadSource =\n | string\n | Buffer\n | Uint8Array\n | ArrayBuffer\n | Blob\n | Readable;\n\nexport interface ResolvedSource {\n /** A Web `Blob` the core Uploader can `.slice()` into multipart chunks. */\n blob: Blob;\n filename: string;\n mimetype: string;\n}\n\n// Smallest map that covers the bulk of real-world server uploads. Anything not\n// listed falls back to application/octet-stream — callers can always override\n// via `{ mimeType }`. Kept deliberately short; this is not a full mime database.\nconst EXT_TO_MIME: Record<string, string> = {\n // images\n png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',\n webp: 'image/webp', avif: 'image/avif', svg: 'image/svg+xml', bmp: 'image/bmp',\n ico: 'image/x-icon', heic: 'image/heic', tiff: 'image/tiff', tif: 'image/tiff',\n // documents\n pdf: 'application/pdf', txt: 'text/plain', csv: 'text/csv', md: 'text/markdown',\n json: 'application/json', xml: 'application/xml', html: 'text/html', htm: 'text/html',\n // office\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // media\n mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', mkv: 'video/x-matroska',\n mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4',\n // archives\n zip: 'application/zip', gz: 'application/gzip', tar: 'application/x-tar',\n};\n\nfunction mimeFromName(name: string): string {\n const ext = extname(name).slice(1).toLowerCase();\n return EXT_TO_MIME[ext] || 'application/octet-stream';\n}\n\n// `fs.openAsBlob` (Node 19.8+/20+) hands back a Blob backed by the file on disk,\n// so slicing it into parts streams lazily instead of loading the whole file into\n// memory. Typed locally — the global DOM `Blob` is what the Uploader wants, and\n// not every @types/node version exposes openAsBlob.\ntype OpenAsBlob = (path: string, options?: { type?: string }) => Promise<Blob>;\nconst openAsBlob = (fs as unknown as { openAsBlob?: OpenAsBlob }).openAsBlob;\n\n// Node's `Buffer<ArrayBufferLike>` and the DOM lib's `BlobPart`\n// (`ArrayBufferView<ArrayBuffer>`) don't line up under recent @types/node, even\n// though every value passed here is a valid Blob part at runtime. Cast once.\nfunction toBlobPart(data: ArrayBuffer | ArrayBufferView): BlobPart {\n return data as unknown as BlobPart;\n}\n\nfunction isReadable(x: unknown): x is Readable {\n return (\n !!x &&\n typeof (x as Readable).pipe === 'function' &&\n typeof (x as { read?: unknown }).read === 'function'\n );\n}\n\nasync function streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(\n Buffer.isBuffer(chunk)\n ? chunk\n : typeof chunk === 'string'\n ? Buffer.from(chunk)\n : Buffer.from(chunk as Uint8Array),\n );\n }\n return Buffer.concat(chunks);\n}\n\n/**\n * Normalize any {@link NodeUploadSource} into a `{ blob, filename, mimetype }`\n * the core Uploader can consume. Caller-supplied `filename` / `mimeType` always\n * win over what we infer from the path or the blob.\n */\nexport async function resolveSource(\n source: NodeUploadSource,\n opts: { filename?: string; mimeType?: string } = {},\n): Promise<ResolvedSource> {\n // 1. File path on disk.\n if (typeof source === 'string') {\n const filename = opts.filename || basename(source) || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n try {\n const blob = openAsBlob\n ? await openAsBlob(source, { type: mimetype })\n : new Blob([toBlobPart(await readFile(source))], { type: mimetype });\n return { blob, filename, mimetype };\n } catch (cause) {\n throw makeError('VALIDATION', `Could not read file at \"${source}\".`, {\n retryable: false,\n cause,\n });\n }\n }\n\n // 2. Already a Blob / File.\n if (typeof Blob !== 'undefined' && source instanceof Blob) {\n const filename = opts.filename || (source as Blob & { name?: string }).name || 'untitled';\n const mimetype = opts.mimeType || source.type || mimeFromName(filename);\n // Only re-wrap when we need to stamp a type the blob doesn't already carry.\n const blob =\n opts.mimeType && opts.mimeType !== source.type\n ? new Blob([source], { type: opts.mimeType })\n : source;\n return { blob, filename, mimetype };\n }\n\n // 3. Node Readable stream — buffer it fully; multipart needs the size up front.\n if (isReadable(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n const buf = await streamToBuffer(source);\n return { blob: new Blob([toBlobPart(buf)], { type: mimetype }), filename, mimetype };\n }\n\n // 4. Buffer / Uint8Array / ArrayBuffer (Buffer is an ArrayBuffer view).\n if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n return { blob: new Blob([toBlobPart(source)], { type: mimetype }), filename, mimetype };\n }\n\n throw makeError(\n 'VALIDATION',\n 'Unsupported upload source. Pass a file path, Buffer, Uint8Array, ArrayBuffer, Blob, or Readable stream.',\n { retryable: false },\n );\n}\n","import { basename } from 'node:path';\nimport { Uploader } from '../uploader.js';\nimport { makeError } from '../errors.js';\nimport { NODE_SDK_VERSION_HEADER } from '../version.js';\nimport { resolveSource, type NodeUploadSource } from './source.js';\nimport type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickedFile,\n PickResponse,\n UploadError,\n} from '../types.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this — we\n * ship a new SDK version if the URL ever changes. (Same constant as the browser\n * client; kept independent so the Node entry doesn't pull in client.ts.)\n */\nconst API_BASE = 'https://api.unionstack.link/v1';\n\n// File-level fan-out for uploadMany. Each file still runs its own part-level\n// concurrency (opts.concurrency), so this caps how many files upload at once —\n// keeps a 10k-file batch from opening 10k sockets / file handles simultaneously.\nconst DEFAULT_FILE_CONCURRENCY = 5;\n\n/**\n * Server-side UnionStack client for Node.js. Uploads files straight to your\n * UnionStack bucket from a backend — no browser, no picker, no DOM.\n *\n * Use an API key whose allowed origins include `*` (server-to-server requests\n * carry no `Origin` header). Create the key and add `*` from your dashboard.\n *\n * ```ts\n * import { UnionStack } from '@masters-union/union-stack/node';\n *\n * const client = UnionStack.init({ apiKey: process.env.UNIONSTACK_API_KEY! });\n * const file = await client.upload('./invoice.pdf');\n * console.log(file.url);\n * ```\n */\nexport class UnionStackNodeClient {\n private uploader: Uploader;\n private cfg: ResolvedClientConfig;\n\n constructor(cfg: ClientConfig) {\n // A server SDK can throw on misconfiguration — unlike the browser client,\n // there's no render path to crash.\n if (!cfg?.apiKey) {\n throw makeError('CONFIG', 'apiKey is required. Pass { apiKey: \"unionstack_live_…\" }.', {\n retryable: false,\n });\n }\n this.cfg = {\n ...cfg,\n apiBase: API_BASE,\n // No picker on the server — never prefetch the picker config.\n skipConfigPrefetch: true,\n // Tag the traffic as server-to-server (\"node/…\") so cdn-be can tell it\n // apart from browser SDK calls (\"js/…\").\n sdkHeader: NODE_SDK_VERSION_HEADER,\n };\n this.uploader = new Uploader(this.cfg);\n }\n\n /**\n * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a\n * Blob/File, or a Readable stream. Returns the stored file (with its public\n * `url`). Rejects with an {@link UploadError}.\n */\n async upload(source: NodeUploadSource, opts: UploadOptions = {}): Promise<UploadedFile> {\n const resolved = await resolveSource(source, { filename: opts.filename, mimeType: opts.mimeType });\n return this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n }\n\n /**\n * Upload many files. Runs up to {@link DEFAULT_FILE_CONCURRENCY} files at once\n * and never rejects on a single file's failure — successes and failures come\n * back separately so a partial failure doesn't drop the whole batch.\n */\n async uploadMany(sources: NodeUploadSource[], opts: BatchUploadOptions = {}): Promise<PickResponse> {\n if (!Array.isArray(sources) || sources.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of sources.', {\n retryable: false,\n });\n opts.onError?.(err);\n throw err;\n }\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n let cursor = 0;\n const worker = async (): Promise<void> => {\n while (true) {\n const i = cursor++;\n if (i >= sources.length) return;\n\n let resolved;\n try {\n resolved = await resolveSource(sources[i], {\n filename: opts.filename,\n mimeType: opts.mimeType,\n });\n } catch (err) {\n filesFailed.push({ file: describeUnresolved(sources[i], i, opts), error: err as UploadError });\n continue;\n }\n\n const picked: PickedFile = {\n uploadId: String(i),\n filename: resolved.filename,\n mimetype: resolved.mimetype,\n size: resolved.blob.size,\n source: 'local',\n };\n try {\n const uploaded = await this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n uploaded.uploadId = picked.uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked, error: err as UploadError });\n }\n }\n };\n\n const pool = Math.max(1, Math.min(DEFAULT_FILE_CONCURRENCY, sources.length));\n await Promise.all(Array.from({ length: pool }, worker));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n\n /** Read-only view of the resolved config. */\n get config(): Readonly<ResolvedClientConfig> {\n return this.cfg;\n }\n}\n\n/** Best-effort descriptor for a file that failed before we could read it. */\nfunction describeUnresolved(\n source: NodeUploadSource,\n index: number,\n opts: BatchUploadOptions,\n): PickedFile {\n return {\n uploadId: String(index),\n filename: opts.filename || (typeof source === 'string' ? basename(source) : 'untitled'),\n mimetype: opts.mimeType || 'application/octet-stream',\n size: 0,\n source: 'local',\n };\n}\n\nexport const UnionStack = {\n /** Create a server-side client. `cfg.apiKey` is required. */\n init(cfg: ClientConfig): UnionStackNodeClient {\n return new UnionStackNodeClient(cfg);\n },\n};\n\nexport type { NodeUploadSource } from './source.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from '../types.js';\n"]}
1
+ {"version":3,"sources":["../src/node/source.ts","../src/node/index.ts"],"names":["extname","openAsBlob","fs","basename","readFile","makeError","NODE_SDK_VERSION_HEADER","Uploader"],"mappings":"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","file":"node.cjs","sourcesContent":["import { basename, extname } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport * as fs from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { makeError } from '../errors.js';\n\n/**\n * Anything the Node client knows how to turn into an upload.\n *\n * • `string` — path to a file on disk (absolute or relative to cwd)\n * • `Buffer` / typed arr — raw bytes already in memory\n * • `ArrayBuffer` — raw bytes\n * • `Blob` / `File` — Web file objects (Node 18+ has `Blob`, 20+ has `File`)\n * • `Readable` — a Node stream (buffered in full before upload, since\n * the multipart protocol needs the total size up front)\n */\nexport type NodeUploadSource =\n | string\n | Buffer\n | Uint8Array\n | ArrayBuffer\n | Blob\n | Readable;\n\nexport interface ResolvedSource {\n /** A Web `Blob` the core Uploader can `.slice()` into multipart chunks. */\n blob: Blob;\n filename: string;\n mimetype: string;\n}\n\n// Smallest map that covers the bulk of real-world server uploads. Anything not\n// listed falls back to application/octet-stream — callers can always override\n// via `{ mimeType }`. Kept deliberately short; this is not a full mime database.\nconst EXT_TO_MIME: Record<string, string> = {\n // images\n png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',\n webp: 'image/webp', avif: 'image/avif', svg: 'image/svg+xml', bmp: 'image/bmp',\n ico: 'image/x-icon', heic: 'image/heic', tiff: 'image/tiff', tif: 'image/tiff',\n // documents\n pdf: 'application/pdf', txt: 'text/plain', csv: 'text/csv', md: 'text/markdown',\n json: 'application/json', xml: 'application/xml', html: 'text/html', htm: 'text/html',\n // office\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // media\n mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', mkv: 'video/x-matroska',\n mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4',\n // archives\n zip: 'application/zip', gz: 'application/gzip', tar: 'application/x-tar',\n};\n\nfunction mimeFromName(name: string): string {\n const ext = extname(name).slice(1).toLowerCase();\n return EXT_TO_MIME[ext] || 'application/octet-stream';\n}\n\n// `fs.openAsBlob` (Node 19.8+/20+) hands back a Blob backed by the file on disk,\n// so slicing it into parts streams lazily instead of loading the whole file into\n// memory. Typed locally — the global DOM `Blob` is what the Uploader wants, and\n// not every @types/node version exposes openAsBlob.\ntype OpenAsBlob = (path: string, options?: { type?: string }) => Promise<Blob>;\nconst openAsBlob = (fs as unknown as { openAsBlob?: OpenAsBlob }).openAsBlob;\n\n// Node's `Buffer<ArrayBufferLike>` and the DOM lib's `BlobPart`\n// (`ArrayBufferView<ArrayBuffer>`) don't line up under recent @types/node, even\n// though every value passed here is a valid Blob part at runtime. Cast once.\nfunction toBlobPart(data: ArrayBuffer | ArrayBufferView): BlobPart {\n return data as unknown as BlobPart;\n}\n\nfunction isReadable(x: unknown): x is Readable {\n return (\n !!x &&\n typeof (x as Readable).pipe === 'function' &&\n typeof (x as { read?: unknown }).read === 'function'\n );\n}\n\nasync function streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(\n Buffer.isBuffer(chunk)\n ? chunk\n : typeof chunk === 'string'\n ? Buffer.from(chunk)\n : Buffer.from(chunk as Uint8Array),\n );\n }\n return Buffer.concat(chunks);\n}\n\n/**\n * Normalize any {@link NodeUploadSource} into a `{ blob, filename, mimetype }`\n * the core Uploader can consume. Caller-supplied `filename` / `mimeType` always\n * win over what we infer from the path or the blob.\n */\nexport async function resolveSource(\n source: NodeUploadSource,\n opts: { filename?: string; mimeType?: string } = {},\n): Promise<ResolvedSource> {\n // 1. File path on disk.\n if (typeof source === 'string') {\n const filename = opts.filename || basename(source) || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n try {\n const blob = openAsBlob\n ? await openAsBlob(source, { type: mimetype })\n : new Blob([toBlobPart(await readFile(source))], { type: mimetype });\n return { blob, filename, mimetype };\n } catch (cause) {\n throw makeError('VALIDATION', `Could not read file at \"${source}\".`, {\n retryable: false,\n cause,\n });\n }\n }\n\n // 2. Already a Blob / File.\n if (typeof Blob !== 'undefined' && source instanceof Blob) {\n const filename = opts.filename || (source as Blob & { name?: string }).name || 'untitled';\n const mimetype = opts.mimeType || source.type || mimeFromName(filename);\n // Only re-wrap when we need to stamp a type the blob doesn't already carry.\n const blob =\n opts.mimeType && opts.mimeType !== source.type\n ? new Blob([source], { type: opts.mimeType })\n : source;\n return { blob, filename, mimetype };\n }\n\n // 3. Node Readable stream — buffer it fully; multipart needs the size up front.\n if (isReadable(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n const buf = await streamToBuffer(source);\n return { blob: new Blob([toBlobPart(buf)], { type: mimetype }), filename, mimetype };\n }\n\n // 4. Buffer / Uint8Array / ArrayBuffer (Buffer is an ArrayBuffer view).\n if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n return { blob: new Blob([toBlobPart(source)], { type: mimetype }), filename, mimetype };\n }\n\n throw makeError(\n 'VALIDATION',\n 'Unsupported upload source. Pass a file path, Buffer, Uint8Array, ArrayBuffer, Blob, or Readable stream.',\n { retryable: false },\n );\n}\n","import { basename } from 'node:path';\nimport { Uploader } from '../uploader.js';\nimport { makeError } from '../errors.js';\nimport { NODE_SDK_VERSION_HEADER } from '../version.js';\nimport { resolveSource, type NodeUploadSource } from './source.js';\nimport type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickedFile,\n PickResponse,\n UploadError,\n} from '../types.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this — we\n * ship a new SDK version if the URL ever changes. (Same constant as the browser\n * client; kept independent so the Node entry doesn't pull in client.ts.)\n */\nconst API_BASE = 'https://api.unionstack.link/v1';\n\n// File-level fan-out for uploadMany. Each file still runs its own part-level\n// concurrency (opts.concurrency), so this caps how many files upload at once —\n// keeps a 10k-file batch from opening 10k sockets / file handles simultaneously.\nconst DEFAULT_FILE_CONCURRENCY = 5;\n\n/**\n * Server-side UnionStack client for Node.js. Uploads files straight to your\n * UnionStack bucket from a backend — no browser, no picker, no DOM.\n *\n * Use an API key whose allowed origins include `*` (server-to-server requests\n * carry no `Origin` header). Create the key and add `*` from your dashboard.\n *\n * ```ts\n * import { UnionStack } from '@masters-union/union-stack/node';\n *\n * const client = UnionStack.init({ apiKey: process.env.UNIONSTACK_API_KEY! });\n * const file = await client.upload('./invoice.pdf');\n * console.log(file.url);\n * ```\n */\nexport class UnionStackNodeClient {\n private uploader: Uploader;\n private cfg: ResolvedClientConfig;\n\n constructor(cfg: ClientConfig) {\n // A server SDK can throw on misconfiguration — unlike the browser client,\n // there's no render path to crash.\n if (!cfg?.apiKey) {\n throw makeError('CONFIG', 'apiKey is required. Pass { apiKey: \"unionstack_live_…\" }.', {\n retryable: false,\n });\n }\n this.cfg = {\n ...cfg,\n apiBase: API_BASE,\n // No picker on the server — never prefetch the picker config.\n skipConfigPrefetch: true,\n // Tag the traffic as server-to-server (\"node/…\") so cdn-be can tell it\n // apart from browser SDK calls (\"js/…\").\n sdkHeader: NODE_SDK_VERSION_HEADER,\n };\n this.uploader = new Uploader(this.cfg);\n }\n\n /**\n * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a\n * Blob/File, or a Readable stream. Returns the stored file (with its public\n * `url`). Rejects with an {@link UploadError}.\n */\n async upload(source: NodeUploadSource, opts: UploadOptions = {}): Promise<UploadedFile> {\n const resolved = await resolveSource(source, { filename: opts.filename, mimeType: opts.mimeType });\n return this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n }\n\n /**\n * Upload many files. Runs up to {@link DEFAULT_FILE_CONCURRENCY} files at once\n * and never rejects on a single file's failure — successes and failures come\n * back separately so a partial failure doesn't drop the whole batch.\n */\n async uploadMany(sources: NodeUploadSource[], opts: BatchUploadOptions = {}): Promise<PickResponse> {\n if (!Array.isArray(sources) || sources.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of sources.', {\n retryable: false,\n });\n opts.onError?.(err);\n throw err;\n }\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n let cursor = 0;\n const worker = async (): Promise<void> => {\n while (true) {\n const i = cursor++;\n if (i >= sources.length) return;\n\n let resolved;\n try {\n resolved = await resolveSource(sources[i], {\n filename: opts.filename,\n mimeType: opts.mimeType,\n });\n } catch (err) {\n filesFailed.push({ file: describeUnresolved(sources[i], i, opts), error: err as UploadError });\n continue;\n }\n\n const picked: PickedFile = {\n uploadId: String(i),\n filename: resolved.filename,\n mimetype: resolved.mimetype,\n size: resolved.blob.size,\n source: 'local',\n };\n try {\n const uploaded = await this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n uploaded.uploadId = picked.uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked, error: err as UploadError });\n }\n }\n };\n\n const pool = Math.max(1, Math.min(DEFAULT_FILE_CONCURRENCY, sources.length));\n await Promise.all(Array.from({ length: pool }, worker));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n\n /** Read-only view of the resolved config. */\n get config(): Readonly<ResolvedClientConfig> {\n return this.cfg;\n }\n}\n\n/** Best-effort descriptor for a file that failed before we could read it. */\nfunction describeUnresolved(\n source: NodeUploadSource,\n index: number,\n opts: BatchUploadOptions,\n): PickedFile {\n return {\n uploadId: String(index),\n filename: opts.filename || (typeof source === 'string' ? basename(source) : 'untitled'),\n mimetype: opts.mimeType || 'application/octet-stream',\n size: 0,\n source: 'local',\n };\n}\n\nexport const UnionStack = {\n /** Create a server-side client. `cfg.apiKey` is required. */\n init(cfg: ClientConfig): UnionStackNodeClient {\n return new UnionStackNodeClient(cfg);\n },\n};\n\nexport type { NodeUploadSource } from './source.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from '../types.js';\n"]}
package/dist/node.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Readable } from 'node:stream';
2
- import { C as ClientConfig, d as UploadOptions, e as UploadedFile, B as BatchUploadOptions, P as PickResponse, R as ResolvedClientConfig } from './types-ZCfjNZls.cjs';
3
- export { a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode } from './types-ZCfjNZls.cjs';
2
+ import { C as ClientConfig, d as UploadOptions, e as UploadedFile, B as BatchUploadOptions, P as PickResponse, R as ResolvedClientConfig } from './types-BWs1slkL.cjs';
3
+ export { a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode } from './types-BWs1slkL.cjs';
4
4
 
5
5
  /**
6
6
  * Anything the Node client knows how to turn into an upload.
package/dist/node.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Readable } from 'node:stream';
2
- import { C as ClientConfig, d as UploadOptions, e as UploadedFile, B as BatchUploadOptions, P as PickResponse, R as ResolvedClientConfig } from './types-ZCfjNZls.js';
3
- export { a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode } from './types-ZCfjNZls.js';
2
+ import { C as ClientConfig, d as UploadOptions, e as UploadedFile, B as BatchUploadOptions, P as PickResponse, R as ResolvedClientConfig } from './types-BWs1slkL.js';
3
+ export { a as PickedFile, b as ProgressEvent, S as Source, U as UploadError, c as UploadErrorCode } from './types-BWs1slkL.js';
4
4
 
5
5
  /**
6
6
  * Anything the Node client knows how to turn into an upload.
package/dist/node.js CHANGED
@@ -1,4 +1,5 @@
1
- import { makeError, NODE_SDK_VERSION_HEADER, Uploader } from './chunk-U5MLTERT.js';
1
+ import { NODE_SDK_VERSION_HEADER, Uploader } from './chunk-7NJTA5ZD.js';
2
+ import { makeError } from './chunk-XBQENFBZ.js';
2
3
  import { basename, extname } from 'path';
3
4
  import { readFile } from 'fs/promises';
4
5
  import * as fs from 'fs';
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/node/source.ts","../src/node/index.ts"],"names":["openAsBlob","basename"],"mappings":"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","file":"node.js","sourcesContent":["import { basename, extname } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport * as fs from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { makeError } from '../errors.js';\n\n/**\n * Anything the Node client knows how to turn into an upload.\n *\n * • `string` — path to a file on disk (absolute or relative to cwd)\n * • `Buffer` / typed arr — raw bytes already in memory\n * • `ArrayBuffer` — raw bytes\n * • `Blob` / `File` — Web file objects (Node 18+ has `Blob`, 20+ has `File`)\n * • `Readable` — a Node stream (buffered in full before upload, since\n * the multipart protocol needs the total size up front)\n */\nexport type NodeUploadSource =\n | string\n | Buffer\n | Uint8Array\n | ArrayBuffer\n | Blob\n | Readable;\n\nexport interface ResolvedSource {\n /** A Web `Blob` the core Uploader can `.slice()` into multipart chunks. */\n blob: Blob;\n filename: string;\n mimetype: string;\n}\n\n// Smallest map that covers the bulk of real-world server uploads. Anything not\n// listed falls back to application/octet-stream — callers can always override\n// via `{ mimeType }`. Kept deliberately short; this is not a full mime database.\nconst EXT_TO_MIME: Record<string, string> = {\n // images\n png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',\n webp: 'image/webp', avif: 'image/avif', svg: 'image/svg+xml', bmp: 'image/bmp',\n ico: 'image/x-icon', heic: 'image/heic', tiff: 'image/tiff', tif: 'image/tiff',\n // documents\n pdf: 'application/pdf', txt: 'text/plain', csv: 'text/csv', md: 'text/markdown',\n json: 'application/json', xml: 'application/xml', html: 'text/html', htm: 'text/html',\n // office\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // media\n mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', mkv: 'video/x-matroska',\n mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4',\n // archives\n zip: 'application/zip', gz: 'application/gzip', tar: 'application/x-tar',\n};\n\nfunction mimeFromName(name: string): string {\n const ext = extname(name).slice(1).toLowerCase();\n return EXT_TO_MIME[ext] || 'application/octet-stream';\n}\n\n// `fs.openAsBlob` (Node 19.8+/20+) hands back a Blob backed by the file on disk,\n// so slicing it into parts streams lazily instead of loading the whole file into\n// memory. Typed locally — the global DOM `Blob` is what the Uploader wants, and\n// not every @types/node version exposes openAsBlob.\ntype OpenAsBlob = (path: string, options?: { type?: string }) => Promise<Blob>;\nconst openAsBlob = (fs as unknown as { openAsBlob?: OpenAsBlob }).openAsBlob;\n\n// Node's `Buffer<ArrayBufferLike>` and the DOM lib's `BlobPart`\n// (`ArrayBufferView<ArrayBuffer>`) don't line up under recent @types/node, even\n// though every value passed here is a valid Blob part at runtime. Cast once.\nfunction toBlobPart(data: ArrayBuffer | ArrayBufferView): BlobPart {\n return data as unknown as BlobPart;\n}\n\nfunction isReadable(x: unknown): x is Readable {\n return (\n !!x &&\n typeof (x as Readable).pipe === 'function' &&\n typeof (x as { read?: unknown }).read === 'function'\n );\n}\n\nasync function streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(\n Buffer.isBuffer(chunk)\n ? chunk\n : typeof chunk === 'string'\n ? Buffer.from(chunk)\n : Buffer.from(chunk as Uint8Array),\n );\n }\n return Buffer.concat(chunks);\n}\n\n/**\n * Normalize any {@link NodeUploadSource} into a `{ blob, filename, mimetype }`\n * the core Uploader can consume. Caller-supplied `filename` / `mimeType` always\n * win over what we infer from the path or the blob.\n */\nexport async function resolveSource(\n source: NodeUploadSource,\n opts: { filename?: string; mimeType?: string } = {},\n): Promise<ResolvedSource> {\n // 1. File path on disk.\n if (typeof source === 'string') {\n const filename = opts.filename || basename(source) || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n try {\n const blob = openAsBlob\n ? await openAsBlob(source, { type: mimetype })\n : new Blob([toBlobPart(await readFile(source))], { type: mimetype });\n return { blob, filename, mimetype };\n } catch (cause) {\n throw makeError('VALIDATION', `Could not read file at \"${source}\".`, {\n retryable: false,\n cause,\n });\n }\n }\n\n // 2. Already a Blob / File.\n if (typeof Blob !== 'undefined' && source instanceof Blob) {\n const filename = opts.filename || (source as Blob & { name?: string }).name || 'untitled';\n const mimetype = opts.mimeType || source.type || mimeFromName(filename);\n // Only re-wrap when we need to stamp a type the blob doesn't already carry.\n const blob =\n opts.mimeType && opts.mimeType !== source.type\n ? new Blob([source], { type: opts.mimeType })\n : source;\n return { blob, filename, mimetype };\n }\n\n // 3. Node Readable stream — buffer it fully; multipart needs the size up front.\n if (isReadable(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n const buf = await streamToBuffer(source);\n return { blob: new Blob([toBlobPart(buf)], { type: mimetype }), filename, mimetype };\n }\n\n // 4. Buffer / Uint8Array / ArrayBuffer (Buffer is an ArrayBuffer view).\n if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n return { blob: new Blob([toBlobPart(source)], { type: mimetype }), filename, mimetype };\n }\n\n throw makeError(\n 'VALIDATION',\n 'Unsupported upload source. Pass a file path, Buffer, Uint8Array, ArrayBuffer, Blob, or Readable stream.',\n { retryable: false },\n );\n}\n","import { basename } from 'node:path';\nimport { Uploader } from '../uploader.js';\nimport { makeError } from '../errors.js';\nimport { NODE_SDK_VERSION_HEADER } from '../version.js';\nimport { resolveSource, type NodeUploadSource } from './source.js';\nimport type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickedFile,\n PickResponse,\n UploadError,\n} from '../types.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this — we\n * ship a new SDK version if the URL ever changes. (Same constant as the browser\n * client; kept independent so the Node entry doesn't pull in client.ts.)\n */\nconst API_BASE = 'https://api.unionstack.link/v1';\n\n// File-level fan-out for uploadMany. Each file still runs its own part-level\n// concurrency (opts.concurrency), so this caps how many files upload at once —\n// keeps a 10k-file batch from opening 10k sockets / file handles simultaneously.\nconst DEFAULT_FILE_CONCURRENCY = 5;\n\n/**\n * Server-side UnionStack client for Node.js. Uploads files straight to your\n * UnionStack bucket from a backend — no browser, no picker, no DOM.\n *\n * Use an API key whose allowed origins include `*` (server-to-server requests\n * carry no `Origin` header). Create the key and add `*` from your dashboard.\n *\n * ```ts\n * import { UnionStack } from '@masters-union/union-stack/node';\n *\n * const client = UnionStack.init({ apiKey: process.env.UNIONSTACK_API_KEY! });\n * const file = await client.upload('./invoice.pdf');\n * console.log(file.url);\n * ```\n */\nexport class UnionStackNodeClient {\n private uploader: Uploader;\n private cfg: ResolvedClientConfig;\n\n constructor(cfg: ClientConfig) {\n // A server SDK can throw on misconfiguration — unlike the browser client,\n // there's no render path to crash.\n if (!cfg?.apiKey) {\n throw makeError('CONFIG', 'apiKey is required. Pass { apiKey: \"unionstack_live_…\" }.', {\n retryable: false,\n });\n }\n this.cfg = {\n ...cfg,\n apiBase: API_BASE,\n // No picker on the server — never prefetch the picker config.\n skipConfigPrefetch: true,\n // Tag the traffic as server-to-server (\"node/…\") so cdn-be can tell it\n // apart from browser SDK calls (\"js/…\").\n sdkHeader: NODE_SDK_VERSION_HEADER,\n };\n this.uploader = new Uploader(this.cfg);\n }\n\n /**\n * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a\n * Blob/File, or a Readable stream. Returns the stored file (with its public\n * `url`). Rejects with an {@link UploadError}.\n */\n async upload(source: NodeUploadSource, opts: UploadOptions = {}): Promise<UploadedFile> {\n const resolved = await resolveSource(source, { filename: opts.filename, mimeType: opts.mimeType });\n return this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n }\n\n /**\n * Upload many files. Runs up to {@link DEFAULT_FILE_CONCURRENCY} files at once\n * and never rejects on a single file's failure — successes and failures come\n * back separately so a partial failure doesn't drop the whole batch.\n */\n async uploadMany(sources: NodeUploadSource[], opts: BatchUploadOptions = {}): Promise<PickResponse> {\n if (!Array.isArray(sources) || sources.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of sources.', {\n retryable: false,\n });\n opts.onError?.(err);\n throw err;\n }\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n let cursor = 0;\n const worker = async (): Promise<void> => {\n while (true) {\n const i = cursor++;\n if (i >= sources.length) return;\n\n let resolved;\n try {\n resolved = await resolveSource(sources[i], {\n filename: opts.filename,\n mimeType: opts.mimeType,\n });\n } catch (err) {\n filesFailed.push({ file: describeUnresolved(sources[i], i, opts), error: err as UploadError });\n continue;\n }\n\n const picked: PickedFile = {\n uploadId: String(i),\n filename: resolved.filename,\n mimetype: resolved.mimetype,\n size: resolved.blob.size,\n source: 'local',\n };\n try {\n const uploaded = await this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n uploaded.uploadId = picked.uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked, error: err as UploadError });\n }\n }\n };\n\n const pool = Math.max(1, Math.min(DEFAULT_FILE_CONCURRENCY, sources.length));\n await Promise.all(Array.from({ length: pool }, worker));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n\n /** Read-only view of the resolved config. */\n get config(): Readonly<ResolvedClientConfig> {\n return this.cfg;\n }\n}\n\n/** Best-effort descriptor for a file that failed before we could read it. */\nfunction describeUnresolved(\n source: NodeUploadSource,\n index: number,\n opts: BatchUploadOptions,\n): PickedFile {\n return {\n uploadId: String(index),\n filename: opts.filename || (typeof source === 'string' ? basename(source) : 'untitled'),\n mimetype: opts.mimeType || 'application/octet-stream',\n size: 0,\n source: 'local',\n };\n}\n\nexport const UnionStack = {\n /** Create a server-side client. `cfg.apiKey` is required. */\n init(cfg: ClientConfig): UnionStackNodeClient {\n return new UnionStackNodeClient(cfg);\n },\n};\n\nexport type { NodeUploadSource } from './source.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from '../types.js';\n"]}
1
+ {"version":3,"sources":["../src/node/source.ts","../src/node/index.ts"],"names":["openAsBlob","basename"],"mappings":";;;;;;AAkCA,IAAM,WAAA,GAAsC;AAAA;AAAA,EAE1C,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,WAAA;AAAA,EAC9D,IAAA,EAAM,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,eAAA;AAAA,EAAiB,GAAA,EAAK,WAAA;AAAA,EACnE,GAAA,EAAK,cAAA;AAAA,EAAgB,IAAA,EAAM,YAAA;AAAA,EAAc,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,YAAA;AAAA;AAAA,EAElE,GAAA,EAAK,iBAAA;AAAA,EAAmB,GAAA,EAAK,YAAA;AAAA,EAAc,GAAA,EAAK,UAAA;AAAA,EAAY,EAAA,EAAI,eAAA;AAAA,EAChE,IAAA,EAAM,kBAAA;AAAA,EAAoB,GAAA,EAAK,iBAAA;AAAA,EAAmB,IAAA,EAAM,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA;AAAA,EAE1E,GAAA,EAAK,oBAAA;AAAA,EACL,IAAA,EAAM,yEAAA;AAAA,EACN,GAAA,EAAK,0BAAA;AAAA,EACL,IAAA,EAAM,mEAAA;AAAA,EACN,GAAA,EAAK,+BAAA;AAAA,EACL,IAAA,EAAM,2EAAA;AAAA;AAAA,EAEN,GAAA,EAAK,WAAA;AAAA,EAAa,IAAA,EAAM,YAAA;AAAA,EAAc,GAAA,EAAK,iBAAA;AAAA,EAAmB,GAAA,EAAK,kBAAA;AAAA,EACnE,GAAA,EAAK,YAAA;AAAA,EAAc,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA,EAAa,GAAA,EAAK,WAAA;AAAA;AAAA,EAE5D,GAAA,EAAK,iBAAA;AAAA,EAAmB,EAAA,EAAI,kBAAA;AAAA,EAAoB,GAAA,EAAK;AACvD,CAAA;AAEA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,MAAM,MAAM,OAAA,CAAQ,IAAI,EAAE,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AAC/C,EAAA,OAAO,WAAA,CAAY,GAAG,CAAA,IAAK,0BAAA;AAC7B;AAOA,IAAMA,WAAAA,GAA4D,EAAA,CAAA,UAAA;AAKlE,SAAS,WAAW,IAAA,EAA+C;AACjE,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,WAAW,CAAA,EAA2B;AAC7C,EAAA,OACE,CAAC,CAAC,CAAA,IACF,OAAQ,EAAe,IAAA,KAAS,UAAA,IAChC,OAAQ,CAAA,CAAyB,IAAA,KAAS,UAAA;AAE9C;AAEA,eAAe,eAAe,MAAA,EAAmC;AAC/D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GACjB,QACA,OAAO,KAAA,KAAU,QAAA,GACf,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,GACjB,MAAA,CAAO,KAAK,KAAmB;AAAA,KACvC;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAC7B;AAOA,eAAsB,aAAA,CACpB,MAAA,EACA,IAAA,GAAiD,EAAC,EACzB;AAEzB,EAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,QAAA,CAAS,MAAM,CAAA,IAAK,UAAA;AACtD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAOA,cACT,MAAMA,WAAAA,CAAW,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,GAC3C,IAAI,KAAK,CAAC,UAAA,CAAW,MAAM,QAAA,CAAS,MAAM,CAAC,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AACrE,MAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,QAAA,EAAS;AAAA,IACpC,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,SAAA,CAAU,YAAA,EAAc,CAAA,wBAAA,EAA2B,MAAM,CAAA,EAAA,CAAA,EAAM;AAAA,QACnE,SAAA,EAAW,KAAA;AAAA,QACX;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,IAAI,OAAO,IAAA,KAAS,WAAA,IAAe,MAAA,YAAkB,IAAA,EAAM;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAa,MAAA,CAAoC,IAAA,IAAQ,UAAA;AAC/E,IAAA,MAAM,WAAW,IAAA,CAAK,QAAA,IAAY,MAAA,CAAO,IAAA,IAAQ,aAAa,QAAQ,CAAA;AAEtE,IAAA,MAAM,OACJ,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,QAAA,KAAa,OAAO,IAAA,GACtC,IAAI,IAAA,CAAK,CAAC,MAAM,CAAA,EAAG,EAAE,MAAM,IAAA,CAAK,QAAA,EAAU,CAAA,GAC1C,MAAA;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,QAAA,EAAS;AAAA,EACpC;AAGA,EAAA,IAAI,UAAA,CAAW,MAAM,CAAA,EAAG;AACtB,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,UAAA;AAClC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,MAAM,GAAA,GAAM,MAAM,cAAA,CAAe,MAAM,CAAA;AACvC,IAAA,OAAO,EAAE,IAAA,EAAM,IAAI,IAAA,CAAK,CAAC,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,EAAG,UAAU,QAAA,EAAS;AAAA,EACrF;AAGA,EAAA,IAAI,MAAA,YAAkB,WAAA,IAAe,WAAA,CAAY,MAAA,CAAO,MAAM,CAAA,EAAG;AAC/D,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,UAAA;AAClC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,YAAA,CAAa,QAAQ,CAAA;AACvD,IAAA,OAAO,EAAE,IAAA,EAAM,IAAI,IAAA,CAAK,CAAC,UAAA,CAAW,MAAM,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA,EAAG,UAAU,QAAA,EAAS;AAAA,EACxF;AAEA,EAAA,MAAM,SAAA;AAAA,IACJ,YAAA;AAAA,IACA,yGAAA;AAAA,IACA,EAAE,WAAW,KAAA;AAAM,GACrB;AACF;;;ACtIA,IAAM,QAAA,GAAW,gCAAA;AAKjB,IAAM,wBAAA,GAA2B,CAAA;AAiB1B,IAAM,uBAAN,MAA2B;AAAA,EAIhC,YAAY,GAAA,EAAmB;AAG7B,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,SAAA,CAAU,UAAU,gEAAA,EAA6D;AAAA,QACrF,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AACA,IAAA,IAAA,CAAK,GAAA,GAAM;AAAA,MACT,GAAG,GAAA;AAAA,MACH,OAAA,EAAS,QAAA;AAAA;AAAA,MAET,kBAAA,EAAoB,IAAA;AAAA;AAAA;AAAA,MAGpB,SAAA,EAAW;AAAA,KACb;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAA,CAAO,MAAA,EAA0B,IAAA,GAAsB,EAAC,EAA0B;AACtF,IAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,MAAA,EAAQ,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,CAAA;AACjG,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,QAAA,CAAS,IAAA,EAAM;AAAA,MACzC,GAAG,IAAA;AAAA,MACH,UAAU,QAAA,CAAS,QAAA;AAAA,MACnB,UAAU,QAAA,CAAS;AAAA,KACpB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAA,CAAW,OAAA,EAA6B,IAAA,GAA2B,EAAC,EAA0B;AAClG,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnD,MAAA,MAAM,GAAA,GAAM,SAAA,CAAU,YAAA,EAAc,mDAAA,EAAqD;AAAA,QACvF,SAAA,EAAW;AAAA,OACZ,CAAA;AACD,MAAA,IAAA,CAAK,UAAU,GAAG,CAAA;AAClB,MAAA,MAAM,GAAA;AAAA,IACR;AAEA,IAAA,MAAM,gBAAgC,EAAC;AACvC,IAAA,MAAM,cAA+D,EAAC;AAEtE,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,MAAM,SAAS,YAA2B;AACxC,MAAA,OAAO,IAAA,EAAM;AACX,QAAA,MAAM,CAAA,GAAI,MAAA,EAAA;AACV,QAAA,IAAI,CAAA,IAAK,QAAQ,MAAA,EAAQ;AAEzB,QAAA,IAAI,QAAA;AACJ,QAAA,IAAI;AACF,UAAA,QAAA,GAAW,MAAM,aAAA,CAAc,OAAA,CAAQ,CAAC,CAAA,EAAG;AAAA,YACzC,UAAU,IAAA,CAAK,QAAA;AAAA,YACf,UAAU,IAAA,CAAK;AAAA,WAChB,CAAA;AAAA,QACH,SAAS,GAAA,EAAK;AACZ,UAAA,WAAA,CAAY,IAAA,CAAK,EAAE,IAAA,EAAM,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA,EAAG,KAAA,EAAO,GAAA,EAAoB,CAAA;AAC7F,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,MAAA,GAAqB;AAAA,UACzB,QAAA,EAAU,OAAO,CAAC,CAAA;AAAA,UAClB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,IAAA,EAAM,SAAS,IAAA,CAAK,IAAA;AAAA,UACpB,MAAA,EAAQ;AAAA,SACV;AACA,QAAA,IAAI;AACF,UAAA,MAAM,WAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,SAAS,IAAA,EAAM;AAAA,YACzD,GAAG,IAAA;AAAA,YACH,UAAU,QAAA,CAAS,QAAA;AAAA,YACnB,UAAU,QAAA,CAAS;AAAA,WACpB,CAAA;AACD,UAAA,QAAA,CAAS,WAAW,MAAA,CAAO,QAAA;AAC3B,UAAA,aAAA,CAAc,KAAK,QAAQ,CAAA;AAAA,QAC7B,SAAS,GAAA,EAAK;AACZ,UAAA,WAAA,CAAY,KAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,KAAoB,CAAA;AAAA,QAC9D;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,wBAAA,EAA0B,OAAA,CAAQ,MAAM,CAAC,CAAA;AAC3E,IAAA,MAAM,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAK,EAAG,MAAM,CAAC,CAAA;AAEtD,IAAA,MAAM,MAAA,GAAuB,EAAE,aAAA,EAAe,WAAA,EAAY;AAC1D,IAAA,IAAA,CAAK,eAAe,MAAM,CAAA;AAC1B,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,MAAA,GAAyC;AAC3C,IAAA,OAAO,IAAA,CAAK,GAAA;AAAA,EACd;AACF;AAGA,SAAS,kBAAA,CACP,MAAA,EACA,KAAA,EACA,IAAA,EACY;AACZ,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,OAAO,KAAK,CAAA;AAAA,IACtB,QAAA,EAAU,KAAK,QAAA,KAAa,OAAO,WAAW,QAAA,GAAWC,QAAAA,CAAS,MAAM,CAAA,GAAI,UAAA,CAAA;AAAA,IAC5E,QAAA,EAAU,KAAK,QAAA,IAAY,0BAAA;AAAA,IAC3B,IAAA,EAAM,CAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACV;AACF;AAEO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,KAAK,GAAA,EAAyC;AAC5C,IAAA,OAAO,IAAI,qBAAqB,GAAG,CAAA;AAAA,EACrC;AACF","file":"node.js","sourcesContent":["import { basename, extname } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport * as fs from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { makeError } from '../errors.js';\n\n/**\n * Anything the Node client knows how to turn into an upload.\n *\n * • `string` — path to a file on disk (absolute or relative to cwd)\n * • `Buffer` / typed arr — raw bytes already in memory\n * • `ArrayBuffer` — raw bytes\n * • `Blob` / `File` — Web file objects (Node 18+ has `Blob`, 20+ has `File`)\n * • `Readable` — a Node stream (buffered in full before upload, since\n * the multipart protocol needs the total size up front)\n */\nexport type NodeUploadSource =\n | string\n | Buffer\n | Uint8Array\n | ArrayBuffer\n | Blob\n | Readable;\n\nexport interface ResolvedSource {\n /** A Web `Blob` the core Uploader can `.slice()` into multipart chunks. */\n blob: Blob;\n filename: string;\n mimetype: string;\n}\n\n// Smallest map that covers the bulk of real-world server uploads. Anything not\n// listed falls back to application/octet-stream — callers can always override\n// via `{ mimeType }`. Kept deliberately short; this is not a full mime database.\nconst EXT_TO_MIME: Record<string, string> = {\n // images\n png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',\n webp: 'image/webp', avif: 'image/avif', svg: 'image/svg+xml', bmp: 'image/bmp',\n ico: 'image/x-icon', heic: 'image/heic', tiff: 'image/tiff', tif: 'image/tiff',\n // documents\n pdf: 'application/pdf', txt: 'text/plain', csv: 'text/csv', md: 'text/markdown',\n json: 'application/json', xml: 'application/xml', html: 'text/html', htm: 'text/html',\n // office\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // media\n mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime', mkv: 'video/x-matroska',\n mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4',\n // archives\n zip: 'application/zip', gz: 'application/gzip', tar: 'application/x-tar',\n};\n\nfunction mimeFromName(name: string): string {\n const ext = extname(name).slice(1).toLowerCase();\n return EXT_TO_MIME[ext] || 'application/octet-stream';\n}\n\n// `fs.openAsBlob` (Node 19.8+/20+) hands back a Blob backed by the file on disk,\n// so slicing it into parts streams lazily instead of loading the whole file into\n// memory. Typed locally — the global DOM `Blob` is what the Uploader wants, and\n// not every @types/node version exposes openAsBlob.\ntype OpenAsBlob = (path: string, options?: { type?: string }) => Promise<Blob>;\nconst openAsBlob = (fs as unknown as { openAsBlob?: OpenAsBlob }).openAsBlob;\n\n// Node's `Buffer<ArrayBufferLike>` and the DOM lib's `BlobPart`\n// (`ArrayBufferView<ArrayBuffer>`) don't line up under recent @types/node, even\n// though every value passed here is a valid Blob part at runtime. Cast once.\nfunction toBlobPart(data: ArrayBuffer | ArrayBufferView): BlobPart {\n return data as unknown as BlobPart;\n}\n\nfunction isReadable(x: unknown): x is Readable {\n return (\n !!x &&\n typeof (x as Readable).pipe === 'function' &&\n typeof (x as { read?: unknown }).read === 'function'\n );\n}\n\nasync function streamToBuffer(stream: Readable): Promise<Buffer> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(\n Buffer.isBuffer(chunk)\n ? chunk\n : typeof chunk === 'string'\n ? Buffer.from(chunk)\n : Buffer.from(chunk as Uint8Array),\n );\n }\n return Buffer.concat(chunks);\n}\n\n/**\n * Normalize any {@link NodeUploadSource} into a `{ blob, filename, mimetype }`\n * the core Uploader can consume. Caller-supplied `filename` / `mimeType` always\n * win over what we infer from the path or the blob.\n */\nexport async function resolveSource(\n source: NodeUploadSource,\n opts: { filename?: string; mimeType?: string } = {},\n): Promise<ResolvedSource> {\n // 1. File path on disk.\n if (typeof source === 'string') {\n const filename = opts.filename || basename(source) || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n try {\n const blob = openAsBlob\n ? await openAsBlob(source, { type: mimetype })\n : new Blob([toBlobPart(await readFile(source))], { type: mimetype });\n return { blob, filename, mimetype };\n } catch (cause) {\n throw makeError('VALIDATION', `Could not read file at \"${source}\".`, {\n retryable: false,\n cause,\n });\n }\n }\n\n // 2. Already a Blob / File.\n if (typeof Blob !== 'undefined' && source instanceof Blob) {\n const filename = opts.filename || (source as Blob & { name?: string }).name || 'untitled';\n const mimetype = opts.mimeType || source.type || mimeFromName(filename);\n // Only re-wrap when we need to stamp a type the blob doesn't already carry.\n const blob =\n opts.mimeType && opts.mimeType !== source.type\n ? new Blob([source], { type: opts.mimeType })\n : source;\n return { blob, filename, mimetype };\n }\n\n // 3. Node Readable stream — buffer it fully; multipart needs the size up front.\n if (isReadable(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n const buf = await streamToBuffer(source);\n return { blob: new Blob([toBlobPart(buf)], { type: mimetype }), filename, mimetype };\n }\n\n // 4. Buffer / Uint8Array / ArrayBuffer (Buffer is an ArrayBuffer view).\n if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {\n const filename = opts.filename || 'untitled';\n const mimetype = opts.mimeType || mimeFromName(filename);\n return { blob: new Blob([toBlobPart(source)], { type: mimetype }), filename, mimetype };\n }\n\n throw makeError(\n 'VALIDATION',\n 'Unsupported upload source. Pass a file path, Buffer, Uint8Array, ArrayBuffer, Blob, or Readable stream.',\n { retryable: false },\n );\n}\n","import { basename } from 'node:path';\nimport { Uploader } from '../uploader.js';\nimport { makeError } from '../errors.js';\nimport { NODE_SDK_VERSION_HEADER } from '../version.js';\nimport { resolveSource, type NodeUploadSource } from './source.js';\nimport type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickedFile,\n PickResponse,\n UploadError,\n} from '../types.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this — we\n * ship a new SDK version if the URL ever changes. (Same constant as the browser\n * client; kept independent so the Node entry doesn't pull in client.ts.)\n */\nconst API_BASE = 'https://api.unionstack.link/v1';\n\n// File-level fan-out for uploadMany. Each file still runs its own part-level\n// concurrency (opts.concurrency), so this caps how many files upload at once —\n// keeps a 10k-file batch from opening 10k sockets / file handles simultaneously.\nconst DEFAULT_FILE_CONCURRENCY = 5;\n\n/**\n * Server-side UnionStack client for Node.js. Uploads files straight to your\n * UnionStack bucket from a backend — no browser, no picker, no DOM.\n *\n * Use an API key whose allowed origins include `*` (server-to-server requests\n * carry no `Origin` header). Create the key and add `*` from your dashboard.\n *\n * ```ts\n * import { UnionStack } from '@masters-union/union-stack/node';\n *\n * const client = UnionStack.init({ apiKey: process.env.UNIONSTACK_API_KEY! });\n * const file = await client.upload('./invoice.pdf');\n * console.log(file.url);\n * ```\n */\nexport class UnionStackNodeClient {\n private uploader: Uploader;\n private cfg: ResolvedClientConfig;\n\n constructor(cfg: ClientConfig) {\n // A server SDK can throw on misconfiguration — unlike the browser client,\n // there's no render path to crash.\n if (!cfg?.apiKey) {\n throw makeError('CONFIG', 'apiKey is required. Pass { apiKey: \"unionstack_live_…\" }.', {\n retryable: false,\n });\n }\n this.cfg = {\n ...cfg,\n apiBase: API_BASE,\n // No picker on the server — never prefetch the picker config.\n skipConfigPrefetch: true,\n // Tag the traffic as server-to-server (\"node/…\") so cdn-be can tell it\n // apart from browser SDK calls (\"js/…\").\n sdkHeader: NODE_SDK_VERSION_HEADER,\n };\n this.uploader = new Uploader(this.cfg);\n }\n\n /**\n * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a\n * Blob/File, or a Readable stream. Returns the stored file (with its public\n * `url`). Rejects with an {@link UploadError}.\n */\n async upload(source: NodeUploadSource, opts: UploadOptions = {}): Promise<UploadedFile> {\n const resolved = await resolveSource(source, { filename: opts.filename, mimeType: opts.mimeType });\n return this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n }\n\n /**\n * Upload many files. Runs up to {@link DEFAULT_FILE_CONCURRENCY} files at once\n * and never rejects on a single file's failure — successes and failures come\n * back separately so a partial failure doesn't drop the whole batch.\n */\n async uploadMany(sources: NodeUploadSource[], opts: BatchUploadOptions = {}): Promise<PickResponse> {\n if (!Array.isArray(sources) || sources.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of sources.', {\n retryable: false,\n });\n opts.onError?.(err);\n throw err;\n }\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n let cursor = 0;\n const worker = async (): Promise<void> => {\n while (true) {\n const i = cursor++;\n if (i >= sources.length) return;\n\n let resolved;\n try {\n resolved = await resolveSource(sources[i], {\n filename: opts.filename,\n mimeType: opts.mimeType,\n });\n } catch (err) {\n filesFailed.push({ file: describeUnresolved(sources[i], i, opts), error: err as UploadError });\n continue;\n }\n\n const picked: PickedFile = {\n uploadId: String(i),\n filename: resolved.filename,\n mimetype: resolved.mimetype,\n size: resolved.blob.size,\n source: 'local',\n };\n try {\n const uploaded = await this.uploader.upload(resolved.blob, {\n ...opts,\n filename: resolved.filename,\n mimeType: resolved.mimetype,\n });\n uploaded.uploadId = picked.uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked, error: err as UploadError });\n }\n }\n };\n\n const pool = Math.max(1, Math.min(DEFAULT_FILE_CONCURRENCY, sources.length));\n await Promise.all(Array.from({ length: pool }, worker));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n\n /** Read-only view of the resolved config. */\n get config(): Readonly<ResolvedClientConfig> {\n return this.cfg;\n }\n}\n\n/** Best-effort descriptor for a file that failed before we could read it. */\nfunction describeUnresolved(\n source: NodeUploadSource,\n index: number,\n opts: BatchUploadOptions,\n): PickedFile {\n return {\n uploadId: String(index),\n filename: opts.filename || (typeof source === 'string' ? basename(source) : 'untitled'),\n mimetype: opts.mimeType || 'application/octet-stream',\n size: 0,\n source: 'local',\n };\n}\n\nexport const UnionStack = {\n /** Create a server-side client. `cfg.apiKey` is required. */\n init(cfg: ClientConfig): UnionStackNodeClient {\n return new UnionStackNodeClient(cfg);\n },\n};\n\nexport type { NodeUploadSource } from './source.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from '../types.js';\n"]}
package/dist/picker.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var chunkGTE65IAM_cjs = require('./chunk-GTE65IAM.cjs');
4
+
3
5
  // src/picker/styles.ts
4
6
  var STYLE_ID = "unionstack-picker-styles";
5
7
  var FONT_ID = "unionstack-picker-fonts";
@@ -1699,6 +1701,8 @@ var Picker = class {
1699
1701
  const notices = [];
1700
1702
  if (rejectedType > 0) notices.push(`${rejectedType} file${rejectedType > 1 ? "s" : ""} skipped \u2014 unsupported type`);
1701
1703
  if (overCap > 0) notices.push(`${overCap} file${overCap > 1 ? "s" : ""} skipped \u2014 max ${cap} allowed`);
1704
+ const emptyCount = chosen.filter((f) => f.size === 0).length;
1705
+ if (emptyCount > 0) notices.push(`${emptyCount} empty file${emptyCount > 1 ? "s" : ""} skipped \u2014 open it in iCloud/Drive to download first`);
1702
1706
  if (notices.length) this.flashNotice(notices.join(" \xB7 "));
1703
1707
  for (const file of chosen) {
1704
1708
  if (file.size === 0) {
@@ -1709,7 +1713,8 @@ var Picker = class {
1709
1713
  edited: false,
1710
1714
  state: "failed",
1711
1715
  progress: 0,
1712
- error: "File is empty (0 bytes) \u2014 if it lives in iCloud/Drive, open it once to download it, then re-add"
1716
+ error: chunkGTE65IAM_cjs.EMPTY_FILE_MESSAGE,
1717
+ errorCode: "EMPTY_FILE"
1713
1718
  };
1714
1719
  this.items.push(item2);
1715
1720
  this.renderItem(item2);
@@ -2106,8 +2111,10 @@ var Picker = class {
2106
2111
  const item = itemByUploadId.get(p.uploadId);
2107
2112
  if (item) {
2108
2113
  item.error = err.message;
2114
+ item.errorCode = err.code;
2109
2115
  this.setItemState(item, "failed");
2110
2116
  }
2117
+ if (err.code === "EMPTY_FILE") this.flashNotice(chunkGTE65IAM_cjs.EMPTY_FILE_MESSAGE);
2111
2118
  this.opts.onFileUploadFailed?.(p, err);
2112
2119
  },
2113
2120
  onUploadDone: (r) => {
@@ -2142,7 +2149,7 @@ var Picker = class {
2142
2149
  source: "local"
2143
2150
  },
2144
2151
  error: {
2145
- code: "VALIDATION",
2152
+ code: i.errorCode || "VALIDATION",
2146
2153
  message: i.error || "failed",
2147
2154
  retryable: false
2148
2155
  }