@masters-union/union-stack 0.3.17 → 0.4.1

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.
@@ -1,8 +1,8 @@
1
- import { Uploader } from './chunk-RYS4MXXL.js';
1
+ import { Uploader } from './chunk-JAO2DEL3.js';
2
2
  import { makeError } from './chunk-G2H5WZDV.js';
3
3
 
4
4
  // src/client.ts
5
- var API_BASE = "https://api.unionstack.link/v1";
5
+ var API_BASE = "https://api.unionstack.in/v1";
6
6
  var PRELOADER_STYLE_ID = "unionstack-preloader-styles";
7
7
  function showPickerPreloader() {
8
8
  if (typeof document === "undefined") return () => {
@@ -137,5 +137,5 @@ var UnionStackClient = class {
137
137
  };
138
138
 
139
139
  export { UnionStackClient };
140
- //# sourceMappingURL=chunk-QQFNG3ZF.js.map
141
- //# sourceMappingURL=chunk-QQFNG3ZF.js.map
140
+ //# sourceMappingURL=chunk-3BQ6RNXE.js.map
141
+ //# sourceMappingURL=chunk-3BQ6RNXE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":["cfg"],"mappings":"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","file":"chunk-3BQ6RNXE.js","sourcesContent":["import type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickResponse,\n PickedFile,\n PickerConfig,\n UploadError,\n} from './types.js';\nimport { Uploader } from './uploader.js';\nimport { makeError } from './errors.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this —\n * we ship a new SDK version if the URL ever changes.\n *\n * For local development against a staging backend, change this constant in\n * src/ and rebuild — no consumer-facing override exists by design.\n */\nconst API_BASE = 'https://api.unionstack.in/v1';\n\n// Forward-declared minimal handle so client.ts doesn't pull in the picker bundle.\nexport interface PickerHandleLike {\n open(): Promise<PickResponse>;\n close(): void;\n cancel(): void;\n}\n\nconst PRELOADER_STYLE_ID = 'unionstack-preloader-styles';\n\n// Instant spinner shown between picker.open() and the modal actually mounting\n// (covers the lazy chunk download + the server config fetch). Self-contained —\n// must not depend on the picker bundle, which is what we're waiting for. The\n// backdrop matches the picker's exactly so the handoff is seamless.\nfunction showPickerPreloader(): () => void {\n if (typeof document === 'undefined') return () => {};\n if (!document.getElementById(PRELOADER_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = PRELOADER_STYLE_ID;\n style.textContent =\n '@keyframes us-preload-spin{to{transform:rotate(360deg)}}' +\n '@keyframes us-preload-fade{from{opacity:0}to{opacity:1}}';\n document.head.appendChild(style);\n }\n const backdrop = document.createElement('div');\n backdrop.setAttribute('role', 'status');\n backdrop.setAttribute('aria-label', 'Loading file picker');\n backdrop.style.cssText =\n 'position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;' +\n 'background:rgba(2,6,23,0.4);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);' +\n 'animation:us-preload-fade 140ms ease-out;';\n const spinner = document.createElement('div');\n spinner.style.cssText =\n 'width:36px;height:36px;border-radius:50%;' +\n 'border:3px solid rgba(220,225,251,0.25);border-top-color:#c0c1ff;' +\n 'animation:us-preload-spin 0.8s linear infinite;';\n backdrop.appendChild(spinner);\n document.body.appendChild(backdrop);\n let removed = false;\n return () => {\n if (removed) return;\n removed = true;\n backdrop.remove();\n };\n}\n\nexport class UnionStackClient {\n private uploader: Uploader;\n private resolvedCfg: ResolvedClientConfig;\n /**\n * Promise that resolves to the server-managed picker config. Pre-fetched on\n * construction (unless `skipConfigPrefetch: true`) so the picker opens\n * without a network hit. Fails silently — picker falls back to defaults.\n */\n pickerConfigPromise: Promise<PickerConfig | null>;\n\n constructor(cfg: ClientConfig) {\n // Don't throw on a missing apiKey: the React provider constructs the\n // client during render, and a render-time throw crashes the host app.\n // Log instead, and let every operation reject with a CONFIG error.\n if (!cfg.apiKey) {\n console.error(\n '[UnionStack] apiKey is not set. Uploads and the picker are disabled until a valid apiKey is provided.',\n );\n }\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = (!cfg.apiKey || this.resolvedCfg.skipConfigPrefetch)\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig()\n .then(cfg => {\n if (cfg?.sdkWarning) console.warn(`[UnionStack] ${cfg.sdkWarning}`);\n return cfg;\n })\n .catch(() => null);\n }\n\n private missingKeyError(): UploadError | null {\n if (this.resolvedCfg.apiKey) return null;\n return makeError('CONFIG', 'apiKey is required.', { retryable: false });\n }\n\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const keyErr = this.missingKeyError();\n if (keyErr) return Promise.reject(keyErr);\n return this.uploader.upload(file, opts);\n }\n\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\n const keyErr = this.missingKeyError();\n if (keyErr) {\n opts.onError?.(keyErr);\n throw keyErr;\n }\n if (!Array.isArray(files) || files.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of files.', { retryable: false });\n opts.onError?.(err);\n throw err;\n }\n\n const picked: PickedFile[] = files.map(f =>\n this.uploader.describe(f, { filename: opts.filename, mimeType: opts.mimeType })\n );\n opts.onUploadStarted?.(picked);\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n await Promise.all(files.map(async (f, i) => {\n try {\n const uploaded = await this.uploader.upload(f, opts);\n // Sync the uploadId so callers can correlate picked → uploaded.\n uploaded.uploadId = picked[i].uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked[i], error: err as UploadError });\n }\n }));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n \n picker(opts: import('./picker/types.js').PickerOptions = {}): PickerHandleLike {\n let real: PickerHandleLike | null = null;\n let opened = false;\n let pendingResolve!: (r: PickResponse) => void;\n let pendingReject!: (e: UploadError) => void;\n const donePromise = new Promise<PickResponse>((res, rej) => {\n pendingResolve = res; pendingReject = rej;\n });\n\n return {\n open: async () => {\n if (opened) return donePromise;\n const keyErr = this.missingKeyError();\n if (keyErr) {\n pendingReject(keyErr);\n throw keyErr;\n }\n opened = true;\n const hidePreloader = showPickerPreloader();\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, {\n ...opts,\n // Picker fires onOpen right after the modal mounts — that's the\n // moment the preloader hands off to the real UI.\n onOpen: () => { hidePreloader(); opts.onOpen?.(); },\n });\n const result = await real.open();\n hidePreloader();\n pendingResolve(result);\n return result;\n } catch (err) {\n hidePreloader();\n const e = (err as UploadError)?.code\n ? (err as UploadError)\n : makeError('CONFIG', 'Failed to load picker.', { retryable: false, cause: err });\n pendingReject(e);\n throw e;\n }\n },\n close: () => { real?.close(); },\n cancel: () => { real?.cancel(); },\n };\n }\n\n /** Read-only accessor used by the React/picker packages. */\n get config(): Readonly<ResolvedClientConfig> { return this.resolvedCfg; }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { makeError, EMPTY_FILE_MESSAGE, fromApiResponse } from './chunk-G2H5WZDV.js';
2
2
 
3
3
  // src/version.ts
4
- var SDK_VERSION = "0.3.17" ;
4
+ var SDK_VERSION = "0.4.1" ;
5
5
  var SDK_VERSION_HEADER = `js/${SDK_VERSION}`;
6
6
  var NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;
7
7
 
@@ -224,5 +224,5 @@ function withSessionId(err, sessionId) {
224
224
  }
225
225
 
226
226
  export { NODE_SDK_VERSION_HEADER, Uploader };
227
- //# sourceMappingURL=chunk-RYS4MXXL.js.map
228
- //# sourceMappingURL=chunk-RYS4MXXL.js.map
227
+ //# sourceMappingURL=chunk-JAO2DEL3.js.map
228
+ //# sourceMappingURL=chunk-JAO2DEL3.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/uploader.ts"],"names":[],"mappings":";;;AAIO,IAAM,WAAA,GAC2B,QAAA,CAAkB;AAGnD,IAAM,kBAAA,GAAqB,MAAM,WAAW,CAAA,CAAA;AAG5C,IAAM,uBAAA,GAA0B,QAAQ,WAAW,CAAA;;;AC6B1D,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,4BAAA,GAA+B,CAAA;AAErC,IAAM,UAAA,GAAa,CAAC,GAAA,EAAK,IAAA,EAAM,IAAI,CAAA;AAE5B,IAAM,WAAN,MAAe;AAAA,EACpB,YAAoB,GAAA,EAA2B;AAA3B,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAAA,EAA4B;AAAA;AAAA,EAGhD,QAAA,CAAS,IAAA,EAAmB,IAAA,GAAiD,EAAC,EAAe;AAC3F,IAAA,MAAM,MAAA,GAAS,OAAO,IAAA,KAAS,WAAA,IAAe,IAAA,YAAgB,IAAA;AAC9D,IAAA,MAAM,QAAA,GACJ,IAAA,CAAK,QAAA,KACJ,MAAA,GAAU,KAAc,IAAA,GAAO,UAAA,CAAA;AAClC,IAAA,MAAM,QAAA,GACJ,IAAA,CAAK,QAAA,IAAa,IAAA,CAAc,IAAA,IAAQ,0BAAA;AAC1C,IAAA,OAAO;AAAA,MACL,UAAU,cAAA,EAAe;AAAA,MACzB,QAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAAA,EAEA,MAAM,MAAA,CAAO,IAAA,EAAmB,IAAA,GAAsB,EAAC,EAA0B;AAC/E,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,CAAA;AACvF,IAAA,IAAA,CAAK,sBAAsB,MAAM,CAAA;AAMjC,IAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,MAAA,MAAM,MAAM,SAAA,CAAU,YAAA,EAAc,oBAAoB,EAAE,SAAA,EAAW,OAAO,CAAA;AAC5E,MAAA,IAAA,CAAK,kBAAA,GAAqB,QAAQ,GAAG,CAAA;AACrC,MAAA,MAAM,GAAA;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,UAAA,CAAW,QAAQ,IAAI,CAAA;AAC/C,MAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,eAAe,IAAA,EAAM,IAAA,EAAM,QAAQ,IAAI,CAAA;AAChE,MAAA,MAAM,YAAY,MAAM,IAAA,CAAK,eAAe,IAAA,CAAK,SAAA,EAAW,OAAO,IAAI,CAAA;AAEvE,MAAA,MAAM,QAAA,GAAyB;AAAA,QAC7B,GAAG,MAAA;AAAA,QACH,QAAQ,SAAA,CAAU,MAAA;AAAA,QAClB,QAAQ,SAAA,CAAU,MAAA;AAAA,QAClB,KAAK,SAAA,CAAU,GAAA;AAAA,QACf,MAAM,SAAA,CAAU,IAAA;AAAA,QAChB,UAAU,SAAA,CAAU,QAAA;AAAA,QACpB,UAAU,SAAA,CAAU,QAAA;AAAA,QACpB,KAAK,SAAA,CAAU,GAAA;AAAA,QACf,WAAW,SAAA,CAAU,SAAA;AAAA,QACrB,MAAA,EAAQ,QAAA;AAAA,QACR,MAAM,SAAA,CAAU,IAAA;AAAA,QAChB,UAAU,SAAA,CAAU;AAAA,OACtB;AACA,MAAA,IAAA,CAAK,uBAAuB,QAAQ,CAAA;AACpC,MAAA,OAAO,QAAA;AAAA,IACT,SAAS,MAAA,EAAQ;AACf,MAAA,MAAM,GAAA,GAAM,eAAe,MAAM,CAAA;AACjC,MAAA,IAAA,CAAK,kBAAA,GAAqB,QAAQ,GAAG,CAAA;AAErC,MAAA,IAAK,QAAmC,SAAA,EAAW;AACjD,QAAA,IAAA,CAAK,aAAA,CAAe,MAAA,CAAiC,SAAS,CAAA,CAAE,MAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAChF;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,MAAM,SAAA,EAAkC;AAC5C,IAAA,MAAM,KAAK,GAAA,CAAI,MAAA,EAAQ,uBAAA,EAAyB,EAAE,WAAW,CAAA;AAAA,EAC/D;AAAA;AAAA,EAGA,MAAM,iBAAA,GAA2C;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,CAAkB,KAAA,EAAO,uBAAuB,CAAA;AAAA,EAC9D;AAAA,EAEA,MAAc,UAAA,CAAW,MAAA,EAAoB,IAAA,EAA4C;AACvF,IAAA,OAAO,IAAA,CAAK,GAAA,CAAkB,MAAA,EAAQ,sBAAA,EAAwB;AAAA,MAC5D,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,UAAU,IAAA,CAAK;AAAA,KACjB,EAAG,KAAK,MAAM,CAAA;AAAA,EAChB;AAAA,EAEA,MAAc,cAAA,CACZ,IAAA,EACA,IAAA,EACA,QACA,IAAA,EACuB;AACvB,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,MAAM,cAAc,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,eAAe,mBAAmB,CAAA;AACvE,IAAA,MAAM,UAAA,GAAa,KAAK,iBAAA,IAAqB,4BAAA;AAG7C,IAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,UAAA,EAAY,CAAA,CAAE,GAAG,CAAU,CAAC,CAAA;AAEhF,IAAA,MAAM,OAAA,GAAwB,IAAI,KAAA,CAAM,UAAU,CAAA;AAClD,IAAA,MAAM,gBAA0B,IAAI,KAAA,CAAM,UAAU,CAAA,CAAE,KAAK,CAAC,CAAA;AAC5D,IAAA,IAAI,MAAA,GAAS,CAAA;AAEb,IAAA,MAAM,aAAa,IAAA,CAAK,IAAA;AAExB,IAAA,MAAM,iBAAiB,MAAM;AAC3B,MAAA,MAAM,MAAA,GAAS,cAAc,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,GAAG,CAAC,CAAA;AACtD,MAAA,MAAM,YAAA,GAAe,UAAA,GAAa,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,KAAA,CAAO,MAAA,GAAS,UAAA,GAAc,GAAG,CAAC,CAAA,GAAI,GAAA;AAC/F,MAAA,MAAM,EAAA,GAAsB,EAAE,UAAA,EAAY,MAAA,EAAQ,YAAA,EAAa;AAC/D,MAAA,IAAA,CAAK,oBAAA,GAAuB,QAAQ,EAAE,CAAA;AAAA,IACxC,CAAA;AAEA,IAAA,MAAM,SAAS,YAA2B;AACxC,MAAA,OAAO,IAAA,EAAM;AACX,QAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,UAAA,MAAM,UAAU,SAAA,EAAW,2BAAA,EAA6B,EAAE,SAAA,EAAW,OAAO,CAAA;AAAA,QAC9E;AACA,QAAA,MAAM,UAAA,GAAa,MAAA,EAAA;AACnB,QAAA,IAAI,aAAa,UAAA,EAAY;AAE7B,QAAA,MAAM,KAAA,GAAA,CAAS,aAAa,CAAA,IAAK,SAAA;AACjC,QAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,SAAA,EAAW,KAAK,IAAI,CAAA;AACjD,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA;AAEnC,QAAA,IAAI,OAAA,GAAU,CAAA;AACd,QAAA,IAAI,OAAA;AACJ,QAAA,OAAO,WAAW,UAAA,EAAY;AAC5B,UAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,YAAA,MAAM,UAAU,SAAA,EAAW,2BAAA,EAA6B,EAAE,SAAA,EAAW,OAAO,CAAA;AAAA,UAC9E;AACA,UAAA,IAAI;AACF,YAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,UAAU,CAAA;AAClC,YAAA,IAAI,CAAC,GAAA,EAAK;AACR,cAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,GAAA;AAAA,gBAC3B,MAAA;AAAA,gBAAQ,2BAAA;AAAA,gBACR,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,UAAA,EAAW;AAAA,gBAAG,IAAA,CAAK;AAAA,eAClD;AACA,cAAA,GAAA,GAAM,SAAA,CAAU,GAAA;AAChB,cAAA,SAAA,CAAU,GAAA,CAAI,YAAY,GAAG,CAAA;AAAA,YAC/B;AAEA,YAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,GAAA,CAAI,QAAQ,GAAA,EAAK;AAAA,cACtC,MAAA,EAAQ,KAAA;AAAA,cACR,IAAA,EAAM,KAAA;AAAA,cACN,QAAQ,IAAA,CAAK;AAAA,aACd,CAAA,IAAK,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAE1E,YAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AAGX,cAAA,IAAI,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK,SAAA,CAAU,OAAO,UAAU,CAAA;AACzE,cAAA,MAAM,SAAA,CAAU,aAAA,EAAe,CAAA,KAAA,EAAQ,UAAU,CAAA,kBAAA,EAAqB,GAAA,CAAI,MAAM,CAAA,CAAA,CAAA,EAAK,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA;AAAA,YAC7G;AACA,YAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACnC,YAAA,IAAI,CAAC,IAAA,EAAM;AACT,cAAA,MAAM,SAAA,CAAU,aAAA,EAAe,CAAA,KAAA,EAAQ,UAAU,CAAA,4BAAA,CAA8B,CAAA;AAAA,YACjF;AAEA,YAAA,OAAA,CAAQ,UAAA,GAAa,CAAC,CAAA,GAAI,EAAE,YAAY,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAK;AAC/D,YAAA,aAAA,CAAc,UAAA,GAAa,CAAC,CAAA,GAAI,KAAA,CAAM,IAAA;AACtC,YAAA,cAAA,EAAe;AACf,YAAA;AAAA,UACF,SAAS,GAAA,EAAK;AACZ,YAAA,OAAA,GAAU,GAAA;AACV,YAAA,OAAA,EAAA;AACA,YAAA,IAAI,UAAU,UAAA,EAAY;AAC1B,YAAA,MAAM,KAAA,CAAM,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,OAAA,GAAU,GAAG,UAAA,CAAW,MAAA,GAAS,CAAC,CAAC,CAAC,CAAA;AAAA,UACtE;AAAA,QACF;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,GAAa,CAAC,CAAA,EAAG;AAC5B,UAAA,MAAM,aAAA;AAAA,YACJ,cAAA,CAAe,WAAW,SAAA,CAAU,aAAA,EAAe,QAAQ,UAAU,CAAA,cAAA,EAAiB,UAAU,CAAA,SAAA,CAAW,CAAC,CAAA;AAAA,YAC5G,IAAA,CAAK;AAAA,WACP;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,UAAU,CAAA,EAAE,EAAG,MAAM,CAAA;AAChF,IAAA,MAAM,OAAA,CAAQ,IAAI,OAAO,CAAA;AACzB,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEA,MAAc,cAAA,CACZ,SAAA,EACA,KAAA,EACA,IAAA,EAC2B;AAC3B,IAAA,OAAO,IAAA,CAAK,GAAA,CAAsB,MAAA,EAAQ,0BAAA,EAA4B;AAAA,MACpE,SAAA;AAAA,MACA,KAAA,EAAO,KAAA,CAAM,GAAA,CAAI,CAAA,CAAA,MAAM,EAAE,UAAA,EAAY,CAAA,CAAE,UAAA,EAAY,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK,CAAE;AAAA,KACpE,EAAG,KAAK,MAAM,CAAA;AAAA,EAChB;AAAA,EAEA,MAAc,cAAc,SAAA,EAAkC;AAC5D,IAAA,IAAI;AAAE,MAAA,MAAM,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAe;AAAA,EAC5D;AAAA,EAEA,MAAc,GAAA,CACZ,MAAA,EACA,IAAA,EACA,MACA,MAAA,EACY;AACZ,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS,KAAA;AACpC,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,OAAO,GAAG,IAAI,CAAA,CAAA;AACtC,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,UAAU,GAAA,EAAK;AAAA,QACzB,MAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,UACxC,cAAA,EAAgB,kBAAA;AAAA,UAChB,kBAAA,EAAoB,IAAA,CAAK,GAAA,CAAI,SAAA,IAAa;AAAA,SAC5C;AAAA,QACA,MAAM,IAAA,KAAS,KAAA,CAAA,GAAY,KAAA,CAAA,GAAY,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,QAC1D;AAAA,OACD,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,IAAK,KAAA,EAAiB,SAAS,YAAA,EAAc;AAC3C,QAAA,MAAM,UAAU,SAAA,EAAW,kBAAA,EAAoB,EAAE,SAAA,EAAW,KAAA,EAAO,OAAO,CAAA;AAAA,MAC5E;AACA,MAAA,MAAM,UAAU,SAAA,EAAW,yBAAA,EAA2B,EAAE,SAAA,EAAW,IAAA,EAAM,OAAO,CAAA;AAAA,IAClF;AACA,IAAA,IAAI,MAAA,GAAkB,IAAA;AACtB,IAAA,IAAI;AAAE,MAAA,MAAA,GAAS,MAAM,IAAI,IAAA,EAAK;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAA4B;AACrE,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,QAAU,eAAA,CAAgB,GAAA,CAAI,QAAQ,MAAM,CAAA;AACrD,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,cAAA,GAAyB;AAEhC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,YAAA,IAAgB,MAAA,EAAQ;AAC3D,IAAA,OAAQ,MAAA,CAAwC,UAAA,EAAW,CAAE,OAAA,CAAQ,MAAM,EAAE,CAAA;AAAA,EAC/E;AACA,EAAA,OAAO,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAA;AACrE;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,CAAA,KAAK,UAAA,CAAW,CAAA,EAAG,EAAE,CAAC,CAAA;AAC3C;AAEA,SAAS,eAAe,GAAA,EAA4C;AAClE,EAAA,IAAI,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,UAAU,GAAA,IAAO,SAAA,IAAa,GAAA,IAAO,WAAA,IAAe,GAAA,EAAK;AAC7F,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,MAAM,GAAA,GAAO,KAAe,OAAA,IAAW,gBAAA;AACvC,EAAA,OAAO,UAAU,SAAA,EAAW,GAAA,EAAK,EAAE,KAAA,EAAO,KAAK,CAAA;AACjD;AAEA,SAAS,aAAA,CAAiB,KAAQ,SAAA,EAAsB;AACtD,EAAA,IAAI,OAAO,OAAO,GAAA,KAAQ,QAAA,EAAW,IAA+B,SAAA,GAAY,SAAA;AAChF,EAAA,OAAO,GAAA;AACT","file":"chunk-RYS4MXXL.js","sourcesContent":["// __SDK_VERSION__ is replaced at build time by tsup's `define` with the\n// package.json version. The typeof guard keeps tsc/tests working unreplaced.\ndeclare const __SDK_VERSION__: string | undefined;\n\nexport const SDK_VERSION: string =\n typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n\n/** Wire format sent to cdn-be on every API call, e.g. \"js/0.1.9\". */\nexport const SDK_VERSION_HEADER = `js/${SDK_VERSION}`;\n\n/** Wire format for the Node server-to-server SDK, e.g. \"node/0.4.0\". */\nexport const NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError, EMPTY_FILE_MESSAGE } from './errors.js';\nimport { SDK_VERSION_HEADER } from './version.js';\n\ninterface InitResponse {\n sessionId: string;\n fileId: string;\n chunkSize: number;\n totalParts: number;\n partUrls: Array<{ partNumber: number; url: string }>;\n expiresAt: string;\n}\n\ninterface CompleteResponse {\n handle: string;\n fileId: string;\n url: string;\n filename: string;\n mimetype: string;\n size: number;\n key: string;\n container: string;\n status: 'Stored';\n etag?: string;\n metadata?: Record<string, unknown>;\n}\n\ninterface PartResult {\n partNumber: number;\n etag: string;\n size: number;\n}\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_MAX_RETRIES_PER_PART = 3;\n// Backoff schedule between part retries. Capped — past this we surrender.\nconst BACKOFF_MS = [400, 1200, 3600];\n\nexport class Uploader {\n constructor(private cfg: ResolvedClientConfig) {}\n\n /** Returns a stable PickedFile descriptor for the input blob/file. */\n describe(file: File | Blob, opts: { filename?: string; mimeType?: string } = {}): PickedFile {\n const isFile = typeof File !== 'undefined' && file instanceof File;\n const filename =\n opts.filename ||\n (isFile ? (file as File).name : 'untitled');\n const mimetype =\n opts.mimeType || (file as Blob).type || 'application/octet-stream';\n return {\n uploadId: cryptoRandomId(),\n filename,\n mimetype,\n size: file.size,\n source: 'local',\n };\n }\n\n async upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const picked = this.describe(file, { filename: opts.filename, mimeType: opts.mimeType });\n opts.onFileUploadStarted?.(picked);\n\n // Refuse empty files before touching the network. A 0-byte File almost\n // always means a cloud \"on-demand\"/placeholder file (iCloud, OneDrive,\n // Google Drive) that hasn't been downloaded, or a file that changed after\n // selection — uploading it would store an unusable 0-byte object.\n if (file.size === 0) {\n const err = makeError('EMPTY_FILE', EMPTY_FILE_MESSAGE, { retryable: false });\n opts.onFileUploadFailed?.(picked, err);\n throw err;\n }\n\n try {\n const init = await this.initUpload(picked, opts);\n const parts = await this.uploadAllParts(file, init, picked, opts);\n const completed = await this.completeUpload(init.sessionId, parts, opts);\n\n const uploaded: UploadedFile = {\n ...picked,\n handle: completed.handle,\n fileId: completed.fileId,\n url: completed.url,\n size: completed.size,\n mimetype: completed.mimetype,\n filename: completed.filename,\n key: completed.key,\n container: completed.container,\n status: 'Stored',\n etag: completed.etag,\n metadata: completed.metadata,\n };\n opts.onFileUploadFinished?.(uploaded);\n return uploaded;\n } catch (rawErr) {\n const err = normalizeError(rawErr);\n opts.onFileUploadFailed?.(picked, err);\n // Best effort: tell the server to clean up the multipart, but ignore failures.\n if ((rawErr as { sessionId?: string })?.sessionId) {\n this.abortSilently((rawErr as { sessionId: string }).sessionId).catch(() => {});\n }\n throw err;\n }\n }\n\n /** Cancel an in-flight session server-side. */\n async abort(sessionId: string): Promise<void> {\n await this.api('POST', '/sdk/v1/uploads/abort', { sessionId });\n }\n\n /** Fetch the server-managed picker config (branding, theme, constraints). */\n async fetchPickerConfig(): Promise<PickerConfig> {\n return this.api<PickerConfig>('GET', '/sdk/v1/picker-config');\n }\n\n private async initUpload(picked: PickedFile, opts: UploadOptions): Promise<InitResponse> {\n return this.api<InitResponse>('POST', '/sdk/v1/uploads/init', {\n filename: picked.filename,\n mimeType: picked.mimetype,\n size: picked.size,\n metadata: opts.metadata,\n }, opts.signal);\n }\n\n private async uploadAllParts(\n file: File | Blob,\n init: InitResponse,\n picked: PickedFile,\n opts: UploadOptions,\n ): Promise<PartResult[]> {\n const totalParts = init.totalParts;\n const chunkSize = init.chunkSize;\n const concurrency = Math.max(1, opts.concurrency ?? DEFAULT_CONCURRENCY);\n const maxRetries = opts.maxRetriesPerPart ?? DEFAULT_MAX_RETRIES_PER_PART;\n\n // Quick lookup: partNumber → presigned URL.\n const urlByPart = new Map(init.partUrls.map(p => [p.partNumber, p.url] as const));\n\n const results: PartResult[] = new Array(totalParts);\n const loadedPerPart: number[] = new Array(totalParts).fill(0);\n let cursor = 1;\n\n const totalBytes = file.size;\n\n const reportProgress = () => {\n const loaded = loadedPerPart.reduce((a, b) => a + b, 0);\n const totalPercent = totalBytes > 0 ? Math.min(100, Math.round((loaded / totalBytes) * 100)) : 100;\n const ev: USProgressEvent = { totalBytes, loaded, totalPercent };\n opts.onFileUploadProgress?.(picked, ev);\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n const partNumber = cursor++;\n if (partNumber > totalParts) return;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const chunk = file.slice(start, end);\n\n let attempt = 0;\n let lastErr: unknown;\n while (attempt <= maxRetries) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n try {\n let url = urlByPart.get(partNumber);\n if (!url) {\n const refreshed = await this.api<{ url: string }>(\n 'POST', '/sdk/v1/uploads/sign-part',\n { sessionId: init.sessionId, partNumber }, opts.signal,\n );\n url = refreshed.url;\n urlByPart.set(partNumber, url);\n }\n\n const res = await this.cfg.fetch?.(url, {\n method: 'PUT',\n body: chunk,\n signal: opts.signal,\n }) ?? await fetch(url, { method: 'PUT', body: chunk, signal: opts.signal });\n\n if (!res.ok) {\n // If R2 rejects with 403 the URL likely expired — drop it so the\n // next attempt re-signs.\n if (res.status === 403 || res.status === 401) urlByPart.delete(partNumber);\n throw makeError('PART_FAILED', `Part ${partNumber} PUT failed (HTTP ${res.status})`, { status: res.status });\n }\n const etag = res.headers.get('etag');\n if (!etag) {\n throw makeError('PART_FAILED', `Part ${partNumber}: R2 did not return an ETag.`);\n }\n\n results[partNumber - 1] = { partNumber, etag, size: chunk.size };\n loadedPerPart[partNumber - 1] = chunk.size;\n reportProgress();\n break;\n } catch (err) {\n lastErr = err;\n attempt++;\n if (attempt > maxRetries) break;\n await sleep(BACKOFF_MS[Math.min(attempt - 1, BACKOFF_MS.length - 1)]);\n }\n }\n if (!results[partNumber - 1]) {\n throw withSessionId(\n normalizeError(lastErr ?? makeError('PART_FAILED', `Part ${partNumber} failed after ${maxRetries} retries.`)),\n init.sessionId,\n );\n }\n }\n };\n\n const workers = Array.from({ length: Math.min(concurrency, totalParts) }, worker);\n await Promise.all(workers);\n return results;\n }\n\n private async completeUpload(\n sessionId: string,\n parts: PartResult[],\n opts: UploadOptions,\n ): Promise<CompleteResponse> {\n return this.api<CompleteResponse>('POST', '/sdk/v1/uploads/complete', {\n sessionId,\n parts: parts.map(p => ({ partNumber: p.partNumber, etag: p.etag })),\n }, opts.signal);\n }\n\n private async abortSilently(sessionId: string): Promise<void> {\n try { await this.abort(sessionId); } catch { /* ignore */ }\n }\n\n private async api<T>(\n method: 'GET' | 'POST' | 'DELETE',\n path: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n const fetchImpl = this.cfg.fetch ?? fetch;\n const url = `${this.cfg.apiBase}${path}`;\n let res: Response;\n try {\n res = await fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.cfg.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-UnionStack-SDK': this.cfg.sdkHeader ?? SDK_VERSION_HEADER,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n });\n } catch (cause) {\n if ((cause as Error)?.name === 'AbortError') {\n throw makeError('ABORTED', 'Request aborted.', { retryable: false, cause });\n }\n throw makeError('NETWORK', 'Network request failed.', { retryable: true, cause });\n }\n let parsed: unknown = null;\n try { parsed = await res.json(); } catch { /* tolerate empty body */ }\n if (!res.ok) throw fromApiResponse(res.status, parsed);\n return parsed as T;\n }\n}\n\nfunction cryptoRandomId(): string {\n // Cheap unique id for client-side uploadId. Not security-sensitive.\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return (crypto as { randomUUID: () => string }).randomUUID().replace(/-/g, '');\n }\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n\nfunction normalizeError(err: unknown): ReturnType<typeof makeError> {\n if (err && typeof err === 'object' && 'code' in err && 'message' in err && 'retryable' in err) {\n return err as ReturnType<typeof makeError>;\n }\n const msg = (err as Error)?.message || 'Upload failed.';\n return makeError('NETWORK', msg, { cause: err });\n}\n\nfunction withSessionId<T>(err: T, sessionId: string): T {\n if (err && typeof err === 'object') (err as { sessionId?: string }).sessionId = sessionId;\n return err;\n}\n"]}
1
+ {"version":3,"sources":["../src/version.ts","../src/uploader.ts"],"names":[],"mappings":"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","file":"chunk-JAO2DEL3.js","sourcesContent":["// __SDK_VERSION__ is replaced at build time by tsup's `define` with the\n// package.json version. The typeof guard keeps tsc/tests working unreplaced.\ndeclare const __SDK_VERSION__: string | undefined;\n\nexport const SDK_VERSION: string =\n typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n\n/** Wire format sent to cdn-be on every API call, e.g. \"js/0.1.9\". */\nexport const SDK_VERSION_HEADER = `js/${SDK_VERSION}`;\n\n/** Wire format for the Node server-to-server SDK, e.g. \"node/0.4.0\". */\nexport const NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError, EMPTY_FILE_MESSAGE } from './errors.js';\nimport { SDK_VERSION_HEADER } from './version.js';\n\ninterface InitResponse {\n sessionId: string;\n fileId: string;\n chunkSize: number;\n totalParts: number;\n partUrls: Array<{ partNumber: number; url: string }>;\n expiresAt: string;\n}\n\ninterface CompleteResponse {\n handle: string;\n fileId: string;\n url: string;\n filename: string;\n mimetype: string;\n size: number;\n key: string;\n container: string;\n status: 'Stored';\n etag?: string;\n metadata?: Record<string, unknown>;\n}\n\ninterface PartResult {\n partNumber: number;\n etag: string;\n size: number;\n}\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_MAX_RETRIES_PER_PART = 3;\n// Backoff schedule between part retries. Capped — past this we surrender.\nconst BACKOFF_MS = [400, 1200, 3600];\n\nexport class Uploader {\n constructor(private cfg: ResolvedClientConfig) {}\n\n /** Returns a stable PickedFile descriptor for the input blob/file. */\n describe(file: File | Blob, opts: { filename?: string; mimeType?: string } = {}): PickedFile {\n const isFile = typeof File !== 'undefined' && file instanceof File;\n const filename =\n opts.filename ||\n (isFile ? (file as File).name : 'untitled');\n const mimetype =\n opts.mimeType || (file as Blob).type || 'application/octet-stream';\n return {\n uploadId: cryptoRandomId(),\n filename,\n mimetype,\n size: file.size,\n source: 'local',\n };\n }\n\n async upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const picked = this.describe(file, { filename: opts.filename, mimeType: opts.mimeType });\n opts.onFileUploadStarted?.(picked);\n\n // Refuse empty files before touching the network. A 0-byte File almost\n // always means a cloud \"on-demand\"/placeholder file (iCloud, OneDrive,\n // Google Drive) that hasn't been downloaded, or a file that changed after\n // selection — uploading it would store an unusable 0-byte object.\n if (file.size === 0) {\n const err = makeError('EMPTY_FILE', EMPTY_FILE_MESSAGE, { retryable: false });\n opts.onFileUploadFailed?.(picked, err);\n throw err;\n }\n\n try {\n const init = await this.initUpload(picked, opts);\n const parts = await this.uploadAllParts(file, init, picked, opts);\n const completed = await this.completeUpload(init.sessionId, parts, opts);\n\n const uploaded: UploadedFile = {\n ...picked,\n handle: completed.handle,\n fileId: completed.fileId,\n url: completed.url,\n size: completed.size,\n mimetype: completed.mimetype,\n filename: completed.filename,\n key: completed.key,\n container: completed.container,\n status: 'Stored',\n etag: completed.etag,\n metadata: completed.metadata,\n };\n opts.onFileUploadFinished?.(uploaded);\n return uploaded;\n } catch (rawErr) {\n const err = normalizeError(rawErr);\n opts.onFileUploadFailed?.(picked, err);\n // Best effort: tell the server to clean up the multipart, but ignore failures.\n if ((rawErr as { sessionId?: string })?.sessionId) {\n this.abortSilently((rawErr as { sessionId: string }).sessionId).catch(() => {});\n }\n throw err;\n }\n }\n\n /** Cancel an in-flight session server-side. */\n async abort(sessionId: string): Promise<void> {\n await this.api('POST', '/sdk/v1/uploads/abort', { sessionId });\n }\n\n /** Fetch the server-managed picker config (branding, theme, constraints). */\n async fetchPickerConfig(): Promise<PickerConfig> {\n return this.api<PickerConfig>('GET', '/sdk/v1/picker-config');\n }\n\n private async initUpload(picked: PickedFile, opts: UploadOptions): Promise<InitResponse> {\n return this.api<InitResponse>('POST', '/sdk/v1/uploads/init', {\n filename: picked.filename,\n mimeType: picked.mimetype,\n size: picked.size,\n metadata: opts.metadata,\n }, opts.signal);\n }\n\n private async uploadAllParts(\n file: File | Blob,\n init: InitResponse,\n picked: PickedFile,\n opts: UploadOptions,\n ): Promise<PartResult[]> {\n const totalParts = init.totalParts;\n const chunkSize = init.chunkSize;\n const concurrency = Math.max(1, opts.concurrency ?? DEFAULT_CONCURRENCY);\n const maxRetries = opts.maxRetriesPerPart ?? DEFAULT_MAX_RETRIES_PER_PART;\n\n // Quick lookup: partNumber → presigned URL.\n const urlByPart = new Map(init.partUrls.map(p => [p.partNumber, p.url] as const));\n\n const results: PartResult[] = new Array(totalParts);\n const loadedPerPart: number[] = new Array(totalParts).fill(0);\n let cursor = 1;\n\n const totalBytes = file.size;\n\n const reportProgress = () => {\n const loaded = loadedPerPart.reduce((a, b) => a + b, 0);\n const totalPercent = totalBytes > 0 ? Math.min(100, Math.round((loaded / totalBytes) * 100)) : 100;\n const ev: USProgressEvent = { totalBytes, loaded, totalPercent };\n opts.onFileUploadProgress?.(picked, ev);\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n const partNumber = cursor++;\n if (partNumber > totalParts) return;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const chunk = file.slice(start, end);\n\n let attempt = 0;\n let lastErr: unknown;\n while (attempt <= maxRetries) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n try {\n let url = urlByPart.get(partNumber);\n if (!url) {\n const refreshed = await this.api<{ url: string }>(\n 'POST', '/sdk/v1/uploads/sign-part',\n { sessionId: init.sessionId, partNumber }, opts.signal,\n );\n url = refreshed.url;\n urlByPart.set(partNumber, url);\n }\n\n const res = await this.cfg.fetch?.(url, {\n method: 'PUT',\n body: chunk,\n signal: opts.signal,\n }) ?? await fetch(url, { method: 'PUT', body: chunk, signal: opts.signal });\n\n if (!res.ok) {\n // If R2 rejects with 403 the URL likely expired — drop it so the\n // next attempt re-signs.\n if (res.status === 403 || res.status === 401) urlByPart.delete(partNumber);\n throw makeError('PART_FAILED', `Part ${partNumber} PUT failed (HTTP ${res.status})`, { status: res.status });\n }\n const etag = res.headers.get('etag');\n if (!etag) {\n throw makeError('PART_FAILED', `Part ${partNumber}: R2 did not return an ETag.`);\n }\n\n results[partNumber - 1] = { partNumber, etag, size: chunk.size };\n loadedPerPart[partNumber - 1] = chunk.size;\n reportProgress();\n break;\n } catch (err) {\n lastErr = err;\n attempt++;\n if (attempt > maxRetries) break;\n await sleep(BACKOFF_MS[Math.min(attempt - 1, BACKOFF_MS.length - 1)]);\n }\n }\n if (!results[partNumber - 1]) {\n throw withSessionId(\n normalizeError(lastErr ?? makeError('PART_FAILED', `Part ${partNumber} failed after ${maxRetries} retries.`)),\n init.sessionId,\n );\n }\n }\n };\n\n const workers = Array.from({ length: Math.min(concurrency, totalParts) }, worker);\n await Promise.all(workers);\n return results;\n }\n\n private async completeUpload(\n sessionId: string,\n parts: PartResult[],\n opts: UploadOptions,\n ): Promise<CompleteResponse> {\n return this.api<CompleteResponse>('POST', '/sdk/v1/uploads/complete', {\n sessionId,\n parts: parts.map(p => ({ partNumber: p.partNumber, etag: p.etag })),\n }, opts.signal);\n }\n\n private async abortSilently(sessionId: string): Promise<void> {\n try { await this.abort(sessionId); } catch { /* ignore */ }\n }\n\n private async api<T>(\n method: 'GET' | 'POST' | 'DELETE',\n path: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n const fetchImpl = this.cfg.fetch ?? fetch;\n const url = `${this.cfg.apiBase}${path}`;\n let res: Response;\n try {\n res = await fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.cfg.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-UnionStack-SDK': this.cfg.sdkHeader ?? SDK_VERSION_HEADER,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n });\n } catch (cause) {\n if ((cause as Error)?.name === 'AbortError') {\n throw makeError('ABORTED', 'Request aborted.', { retryable: false, cause });\n }\n throw makeError('NETWORK', 'Network request failed.', { retryable: true, cause });\n }\n let parsed: unknown = null;\n try { parsed = await res.json(); } catch { /* tolerate empty body */ }\n if (!res.ok) throw fromApiResponse(res.status, parsed);\n return parsed as T;\n }\n}\n\nfunction cryptoRandomId(): string {\n // Cheap unique id for client-side uploadId. Not security-sensitive.\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return (crypto as { randomUUID: () => string }).randomUUID().replace(/-/g, '');\n }\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n\nfunction normalizeError(err: unknown): ReturnType<typeof makeError> {\n if (err && typeof err === 'object' && 'code' in err && 'message' in err && 'retryable' in err) {\n return err as ReturnType<typeof makeError>;\n }\n const msg = (err as Error)?.message || 'Upload failed.';\n return makeError('NETWORK', msg, { cause: err });\n}\n\nfunction withSessionId<T>(err: T, sessionId: string): T {\n if (err && typeof err === 'object') (err as { sessionId?: string }).sessionId = sessionId;\n return err;\n}\n"]}
@@ -3,7 +3,7 @@
3
3
  var chunkTQDC5KIC_cjs = require('./chunk-TQDC5KIC.cjs');
4
4
 
5
5
  // src/version.ts
6
- var SDK_VERSION = "0.3.17" ;
6
+ var SDK_VERSION = "0.4.1" ;
7
7
  var SDK_VERSION_HEADER = `js/${SDK_VERSION}`;
8
8
  var NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;
9
9
 
@@ -227,5 +227,5 @@ function withSessionId(err, sessionId) {
227
227
 
228
228
  exports.NODE_SDK_VERSION_HEADER = NODE_SDK_VERSION_HEADER;
229
229
  exports.Uploader = Uploader;
230
- //# sourceMappingURL=chunk-PVM2ZX45.cjs.map
231
- //# sourceMappingURL=chunk-PVM2ZX45.cjs.map
230
+ //# sourceMappingURL=chunk-ULC3GQ5J.cjs.map
231
+ //# sourceMappingURL=chunk-ULC3GQ5J.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/uploader.ts"],"names":["makeError","EMPTY_FILE_MESSAGE","fromApiResponse"],"mappings":";;;;;AAIO,IAAM,WAAA,GAC2B,QAAA,CAAkB;AAGnD,IAAM,kBAAA,GAAqB,MAAM,WAAW,CAAA,CAAA;AAG5C,IAAM,uBAAA,GAA0B,QAAQ,WAAW,CAAA;;;AC6B1D,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,4BAAA,GAA+B,CAAA;AAErC,IAAM,UAAA,GAAa,CAAC,GAAA,EAAK,IAAA,EAAM,IAAI,CAAA;AAE5B,IAAM,WAAN,MAAe;AAAA,EACpB,YAAoB,GAAA,EAA2B;AAA3B,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAAA,EAA4B;AAAA;AAAA,EAGhD,QAAA,CAAS,IAAA,EAAmB,IAAA,GAAiD,EAAC,EAAe;AAC3F,IAAA,MAAM,MAAA,GAAS,OAAO,IAAA,KAAS,WAAA,IAAe,IAAA,YAAgB,IAAA;AAC9D,IAAA,MAAM,QAAA,GACJ,IAAA,CAAK,QAAA,KACJ,MAAA,GAAU,KAAc,IAAA,GAAO,UAAA,CAAA;AAClC,IAAA,MAAM,QAAA,GACJ,IAAA,CAAK,QAAA,IAAa,IAAA,CAAc,IAAA,IAAQ,0BAAA;AAC1C,IAAA,OAAO;AAAA,MACL,UAAU,cAAA,EAAe;AAAA,MACzB,QAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAAA,EAEA,MAAM,MAAA,CAAO,IAAA,EAAmB,IAAA,GAAsB,EAAC,EAA0B;AAC/E,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,CAAA;AACvF,IAAA,IAAA,CAAK,sBAAsB,MAAM,CAAA;AAMjC,IAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,MAAA,MAAM,MAAMA,2BAAA,CAAU,YAAA,EAAcC,sCAAoB,EAAE,SAAA,EAAW,OAAO,CAAA;AAC5E,MAAA,IAAA,CAAK,kBAAA,GAAqB,QAAQ,GAAG,CAAA;AACrC,MAAA,MAAM,GAAA;AAAA,IACR;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,UAAA,CAAW,QAAQ,IAAI,CAAA;AAC/C,MAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,eAAe,IAAA,EAAM,IAAA,EAAM,QAAQ,IAAI,CAAA;AAChE,MAAA,MAAM,YAAY,MAAM,IAAA,CAAK,eAAe,IAAA,CAAK,SAAA,EAAW,OAAO,IAAI,CAAA;AAEvE,MAAA,MAAM,QAAA,GAAyB;AAAA,QAC7B,GAAG,MAAA;AAAA,QACH,QAAQ,SAAA,CAAU,MAAA;AAAA,QAClB,QAAQ,SAAA,CAAU,MAAA;AAAA,QAClB,KAAK,SAAA,CAAU,GAAA;AAAA,QACf,MAAM,SAAA,CAAU,IAAA;AAAA,QAChB,UAAU,SAAA,CAAU,QAAA;AAAA,QACpB,UAAU,SAAA,CAAU,QAAA;AAAA,QACpB,KAAK,SAAA,CAAU,GAAA;AAAA,QACf,WAAW,SAAA,CAAU,SAAA;AAAA,QACrB,MAAA,EAAQ,QAAA;AAAA,QACR,MAAM,SAAA,CAAU,IAAA;AAAA,QAChB,UAAU,SAAA,CAAU;AAAA,OACtB;AACA,MAAA,IAAA,CAAK,uBAAuB,QAAQ,CAAA;AACpC,MAAA,OAAO,QAAA;AAAA,IACT,SAAS,MAAA,EAAQ;AACf,MAAA,MAAM,GAAA,GAAM,eAAe,MAAM,CAAA;AACjC,MAAA,IAAA,CAAK,kBAAA,GAAqB,QAAQ,GAAG,CAAA;AAErC,MAAA,IAAK,QAAmC,SAAA,EAAW;AACjD,QAAA,IAAA,CAAK,aAAA,CAAe,MAAA,CAAiC,SAAS,CAAA,CAAE,MAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAChF;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,MAAM,SAAA,EAAkC;AAC5C,IAAA,MAAM,KAAK,GAAA,CAAI,MAAA,EAAQ,uBAAA,EAAyB,EAAE,WAAW,CAAA;AAAA,EAC/D;AAAA;AAAA,EAGA,MAAM,iBAAA,GAA2C;AAC/C,IAAA,OAAO,IAAA,CAAK,GAAA,CAAkB,KAAA,EAAO,uBAAuB,CAAA;AAAA,EAC9D;AAAA,EAEA,MAAc,UAAA,CAAW,MAAA,EAAoB,IAAA,EAA4C;AACvF,IAAA,OAAO,IAAA,CAAK,GAAA,CAAkB,MAAA,EAAQ,sBAAA,EAAwB;AAAA,MAC5D,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,UAAU,IAAA,CAAK;AAAA,KACjB,EAAG,KAAK,MAAM,CAAA;AAAA,EAChB;AAAA,EAEA,MAAc,cAAA,CACZ,IAAA,EACA,IAAA,EACA,QACA,IAAA,EACuB;AACvB,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,MAAM,cAAc,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,eAAe,mBAAmB,CAAA;AACvE,IAAA,MAAM,UAAA,GAAa,KAAK,iBAAA,IAAqB,4BAAA;AAG7C,IAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,UAAA,EAAY,CAAA,CAAE,GAAG,CAAU,CAAC,CAAA;AAEhF,IAAA,MAAM,OAAA,GAAwB,IAAI,KAAA,CAAM,UAAU,CAAA;AAClD,IAAA,MAAM,gBAA0B,IAAI,KAAA,CAAM,UAAU,CAAA,CAAE,KAAK,CAAC,CAAA;AAC5D,IAAA,IAAI,MAAA,GAAS,CAAA;AAEb,IAAA,MAAM,aAAa,IAAA,CAAK,IAAA;AAExB,IAAA,MAAM,iBAAiB,MAAM;AAC3B,MAAA,MAAM,MAAA,GAAS,cAAc,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,GAAG,CAAC,CAAA;AACtD,MAAA,MAAM,YAAA,GAAe,UAAA,GAAa,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,KAAA,CAAO,MAAA,GAAS,UAAA,GAAc,GAAG,CAAC,CAAA,GAAI,GAAA;AAC/F,MAAA,MAAM,EAAA,GAAsB,EAAE,UAAA,EAAY,MAAA,EAAQ,YAAA,EAAa;AAC/D,MAAA,IAAA,CAAK,oBAAA,GAAuB,QAAQ,EAAE,CAAA;AAAA,IACxC,CAAA;AAEA,IAAA,MAAM,SAAS,YAA2B;AACxC,MAAA,OAAO,IAAA,EAAM;AACX,QAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,UAAA,MAAMD,4BAAU,SAAA,EAAW,2BAAA,EAA6B,EAAE,SAAA,EAAW,OAAO,CAAA;AAAA,QAC9E;AACA,QAAA,MAAM,UAAA,GAAa,MAAA,EAAA;AACnB,QAAA,IAAI,aAAa,UAAA,EAAY;AAE7B,QAAA,MAAM,KAAA,GAAA,CAAS,aAAa,CAAA,IAAK,SAAA;AACjC,QAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,SAAA,EAAW,KAAK,IAAI,CAAA;AACjD,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA;AAEnC,QAAA,IAAI,OAAA,GAAU,CAAA;AACd,QAAA,IAAI,OAAA;AACJ,QAAA,OAAO,WAAW,UAAA,EAAY;AAC5B,UAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,YAAA,MAAMA,4BAAU,SAAA,EAAW,2BAAA,EAA6B,EAAE,SAAA,EAAW,OAAO,CAAA;AAAA,UAC9E;AACA,UAAA,IAAI;AACF,YAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,UAAU,CAAA;AAClC,YAAA,IAAI,CAAC,GAAA,EAAK;AACR,cAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,GAAA;AAAA,gBAC3B,MAAA;AAAA,gBAAQ,2BAAA;AAAA,gBACR,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,UAAA,EAAW;AAAA,gBAAG,IAAA,CAAK;AAAA,eAClD;AACA,cAAA,GAAA,GAAM,SAAA,CAAU,GAAA;AAChB,cAAA,SAAA,CAAU,GAAA,CAAI,YAAY,GAAG,CAAA;AAAA,YAC/B;AAEA,YAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,GAAA,CAAI,QAAQ,GAAA,EAAK;AAAA,cACtC,MAAA,EAAQ,KAAA;AAAA,cACR,IAAA,EAAM,KAAA;AAAA,cACN,QAAQ,IAAA,CAAK;AAAA,aACd,CAAA,IAAK,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAE1E,YAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AAGX,cAAA,IAAI,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK,SAAA,CAAU,OAAO,UAAU,CAAA;AACzE,cAAA,MAAMA,2BAAA,CAAU,aAAA,EAAe,CAAA,KAAA,EAAQ,UAAU,CAAA,kBAAA,EAAqB,GAAA,CAAI,MAAM,CAAA,CAAA,CAAA,EAAK,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA;AAAA,YAC7G;AACA,YAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACnC,YAAA,IAAI,CAAC,IAAA,EAAM;AACT,cAAA,MAAMA,2BAAA,CAAU,aAAA,EAAe,CAAA,KAAA,EAAQ,UAAU,CAAA,4BAAA,CAA8B,CAAA;AAAA,YACjF;AAEA,YAAA,OAAA,CAAQ,UAAA,GAAa,CAAC,CAAA,GAAI,EAAE,YAAY,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAK;AAC/D,YAAA,aAAA,CAAc,UAAA,GAAa,CAAC,CAAA,GAAI,KAAA,CAAM,IAAA;AACtC,YAAA,cAAA,EAAe;AACf,YAAA;AAAA,UACF,SAAS,GAAA,EAAK;AACZ,YAAA,OAAA,GAAU,GAAA;AACV,YAAA,OAAA,EAAA;AACA,YAAA,IAAI,UAAU,UAAA,EAAY;AAC1B,YAAA,MAAM,KAAA,CAAM,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,OAAA,GAAU,GAAG,UAAA,CAAW,MAAA,GAAS,CAAC,CAAC,CAAC,CAAA;AAAA,UACtE;AAAA,QACF;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,GAAa,CAAC,CAAA,EAAG;AAC5B,UAAA,MAAM,aAAA;AAAA,YACJ,cAAA,CAAe,WAAWA,2BAAA,CAAU,aAAA,EAAe,QAAQ,UAAU,CAAA,cAAA,EAAiB,UAAU,CAAA,SAAA,CAAW,CAAC,CAAA;AAAA,YAC5G,IAAA,CAAK;AAAA,WACP;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,UAAU,CAAA,EAAE,EAAG,MAAM,CAAA;AAChF,IAAA,MAAM,OAAA,CAAQ,IAAI,OAAO,CAAA;AACzB,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEA,MAAc,cAAA,CACZ,SAAA,EACA,KAAA,EACA,IAAA,EAC2B;AAC3B,IAAA,OAAO,IAAA,CAAK,GAAA,CAAsB,MAAA,EAAQ,0BAAA,EAA4B;AAAA,MACpE,SAAA;AAAA,MACA,KAAA,EAAO,KAAA,CAAM,GAAA,CAAI,CAAA,CAAA,MAAM,EAAE,UAAA,EAAY,CAAA,CAAE,UAAA,EAAY,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK,CAAE;AAAA,KACpE,EAAG,KAAK,MAAM,CAAA;AAAA,EAChB;AAAA,EAEA,MAAc,cAAc,SAAA,EAAkC;AAC5D,IAAA,IAAI;AAAE,MAAA,MAAM,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAe;AAAA,EAC5D;AAAA,EAEA,MAAc,GAAA,CACZ,MAAA,EACA,IAAA,EACA,MACA,MAAA,EACY;AACZ,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS,KAAA;AACpC,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,OAAO,GAAG,IAAI,CAAA,CAAA;AACtC,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,UAAU,GAAA,EAAK;AAAA,QACzB,MAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,UACxC,cAAA,EAAgB,kBAAA;AAAA,UAChB,kBAAA,EAAoB,IAAA,CAAK,GAAA,CAAI,SAAA,IAAa;AAAA,SAC5C;AAAA,QACA,MAAM,IAAA,KAAS,KAAA,CAAA,GAAY,KAAA,CAAA,GAAY,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,QAC1D;AAAA,OACD,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,IAAK,KAAA,EAAiB,SAAS,YAAA,EAAc;AAC3C,QAAA,MAAMA,4BAAU,SAAA,EAAW,kBAAA,EAAoB,EAAE,SAAA,EAAW,KAAA,EAAO,OAAO,CAAA;AAAA,MAC5E;AACA,MAAA,MAAMA,4BAAU,SAAA,EAAW,yBAAA,EAA2B,EAAE,SAAA,EAAW,IAAA,EAAM,OAAO,CAAA;AAAA,IAClF;AACA,IAAA,IAAI,MAAA,GAAkB,IAAA;AACtB,IAAA,IAAI;AAAE,MAAA,MAAA,GAAS,MAAM,IAAI,IAAA,EAAK;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAA4B;AACrE,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,QAAUE,iCAAA,CAAgB,GAAA,CAAI,QAAQ,MAAM,CAAA;AACrD,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,cAAA,GAAyB;AAEhC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,YAAA,IAAgB,MAAA,EAAQ;AAC3D,IAAA,OAAQ,MAAA,CAAwC,UAAA,EAAW,CAAE,OAAA,CAAQ,MAAM,EAAE,CAAA;AAAA,EAC/E;AACA,EAAA,OAAO,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAA;AACrE;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,CAAA,KAAK,UAAA,CAAW,CAAA,EAAG,EAAE,CAAC,CAAA;AAC3C;AAEA,SAAS,eAAe,GAAA,EAA4C;AAClE,EAAA,IAAI,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,UAAU,GAAA,IAAO,SAAA,IAAa,GAAA,IAAO,WAAA,IAAe,GAAA,EAAK;AAC7F,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,MAAM,GAAA,GAAO,KAAe,OAAA,IAAW,gBAAA;AACvC,EAAA,OAAOF,4BAAU,SAAA,EAAW,GAAA,EAAK,EAAE,KAAA,EAAO,KAAK,CAAA;AACjD;AAEA,SAAS,aAAA,CAAiB,KAAQ,SAAA,EAAsB;AACtD,EAAA,IAAI,OAAO,OAAO,GAAA,KAAQ,QAAA,EAAW,IAA+B,SAAA,GAAY,SAAA;AAChF,EAAA,OAAO,GAAA;AACT","file":"chunk-PVM2ZX45.cjs","sourcesContent":["// __SDK_VERSION__ is replaced at build time by tsup's `define` with the\n// package.json version. The typeof guard keeps tsc/tests working unreplaced.\ndeclare const __SDK_VERSION__: string | undefined;\n\nexport const SDK_VERSION: string =\n typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n\n/** Wire format sent to cdn-be on every API call, e.g. \"js/0.1.9\". */\nexport const SDK_VERSION_HEADER = `js/${SDK_VERSION}`;\n\n/** Wire format for the Node server-to-server SDK, e.g. \"node/0.4.0\". */\nexport const NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError, EMPTY_FILE_MESSAGE } from './errors.js';\nimport { SDK_VERSION_HEADER } from './version.js';\n\ninterface InitResponse {\n sessionId: string;\n fileId: string;\n chunkSize: number;\n totalParts: number;\n partUrls: Array<{ partNumber: number; url: string }>;\n expiresAt: string;\n}\n\ninterface CompleteResponse {\n handle: string;\n fileId: string;\n url: string;\n filename: string;\n mimetype: string;\n size: number;\n key: string;\n container: string;\n status: 'Stored';\n etag?: string;\n metadata?: Record<string, unknown>;\n}\n\ninterface PartResult {\n partNumber: number;\n etag: string;\n size: number;\n}\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_MAX_RETRIES_PER_PART = 3;\n// Backoff schedule between part retries. Capped — past this we surrender.\nconst BACKOFF_MS = [400, 1200, 3600];\n\nexport class Uploader {\n constructor(private cfg: ResolvedClientConfig) {}\n\n /** Returns a stable PickedFile descriptor for the input blob/file. */\n describe(file: File | Blob, opts: { filename?: string; mimeType?: string } = {}): PickedFile {\n const isFile = typeof File !== 'undefined' && file instanceof File;\n const filename =\n opts.filename ||\n (isFile ? (file as File).name : 'untitled');\n const mimetype =\n opts.mimeType || (file as Blob).type || 'application/octet-stream';\n return {\n uploadId: cryptoRandomId(),\n filename,\n mimetype,\n size: file.size,\n source: 'local',\n };\n }\n\n async upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const picked = this.describe(file, { filename: opts.filename, mimeType: opts.mimeType });\n opts.onFileUploadStarted?.(picked);\n\n // Refuse empty files before touching the network. A 0-byte File almost\n // always means a cloud \"on-demand\"/placeholder file (iCloud, OneDrive,\n // Google Drive) that hasn't been downloaded, or a file that changed after\n // selection — uploading it would store an unusable 0-byte object.\n if (file.size === 0) {\n const err = makeError('EMPTY_FILE', EMPTY_FILE_MESSAGE, { retryable: false });\n opts.onFileUploadFailed?.(picked, err);\n throw err;\n }\n\n try {\n const init = await this.initUpload(picked, opts);\n const parts = await this.uploadAllParts(file, init, picked, opts);\n const completed = await this.completeUpload(init.sessionId, parts, opts);\n\n const uploaded: UploadedFile = {\n ...picked,\n handle: completed.handle,\n fileId: completed.fileId,\n url: completed.url,\n size: completed.size,\n mimetype: completed.mimetype,\n filename: completed.filename,\n key: completed.key,\n container: completed.container,\n status: 'Stored',\n etag: completed.etag,\n metadata: completed.metadata,\n };\n opts.onFileUploadFinished?.(uploaded);\n return uploaded;\n } catch (rawErr) {\n const err = normalizeError(rawErr);\n opts.onFileUploadFailed?.(picked, err);\n // Best effort: tell the server to clean up the multipart, but ignore failures.\n if ((rawErr as { sessionId?: string })?.sessionId) {\n this.abortSilently((rawErr as { sessionId: string }).sessionId).catch(() => {});\n }\n throw err;\n }\n }\n\n /** Cancel an in-flight session server-side. */\n async abort(sessionId: string): Promise<void> {\n await this.api('POST', '/sdk/v1/uploads/abort', { sessionId });\n }\n\n /** Fetch the server-managed picker config (branding, theme, constraints). */\n async fetchPickerConfig(): Promise<PickerConfig> {\n return this.api<PickerConfig>('GET', '/sdk/v1/picker-config');\n }\n\n private async initUpload(picked: PickedFile, opts: UploadOptions): Promise<InitResponse> {\n return this.api<InitResponse>('POST', '/sdk/v1/uploads/init', {\n filename: picked.filename,\n mimeType: picked.mimetype,\n size: picked.size,\n metadata: opts.metadata,\n }, opts.signal);\n }\n\n private async uploadAllParts(\n file: File | Blob,\n init: InitResponse,\n picked: PickedFile,\n opts: UploadOptions,\n ): Promise<PartResult[]> {\n const totalParts = init.totalParts;\n const chunkSize = init.chunkSize;\n const concurrency = Math.max(1, opts.concurrency ?? DEFAULT_CONCURRENCY);\n const maxRetries = opts.maxRetriesPerPart ?? DEFAULT_MAX_RETRIES_PER_PART;\n\n // Quick lookup: partNumber → presigned URL.\n const urlByPart = new Map(init.partUrls.map(p => [p.partNumber, p.url] as const));\n\n const results: PartResult[] = new Array(totalParts);\n const loadedPerPart: number[] = new Array(totalParts).fill(0);\n let cursor = 1;\n\n const totalBytes = file.size;\n\n const reportProgress = () => {\n const loaded = loadedPerPart.reduce((a, b) => a + b, 0);\n const totalPercent = totalBytes > 0 ? Math.min(100, Math.round((loaded / totalBytes) * 100)) : 100;\n const ev: USProgressEvent = { totalBytes, loaded, totalPercent };\n opts.onFileUploadProgress?.(picked, ev);\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n const partNumber = cursor++;\n if (partNumber > totalParts) return;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const chunk = file.slice(start, end);\n\n let attempt = 0;\n let lastErr: unknown;\n while (attempt <= maxRetries) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n try {\n let url = urlByPart.get(partNumber);\n if (!url) {\n const refreshed = await this.api<{ url: string }>(\n 'POST', '/sdk/v1/uploads/sign-part',\n { sessionId: init.sessionId, partNumber }, opts.signal,\n );\n url = refreshed.url;\n urlByPart.set(partNumber, url);\n }\n\n const res = await this.cfg.fetch?.(url, {\n method: 'PUT',\n body: chunk,\n signal: opts.signal,\n }) ?? await fetch(url, { method: 'PUT', body: chunk, signal: opts.signal });\n\n if (!res.ok) {\n // If R2 rejects with 403 the URL likely expired — drop it so the\n // next attempt re-signs.\n if (res.status === 403 || res.status === 401) urlByPart.delete(partNumber);\n throw makeError('PART_FAILED', `Part ${partNumber} PUT failed (HTTP ${res.status})`, { status: res.status });\n }\n const etag = res.headers.get('etag');\n if (!etag) {\n throw makeError('PART_FAILED', `Part ${partNumber}: R2 did not return an ETag.`);\n }\n\n results[partNumber - 1] = { partNumber, etag, size: chunk.size };\n loadedPerPart[partNumber - 1] = chunk.size;\n reportProgress();\n break;\n } catch (err) {\n lastErr = err;\n attempt++;\n if (attempt > maxRetries) break;\n await sleep(BACKOFF_MS[Math.min(attempt - 1, BACKOFF_MS.length - 1)]);\n }\n }\n if (!results[partNumber - 1]) {\n throw withSessionId(\n normalizeError(lastErr ?? makeError('PART_FAILED', `Part ${partNumber} failed after ${maxRetries} retries.`)),\n init.sessionId,\n );\n }\n }\n };\n\n const workers = Array.from({ length: Math.min(concurrency, totalParts) }, worker);\n await Promise.all(workers);\n return results;\n }\n\n private async completeUpload(\n sessionId: string,\n parts: PartResult[],\n opts: UploadOptions,\n ): Promise<CompleteResponse> {\n return this.api<CompleteResponse>('POST', '/sdk/v1/uploads/complete', {\n sessionId,\n parts: parts.map(p => ({ partNumber: p.partNumber, etag: p.etag })),\n }, opts.signal);\n }\n\n private async abortSilently(sessionId: string): Promise<void> {\n try { await this.abort(sessionId); } catch { /* ignore */ }\n }\n\n private async api<T>(\n method: 'GET' | 'POST' | 'DELETE',\n path: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n const fetchImpl = this.cfg.fetch ?? fetch;\n const url = `${this.cfg.apiBase}${path}`;\n let res: Response;\n try {\n res = await fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.cfg.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-UnionStack-SDK': this.cfg.sdkHeader ?? SDK_VERSION_HEADER,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n });\n } catch (cause) {\n if ((cause as Error)?.name === 'AbortError') {\n throw makeError('ABORTED', 'Request aborted.', { retryable: false, cause });\n }\n throw makeError('NETWORK', 'Network request failed.', { retryable: true, cause });\n }\n let parsed: unknown = null;\n try { parsed = await res.json(); } catch { /* tolerate empty body */ }\n if (!res.ok) throw fromApiResponse(res.status, parsed);\n return parsed as T;\n }\n}\n\nfunction cryptoRandomId(): string {\n // Cheap unique id for client-side uploadId. Not security-sensitive.\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return (crypto as { randomUUID: () => string }).randomUUID().replace(/-/g, '');\n }\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n\nfunction normalizeError(err: unknown): ReturnType<typeof makeError> {\n if (err && typeof err === 'object' && 'code' in err && 'message' in err && 'retryable' in err) {\n return err as ReturnType<typeof makeError>;\n }\n const msg = (err as Error)?.message || 'Upload failed.';\n return makeError('NETWORK', msg, { cause: err });\n}\n\nfunction withSessionId<T>(err: T, sessionId: string): T {\n if (err && typeof err === 'object') (err as { sessionId?: string }).sessionId = sessionId;\n return err;\n}\n"]}
1
+ {"version":3,"sources":["../src/version.ts","../src/uploader.ts"],"names":["makeError","EMPTY_FILE_MESSAGE","fromApiResponse"],"mappings":"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","file":"chunk-ULC3GQ5J.cjs","sourcesContent":["// __SDK_VERSION__ is replaced at build time by tsup's `define` with the\n// package.json version. The typeof guard keeps tsc/tests working unreplaced.\ndeclare const __SDK_VERSION__: string | undefined;\n\nexport const SDK_VERSION: string =\n typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n\n/** Wire format sent to cdn-be on every API call, e.g. \"js/0.1.9\". */\nexport const SDK_VERSION_HEADER = `js/${SDK_VERSION}`;\n\n/** Wire format for the Node server-to-server SDK, e.g. \"node/0.4.0\". */\nexport const NODE_SDK_VERSION_HEADER = `node/${SDK_VERSION}`;\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError, EMPTY_FILE_MESSAGE } from './errors.js';\nimport { SDK_VERSION_HEADER } from './version.js';\n\ninterface InitResponse {\n sessionId: string;\n fileId: string;\n chunkSize: number;\n totalParts: number;\n partUrls: Array<{ partNumber: number; url: string }>;\n expiresAt: string;\n}\n\ninterface CompleteResponse {\n handle: string;\n fileId: string;\n url: string;\n filename: string;\n mimetype: string;\n size: number;\n key: string;\n container: string;\n status: 'Stored';\n etag?: string;\n metadata?: Record<string, unknown>;\n}\n\ninterface PartResult {\n partNumber: number;\n etag: string;\n size: number;\n}\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_MAX_RETRIES_PER_PART = 3;\n// Backoff schedule between part retries. Capped — past this we surrender.\nconst BACKOFF_MS = [400, 1200, 3600];\n\nexport class Uploader {\n constructor(private cfg: ResolvedClientConfig) {}\n\n /** Returns a stable PickedFile descriptor for the input blob/file. */\n describe(file: File | Blob, opts: { filename?: string; mimeType?: string } = {}): PickedFile {\n const isFile = typeof File !== 'undefined' && file instanceof File;\n const filename =\n opts.filename ||\n (isFile ? (file as File).name : 'untitled');\n const mimetype =\n opts.mimeType || (file as Blob).type || 'application/octet-stream';\n return {\n uploadId: cryptoRandomId(),\n filename,\n mimetype,\n size: file.size,\n source: 'local',\n };\n }\n\n async upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const picked = this.describe(file, { filename: opts.filename, mimeType: opts.mimeType });\n opts.onFileUploadStarted?.(picked);\n\n // Refuse empty files before touching the network. A 0-byte File almost\n // always means a cloud \"on-demand\"/placeholder file (iCloud, OneDrive,\n // Google Drive) that hasn't been downloaded, or a file that changed after\n // selection — uploading it would store an unusable 0-byte object.\n if (file.size === 0) {\n const err = makeError('EMPTY_FILE', EMPTY_FILE_MESSAGE, { retryable: false });\n opts.onFileUploadFailed?.(picked, err);\n throw err;\n }\n\n try {\n const init = await this.initUpload(picked, opts);\n const parts = await this.uploadAllParts(file, init, picked, opts);\n const completed = await this.completeUpload(init.sessionId, parts, opts);\n\n const uploaded: UploadedFile = {\n ...picked,\n handle: completed.handle,\n fileId: completed.fileId,\n url: completed.url,\n size: completed.size,\n mimetype: completed.mimetype,\n filename: completed.filename,\n key: completed.key,\n container: completed.container,\n status: 'Stored',\n etag: completed.etag,\n metadata: completed.metadata,\n };\n opts.onFileUploadFinished?.(uploaded);\n return uploaded;\n } catch (rawErr) {\n const err = normalizeError(rawErr);\n opts.onFileUploadFailed?.(picked, err);\n // Best effort: tell the server to clean up the multipart, but ignore failures.\n if ((rawErr as { sessionId?: string })?.sessionId) {\n this.abortSilently((rawErr as { sessionId: string }).sessionId).catch(() => {});\n }\n throw err;\n }\n }\n\n /** Cancel an in-flight session server-side. */\n async abort(sessionId: string): Promise<void> {\n await this.api('POST', '/sdk/v1/uploads/abort', { sessionId });\n }\n\n /** Fetch the server-managed picker config (branding, theme, constraints). */\n async fetchPickerConfig(): Promise<PickerConfig> {\n return this.api<PickerConfig>('GET', '/sdk/v1/picker-config');\n }\n\n private async initUpload(picked: PickedFile, opts: UploadOptions): Promise<InitResponse> {\n return this.api<InitResponse>('POST', '/sdk/v1/uploads/init', {\n filename: picked.filename,\n mimeType: picked.mimetype,\n size: picked.size,\n metadata: opts.metadata,\n }, opts.signal);\n }\n\n private async uploadAllParts(\n file: File | Blob,\n init: InitResponse,\n picked: PickedFile,\n opts: UploadOptions,\n ): Promise<PartResult[]> {\n const totalParts = init.totalParts;\n const chunkSize = init.chunkSize;\n const concurrency = Math.max(1, opts.concurrency ?? DEFAULT_CONCURRENCY);\n const maxRetries = opts.maxRetriesPerPart ?? DEFAULT_MAX_RETRIES_PER_PART;\n\n // Quick lookup: partNumber → presigned URL.\n const urlByPart = new Map(init.partUrls.map(p => [p.partNumber, p.url] as const));\n\n const results: PartResult[] = new Array(totalParts);\n const loadedPerPart: number[] = new Array(totalParts).fill(0);\n let cursor = 1;\n\n const totalBytes = file.size;\n\n const reportProgress = () => {\n const loaded = loadedPerPart.reduce((a, b) => a + b, 0);\n const totalPercent = totalBytes > 0 ? Math.min(100, Math.round((loaded / totalBytes) * 100)) : 100;\n const ev: USProgressEvent = { totalBytes, loaded, totalPercent };\n opts.onFileUploadProgress?.(picked, ev);\n };\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n const partNumber = cursor++;\n if (partNumber > totalParts) return;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const chunk = file.slice(start, end);\n\n let attempt = 0;\n let lastErr: unknown;\n while (attempt <= maxRetries) {\n if (opts.signal?.aborted) {\n throw makeError('ABORTED', 'Upload aborted by caller.', { retryable: false });\n }\n try {\n let url = urlByPart.get(partNumber);\n if (!url) {\n const refreshed = await this.api<{ url: string }>(\n 'POST', '/sdk/v1/uploads/sign-part',\n { sessionId: init.sessionId, partNumber }, opts.signal,\n );\n url = refreshed.url;\n urlByPart.set(partNumber, url);\n }\n\n const res = await this.cfg.fetch?.(url, {\n method: 'PUT',\n body: chunk,\n signal: opts.signal,\n }) ?? await fetch(url, { method: 'PUT', body: chunk, signal: opts.signal });\n\n if (!res.ok) {\n // If R2 rejects with 403 the URL likely expired — drop it so the\n // next attempt re-signs.\n if (res.status === 403 || res.status === 401) urlByPart.delete(partNumber);\n throw makeError('PART_FAILED', `Part ${partNumber} PUT failed (HTTP ${res.status})`, { status: res.status });\n }\n const etag = res.headers.get('etag');\n if (!etag) {\n throw makeError('PART_FAILED', `Part ${partNumber}: R2 did not return an ETag.`);\n }\n\n results[partNumber - 1] = { partNumber, etag, size: chunk.size };\n loadedPerPart[partNumber - 1] = chunk.size;\n reportProgress();\n break;\n } catch (err) {\n lastErr = err;\n attempt++;\n if (attempt > maxRetries) break;\n await sleep(BACKOFF_MS[Math.min(attempt - 1, BACKOFF_MS.length - 1)]);\n }\n }\n if (!results[partNumber - 1]) {\n throw withSessionId(\n normalizeError(lastErr ?? makeError('PART_FAILED', `Part ${partNumber} failed after ${maxRetries} retries.`)),\n init.sessionId,\n );\n }\n }\n };\n\n const workers = Array.from({ length: Math.min(concurrency, totalParts) }, worker);\n await Promise.all(workers);\n return results;\n }\n\n private async completeUpload(\n sessionId: string,\n parts: PartResult[],\n opts: UploadOptions,\n ): Promise<CompleteResponse> {\n return this.api<CompleteResponse>('POST', '/sdk/v1/uploads/complete', {\n sessionId,\n parts: parts.map(p => ({ partNumber: p.partNumber, etag: p.etag })),\n }, opts.signal);\n }\n\n private async abortSilently(sessionId: string): Promise<void> {\n try { await this.abort(sessionId); } catch { /* ignore */ }\n }\n\n private async api<T>(\n method: 'GET' | 'POST' | 'DELETE',\n path: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n const fetchImpl = this.cfg.fetch ?? fetch;\n const url = `${this.cfg.apiBase}${path}`;\n let res: Response;\n try {\n res = await fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.cfg.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-UnionStack-SDK': this.cfg.sdkHeader ?? SDK_VERSION_HEADER,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n });\n } catch (cause) {\n if ((cause as Error)?.name === 'AbortError') {\n throw makeError('ABORTED', 'Request aborted.', { retryable: false, cause });\n }\n throw makeError('NETWORK', 'Network request failed.', { retryable: true, cause });\n }\n let parsed: unknown = null;\n try { parsed = await res.json(); } catch { /* tolerate empty body */ }\n if (!res.ok) throw fromApiResponse(res.status, parsed);\n return parsed as T;\n }\n}\n\nfunction cryptoRandomId(): string {\n // Cheap unique id for client-side uploadId. Not security-sensitive.\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return (crypto as { randomUUID: () => string }).randomUUID().replace(/-/g, '');\n }\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n\nfunction normalizeError(err: unknown): ReturnType<typeof makeError> {\n if (err && typeof err === 'object' && 'code' in err && 'message' in err && 'retryable' in err) {\n return err as ReturnType<typeof makeError>;\n }\n const msg = (err as Error)?.message || 'Upload failed.';\n return makeError('NETWORK', msg, { cause: err });\n}\n\nfunction withSessionId<T>(err: T, sessionId: string): T {\n if (err && typeof err === 'object') (err as { sessionId?: string }).sessionId = sessionId;\n return err;\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkPVM2ZX45_cjs = require('./chunk-PVM2ZX45.cjs');
3
+ var chunkULC3GQ5J_cjs = require('./chunk-ULC3GQ5J.cjs');
4
4
  var chunkTQDC5KIC_cjs = require('./chunk-TQDC5KIC.cjs');
5
5
 
6
6
  // src/client.ts
7
- var API_BASE = "https://api.unionstack.link/v1";
7
+ var API_BASE = "https://api.unionstack.in/v1";
8
8
  var PRELOADER_STYLE_ID = "unionstack-preloader-styles";
9
9
  function showPickerPreloader() {
10
10
  if (typeof document === "undefined") return () => {
@@ -38,7 +38,7 @@ var UnionStackClient = class {
38
38
  );
39
39
  }
40
40
  this.resolvedCfg = { ...cfg, apiBase: API_BASE };
41
- this.uploader = new chunkPVM2ZX45_cjs.Uploader(this.resolvedCfg);
41
+ this.uploader = new chunkULC3GQ5J_cjs.Uploader(this.resolvedCfg);
42
42
  this.pickerConfigPromise = !cfg.apiKey || this.resolvedCfg.skipConfigPrefetch ? Promise.resolve(null) : this.uploader.fetchPickerConfig().then((cfg2) => {
43
43
  if (cfg2?.sdkWarning) console.warn(`[UnionStack] ${cfg2.sdkWarning}`);
44
44
  return cfg2;
@@ -139,5 +139,5 @@ var UnionStackClient = class {
139
139
  };
140
140
 
141
141
  exports.UnionStackClient = UnionStackClient;
142
- //# sourceMappingURL=chunk-4645KBSE.cjs.map
143
- //# sourceMappingURL=chunk-4645KBSE.cjs.map
142
+ //# sourceMappingURL=chunk-Z7JOL2OE.cjs.map
143
+ //# sourceMappingURL=chunk-Z7JOL2OE.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":["Uploader","cfg","makeError"],"mappings":"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","file":"chunk-Z7JOL2OE.cjs","sourcesContent":["import type {\n ClientConfig,\n ResolvedClientConfig,\n UploadOptions,\n BatchUploadOptions,\n UploadedFile,\n PickResponse,\n PickedFile,\n PickerConfig,\n UploadError,\n} from './types.js';\nimport { Uploader } from './uploader.js';\nimport { makeError } from './errors.js';\n\n/**\n * UnionStack API URL baked into the SDK. Consumers never see or set this —\n * we ship a new SDK version if the URL ever changes.\n *\n * For local development against a staging backend, change this constant in\n * src/ and rebuild — no consumer-facing override exists by design.\n */\nconst API_BASE = 'https://api.unionstack.in/v1';\n\n// Forward-declared minimal handle so client.ts doesn't pull in the picker bundle.\nexport interface PickerHandleLike {\n open(): Promise<PickResponse>;\n close(): void;\n cancel(): void;\n}\n\nconst PRELOADER_STYLE_ID = 'unionstack-preloader-styles';\n\n// Instant spinner shown between picker.open() and the modal actually mounting\n// (covers the lazy chunk download + the server config fetch). Self-contained —\n// must not depend on the picker bundle, which is what we're waiting for. The\n// backdrop matches the picker's exactly so the handoff is seamless.\nfunction showPickerPreloader(): () => void {\n if (typeof document === 'undefined') return () => {};\n if (!document.getElementById(PRELOADER_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = PRELOADER_STYLE_ID;\n style.textContent =\n '@keyframes us-preload-spin{to{transform:rotate(360deg)}}' +\n '@keyframes us-preload-fade{from{opacity:0}to{opacity:1}}';\n document.head.appendChild(style);\n }\n const backdrop = document.createElement('div');\n backdrop.setAttribute('role', 'status');\n backdrop.setAttribute('aria-label', 'Loading file picker');\n backdrop.style.cssText =\n 'position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;' +\n 'background:rgba(2,6,23,0.4);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);' +\n 'animation:us-preload-fade 140ms ease-out;';\n const spinner = document.createElement('div');\n spinner.style.cssText =\n 'width:36px;height:36px;border-radius:50%;' +\n 'border:3px solid rgba(220,225,251,0.25);border-top-color:#c0c1ff;' +\n 'animation:us-preload-spin 0.8s linear infinite;';\n backdrop.appendChild(spinner);\n document.body.appendChild(backdrop);\n let removed = false;\n return () => {\n if (removed) return;\n removed = true;\n backdrop.remove();\n };\n}\n\nexport class UnionStackClient {\n private uploader: Uploader;\n private resolvedCfg: ResolvedClientConfig;\n /**\n * Promise that resolves to the server-managed picker config. Pre-fetched on\n * construction (unless `skipConfigPrefetch: true`) so the picker opens\n * without a network hit. Fails silently — picker falls back to defaults.\n */\n pickerConfigPromise: Promise<PickerConfig | null>;\n\n constructor(cfg: ClientConfig) {\n // Don't throw on a missing apiKey: the React provider constructs the\n // client during render, and a render-time throw crashes the host app.\n // Log instead, and let every operation reject with a CONFIG error.\n if (!cfg.apiKey) {\n console.error(\n '[UnionStack] apiKey is not set. Uploads and the picker are disabled until a valid apiKey is provided.',\n );\n }\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = (!cfg.apiKey || this.resolvedCfg.skipConfigPrefetch)\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig()\n .then(cfg => {\n if (cfg?.sdkWarning) console.warn(`[UnionStack] ${cfg.sdkWarning}`);\n return cfg;\n })\n .catch(() => null);\n }\n\n private missingKeyError(): UploadError | null {\n if (this.resolvedCfg.apiKey) return null;\n return makeError('CONFIG', 'apiKey is required.', { retryable: false });\n }\n\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n const keyErr = this.missingKeyError();\n if (keyErr) return Promise.reject(keyErr);\n return this.uploader.upload(file, opts);\n }\n\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\n const keyErr = this.missingKeyError();\n if (keyErr) {\n opts.onError?.(keyErr);\n throw keyErr;\n }\n if (!Array.isArray(files) || files.length === 0) {\n const err = makeError('VALIDATION', 'uploadMany requires a non-empty array of files.', { retryable: false });\n opts.onError?.(err);\n throw err;\n }\n\n const picked: PickedFile[] = files.map(f =>\n this.uploader.describe(f, { filename: opts.filename, mimeType: opts.mimeType })\n );\n opts.onUploadStarted?.(picked);\n\n const filesUploaded: UploadedFile[] = [];\n const filesFailed: Array<{ file: PickedFile; error: UploadError }> = [];\n\n await Promise.all(files.map(async (f, i) => {\n try {\n const uploaded = await this.uploader.upload(f, opts);\n // Sync the uploadId so callers can correlate picked → uploaded.\n uploaded.uploadId = picked[i].uploadId;\n filesUploaded.push(uploaded);\n } catch (err) {\n filesFailed.push({ file: picked[i], error: err as UploadError });\n }\n }));\n\n const result: PickResponse = { filesUploaded, filesFailed };\n opts.onUploadDone?.(result);\n return result;\n }\n \n picker(opts: import('./picker/types.js').PickerOptions = {}): PickerHandleLike {\n let real: PickerHandleLike | null = null;\n let opened = false;\n let pendingResolve!: (r: PickResponse) => void;\n let pendingReject!: (e: UploadError) => void;\n const donePromise = new Promise<PickResponse>((res, rej) => {\n pendingResolve = res; pendingReject = rej;\n });\n\n return {\n open: async () => {\n if (opened) return donePromise;\n const keyErr = this.missingKeyError();\n if (keyErr) {\n pendingReject(keyErr);\n throw keyErr;\n }\n opened = true;\n const hidePreloader = showPickerPreloader();\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, {\n ...opts,\n // Picker fires onOpen right after the modal mounts — that's the\n // moment the preloader hands off to the real UI.\n onOpen: () => { hidePreloader(); opts.onOpen?.(); },\n });\n const result = await real.open();\n hidePreloader();\n pendingResolve(result);\n return result;\n } catch (err) {\n hidePreloader();\n const e = (err as UploadError)?.code\n ? (err as UploadError)\n : makeError('CONFIG', 'Failed to load picker.', { retryable: false, cause: err });\n pendingReject(e);\n throw e;\n }\n },\n close: () => { real?.close(); },\n cancel: () => { real?.cancel(); },\n };\n }\n\n /** Read-only accessor used by the React/picker packages. */\n get config(): Readonly<ResolvedClientConfig> { return this.resolvedCfg; }\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var chunk4645KBSE_cjs = require('./chunk-4645KBSE.cjs');
4
- require('./chunk-PVM2ZX45.cjs');
3
+ var chunkZ7JOL2OE_cjs = require('./chunk-Z7JOL2OE.cjs');
4
+ require('./chunk-ULC3GQ5J.cjs');
5
5
  require('./chunk-TQDC5KIC.cjs');
6
6
 
7
7
  // src/index.ts
8
8
  var UnionStack = {
9
9
  init(cfg) {
10
- return new chunk4645KBSE_cjs.UnionStackClient(cfg);
10
+ return new chunkZ7JOL2OE_cjs.UnionStackClient(cfg);
11
11
  }
12
12
  };
13
13
 
14
14
  Object.defineProperty(exports, "UnionStackClient", {
15
15
  enumerable: true,
16
- get: function () { return chunk4645KBSE_cjs.UnionStackClient; }
16
+ get: function () { return chunkZ7JOL2OE_cjs.UnionStackClient; }
17
17
  });
18
18
  exports.UnionStack = UnionStack;
19
19
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { UnionStackClient } from './chunk-QQFNG3ZF.js';
2
- export { UnionStackClient } from './chunk-QQFNG3ZF.js';
3
- import './chunk-RYS4MXXL.js';
1
+ import { UnionStackClient } from './chunk-3BQ6RNXE.js';
2
+ export { UnionStackClient } from './chunk-3BQ6RNXE.js';
3
+ import './chunk-JAO2DEL3.js';
4
4
  import './chunk-G2H5WZDV.js';
5
5
 
6
6
  // src/index.ts
package/dist/node.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkPVM2ZX45_cjs = require('./chunk-PVM2ZX45.cjs');
3
+ var chunkULC3GQ5J_cjs = require('./chunk-ULC3GQ5J.cjs');
4
4
  var chunkTQDC5KIC_cjs = require('./chunk-TQDC5KIC.cjs');
5
5
  var path = require('path');
6
6
  var promises = require('fs/promises');
@@ -129,7 +129,7 @@ async function resolveSource(source, opts = {}) {
129
129
  }
130
130
 
131
131
  // src/node/index.ts
132
- var API_BASE = "https://api.unionstack.link/v1";
132
+ var API_BASE = "https://api.unionstack.in/v1";
133
133
  var DEFAULT_FILE_CONCURRENCY = 5;
134
134
  var UnionStackNodeClient = class {
135
135
  constructor(cfg) {
@@ -145,9 +145,9 @@ var UnionStackNodeClient = class {
145
145
  skipConfigPrefetch: true,
146
146
  // Tag the traffic as server-to-server ("node/…") so cdn-be can tell it
147
147
  // apart from browser SDK calls ("js/…").
148
- sdkHeader: chunkPVM2ZX45_cjs.NODE_SDK_VERSION_HEADER
148
+ sdkHeader: chunkULC3GQ5J_cjs.NODE_SDK_VERSION_HEADER
149
149
  };
150
- this.uploader = new chunkPVM2ZX45_cjs.Uploader(this.cfg);
150
+ this.uploader = new chunkULC3GQ5J_cjs.Uploader(this.cfg);
151
151
  }
152
152
  /**
153
153
  * Upload one file. Accepts a path on disk, a Buffer/Uint8Array/ArrayBuffer, a
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":"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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"]}
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.in/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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NODE_SDK_VERSION_HEADER, Uploader } from './chunk-RYS4MXXL.js';
1
+ import { NODE_SDK_VERSION_HEADER, Uploader } from './chunk-JAO2DEL3.js';
2
2
  import { makeError } from './chunk-G2H5WZDV.js';
3
3
  import { basename, extname } from 'path';
4
4
  import { readFile } from 'fs/promises';
@@ -107,7 +107,7 @@ async function resolveSource(source, opts = {}) {
107
107
  }
108
108
 
109
109
  // src/node/index.ts
110
- var API_BASE = "https://api.unionstack.link/v1";
110
+ var API_BASE = "https://api.unionstack.in/v1";
111
111
  var DEFAULT_FILE_CONCURRENCY = 5;
112
112
  var UnionStackNodeClient = class {
113
113
  constructor(cfg) {