@masters-union/union-stack 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/loader.v1.global.js +234 -42
- package/dist/cdn/loader.v1.global.js.map +1 -1
- package/dist/{chunk-445C5G3Q.cjs → chunk-GJ2ORKJM.cjs} +2 -2
- package/dist/{chunk-445C5G3Q.cjs.map → chunk-GJ2ORKJM.cjs.map} +1 -1
- package/dist/{chunk-I4NHLGGL.js → chunk-YLAPR7HG.js} +2 -2
- package/dist/{chunk-I4NHLGGL.js.map → chunk-YLAPR7HG.js.map} +1 -1
- package/dist/{client-DrOHTZ94.d.cts → client-AMBRkgCm.d.cts} +8 -0
- package/dist/{client-DrOHTZ94.d.ts → client-AMBRkgCm.d.ts} +8 -0
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/picker.cjs +431 -72
- package/dist/picker.cjs.map +1 -1
- package/dist/picker.d.cts +6 -2
- package/dist/picker.d.ts +6 -2
- package/dist/picker.js +431 -72
- package/dist/picker.js.map +1 -1
- package/dist/react.cjs +2 -2
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/picker/styles.ts","../../src/picker/picker.ts","../../src/picker/index.ts","../../src/loader/index.ts","../../src/errors.ts","../../src/uploader.ts","../../src/client.ts","../../src/index.ts"],"sourcesContent":["import type { PickerTheme } from './types.js';\n\nconst STYLE_ID = 'unionstack-picker-styles';\n\n/** Inject a single <style> tag once. Idempotent — safe to call repeatedly. */\nexport function ensureStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = BASE_CSS;\n document.head.appendChild(el);\n}\n\n/** Resolve a partial theme into CSS variables on the modal root. */\nexport function themeToCssVars(theme: PickerTheme | undefined): Record<string, string> {\n const mode = theme?.mode || 'light';\n const defaults = mode === 'dark' ? DARK_DEFAULTS : LIGHT_DEFAULTS;\n return {\n '--us-primary': theme?.primary ?? defaults.primary,\n '--us-bg': theme?.background ?? defaults.background,\n '--us-fg': theme?.foreground ?? defaults.foreground,\n '--us-muted': theme?.muted ?? defaults.muted,\n '--us-border': theme?.border ?? defaults.border,\n '--us-radius': theme?.radius ?? '12px',\n };\n}\n\nconst LIGHT_DEFAULTS = {\n primary: '#4f46e5',\n background: '#ffffff',\n foreground: '#0f172a',\n muted: '#64748b',\n border: '#e2e8f0',\n};\nconst DARK_DEFAULTS = {\n primary: '#6366f1',\n background: '#0f172a',\n foreground: '#f1f5f9',\n muted: '#94a3b8',\n border: '#1e293b',\n};\n\n// All selectors namespaced under .us-picker to avoid bleed into host page.\nconst BASE_CSS = `\n.us-picker-backdrop {\n position: fixed; inset: 0; z-index: 2147483000;\n background: rgba(2, 6, 23, 0.55);\n display: flex; align-items: center; justify-content: center;\n padding: 16px; font-family: ui-sans-serif, system-ui, sans-serif;\n animation: us-fade 120ms ease-out;\n}\n@keyframes us-fade { from { opacity: 0; } to { opacity: 1; } }\n.us-picker {\n background: var(--us-bg); color: var(--us-fg);\n border-radius: var(--us-radius);\n width: 100%; max-width: 480px; max-height: calc(100vh - 32px);\n display: flex; flex-direction: column;\n box-shadow: 0 25px 50px -12px rgba(0,0,0,0.4);\n overflow: hidden;\n}\n.us-picker * { box-sizing: border-box; }\n.us-picker-header {\n display: flex; align-items: center; gap: 12px;\n padding: 16px 20px; border-bottom: 1px solid var(--us-border);\n}\n.us-picker-header img { height: 24px; }\n.us-picker-title { font-weight: 600; font-size: 16px; flex: 1; }\n.us-picker-close {\n background: none; border: 0; cursor: pointer;\n color: var(--us-muted); font-size: 22px; line-height: 1;\n padding: 4px 8px; border-radius: 6px;\n}\n.us-picker-close:hover { background: var(--us-border); color: var(--us-fg); }\n.us-picker-body { padding: 20px; overflow-y: auto; }\n.us-dropzone {\n border: 2px dashed var(--us-border); border-radius: var(--us-radius);\n padding: 32px 20px; text-align: center; cursor: pointer;\n transition: border-color 120ms, background 120ms;\n}\n.us-dropzone:hover, .us-dropzone[data-drag=\"over\"] {\n border-color: var(--us-primary);\n background: color-mix(in srgb, var(--us-primary) 5%, transparent);\n}\n.us-dropzone-title { font-weight: 500; margin-bottom: 4px; }\n.us-dropzone-hint { color: var(--us-muted); font-size: 13px; }\n.us-file-list { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }\n.us-file {\n display: flex; align-items: center; gap: 12px;\n padding: 10px 12px; border: 1px solid var(--us-border);\n border-radius: 10px; font-size: 14px;\n}\n.us-file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.us-file-meta { color: var(--us-muted); font-size: 12px; }\n.us-file-progress {\n height: 4px; background: var(--us-border); border-radius: 999px; overflow: hidden;\n margin-top: 6px;\n}\n.us-file-progress-bar {\n height: 100%; background: var(--us-primary);\n width: 0%; transition: width 200ms;\n}\n.us-file[data-state=\"done\"] .us-file-progress-bar { background: #16a34a; width: 100%; }\n.us-file[data-state=\"failed\"] .us-file-progress-bar { background: #dc2626; }\n.us-actions {\n display: flex; gap: 8px; justify-content: flex-end;\n padding: 14px 20px; border-top: 1px solid var(--us-border);\n}\n.us-btn {\n padding: 8px 14px; border-radius: 8px; border: 1px solid var(--us-border);\n background: transparent; color: var(--us-fg); cursor: pointer; font-size: 14px;\n font-weight: 500;\n}\n.us-btn:hover { background: var(--us-border); }\n.us-btn-primary {\n background: var(--us-primary); color: white; border-color: var(--us-primary);\n}\n.us-btn-primary:hover { filter: brightness(0.95); }\n.us-btn[disabled] { opacity: 0.5; cursor: not-allowed; }\n.us-footer {\n padding: 8px 20px; font-size: 11px; color: var(--us-muted); text-align: center;\n}\n.us-footer a { color: var(--us-muted); }\n`;\n","import type { UnionStackClient } from '../client.js';\nimport type { PickerConfig, UploadError } from '../types.js';\nimport type {\n PickResponse,\n PickedFile,\n PickerHandle,\n PickerOptions,\n UploadedFile,\n} from './types.js';\nimport { ensureStyles, themeToCssVars } from './styles.js';\n\n// Merge server-managed picker config with runtime options. Runtime options\n// always win — they're the explicit dev escape hatch.\nfunction mergeConfig(server: PickerConfig, runtime: PickerOptions): PickerOptions {\n const merged: PickerOptions = { ...runtime };\n\n // Branding: shallow merge, runtime wins per-field.\n const runtimeBranding = runtime.branding || {};\n merged.branding = {\n logoUrl: runtimeBranding.logoUrl ?? server.branding.logoUrl ?? undefined,\n title: runtimeBranding.title ?? server.branding.title ?? undefined,\n hideFooter: runtimeBranding.hideFooter ?? server.branding.hideFooter,\n // PickerBranding has no footerText today — keep server's value internal.\n };\n\n // Theme: shallow merge.\n const runtimeTheme = runtime.theme || {};\n merged.theme = {\n primary: runtimeTheme.primary ?? server.theme.primary ?? undefined,\n background: runtimeTheme.background ?? server.theme.background ?? undefined,\n foreground: runtimeTheme.foreground ?? server.theme.foreground ?? undefined,\n border: runtimeTheme.border ?? server.theme.border ?? undefined,\n radius: runtimeTheme.radius ?? server.theme.radius ?? undefined,\n mode: runtimeTheme.mode ?? server.theme.mode ?? undefined,\n };\n\n // Constraints inform the dropzone (accept attr, size cap).\n merged.maxFileSize = runtime.maxFileSize ?? server.constraints.maxFileSizeBytes;\n merged.maxFiles = runtime.maxFiles ?? server.constraints.maxFilesPerUpload;\n if (!runtime.accept && server.constraints.allowedMimeTypes?.length) {\n const types = server.constraints.allowedMimeTypes.filter(t => t !== '*/*');\n if (types.length > 0) merged.accept = types.join(',');\n }\n return merged;\n}\n\ntype FileItemState = 'queued' | 'uploading' | 'done' | 'failed' | 'cancelled';\n\ninterface FileItem {\n uploadId: string; // matches PickedFile.uploadId once described\n file: File;\n state: FileItemState;\n progress: number; // 0-100\n error?: string;\n uploaded?: UploadedFile;\n // DOM refs we mutate on progress.\n $row?: HTMLElement;\n $bar?: HTMLElement;\n $status?: HTMLElement;\n}\n\nconst DEFAULT_TITLE = 'Upload files';\nconst FOOTER_LINK = 'https://unionstack.mastersunion.link';\n\n/**\n * Single-shot file picker modal. Built imperatively (no framework) so it can\n * be lazy-loaded by either the vanilla SDK or the React wrapper.\n */\nexport class Picker {\n private $backdrop: HTMLElement | null = null;\n private $list: HTMLElement | null = null;\n private $confirm: HTMLButtonElement | null = null;\n private $cancel: HTMLButtonElement | null = null;\n private $closeBtn: HTMLButtonElement | null = null;\n private $input: HTMLInputElement | null = null;\n\n private items: FileItem[] = [];\n private abortCtrl = new AbortController();\n private uploadStarted = false;\n private resolved = false;\n private resolvePromise!: (r: PickResponse) => void;\n private donePromise: Promise<PickResponse>;\n\n constructor(\n private client: UnionStackClient,\n private opts: PickerOptions,\n ) {\n this.donePromise = new Promise<PickResponse>(res => { this.resolvePromise = res; });\n }\n\n // ---- public api ---------------------------------------------------------\n\n async open(): Promise<PickResponse> {\n if (typeof document === 'undefined') {\n throw new Error('[union-stack] Picker requires a browser environment.');\n }\n // Pull server-side branding/theme defaults before painting the modal.\n // Runtime opts win over server config — see mergeConfig below.\n try {\n const serverConfig = await this.client.pickerConfigPromise;\n if (serverConfig) this.opts = mergeConfig(serverConfig, this.opts);\n } catch { /* fall through with whatever opts the caller passed */ }\n\n ensureStyles();\n this.mount();\n this.opts.onOpen?.();\n return this.donePromise;\n }\n\n close(): void {\n this.unmount();\n // Resolve with whatever was collected so callers awaiting open() never hang.\n if (!this.resolved) this.resolveResult();\n }\n\n cancel(): void {\n this.abortCtrl.abort();\n this.opts.onCancel?.();\n this.close();\n }\n\n // ---- mount / dom --------------------------------------------------------\n\n private mount() {\n const root = document.createElement('div');\n root.className = 'us-picker-backdrop';\n Object.entries(themeToCssVars(this.opts.theme)).forEach(([k, v]) => {\n root.style.setProperty(k, v);\n });\n root.addEventListener('click', e => {\n if (e.target === root && !this.uploadStarted) this.cancel();\n });\n\n const panel = el('div', 'us-picker');\n\n // Header\n const header = el('div', 'us-picker-header');\n if (this.opts.branding?.logoUrl) {\n const logo = document.createElement('img');\n logo.src = this.opts.branding.logoUrl;\n logo.alt = 'logo';\n header.appendChild(logo);\n }\n const title = el('div', 'us-picker-title', this.opts.branding?.title ?? DEFAULT_TITLE);\n header.appendChild(title);\n this.$closeBtn = document.createElement('button');\n this.$closeBtn.type = 'button';\n this.$closeBtn.className = 'us-picker-close';\n this.$closeBtn.setAttribute('aria-label', 'Close');\n this.$closeBtn.textContent = '×';\n this.$closeBtn.onclick = () => this.cancel();\n header.appendChild(this.$closeBtn);\n panel.appendChild(header);\n\n // Body\n const body = el('div', 'us-picker-body');\n body.appendChild(this.renderDropzone());\n this.$list = el('div', 'us-file-list');\n body.appendChild(this.$list);\n panel.appendChild(body);\n\n // Actions\n const actions = el('div', 'us-actions');\n this.$cancel = document.createElement('button');\n this.$cancel.type = 'button';\n this.$cancel.className = 'us-btn';\n this.$cancel.textContent = 'Cancel';\n this.$cancel.onclick = () => this.cancel();\n this.$confirm = document.createElement('button');\n this.$confirm.type = 'button';\n this.$confirm.className = 'us-btn us-btn-primary';\n this.$confirm.textContent = 'Upload';\n this.$confirm.disabled = true;\n this.$confirm.onclick = () => this.startUpload();\n actions.appendChild(this.$cancel);\n actions.appendChild(this.$confirm);\n panel.appendChild(actions);\n\n if (!this.opts.branding?.hideFooter) {\n const footer = el('div', 'us-footer');\n footer.innerHTML = `Powered by <a href=\"${FOOTER_LINK}\" target=\"_blank\" rel=\"noopener\">UnionStack</a>`;\n panel.appendChild(footer);\n }\n\n root.appendChild(panel);\n (this.opts.container ?? document.body).appendChild(root);\n this.$backdrop = root;\n }\n\n private renderDropzone(): HTMLElement {\n const dz = el('div', 'us-dropzone');\n dz.setAttribute('role', 'button');\n dz.setAttribute('tabindex', '0');\n dz.appendChild(el('div', 'us-dropzone-title', 'Drag files here'));\n dz.appendChild(el('div', 'us-dropzone-hint', 'or click to browse'));\n\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = (this.opts.maxFiles ?? 10) > 1;\n if (this.opts.accept) input.accept = this.opts.accept;\n input.style.display = 'none';\n input.onchange = () => {\n if (input.files) this.addFiles(Array.from(input.files));\n input.value = '';\n };\n this.$input = input;\n dz.appendChild(input);\n\n dz.onclick = () => input.click();\n dz.onkeydown = e => {\n if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); input.click(); }\n };\n\n dz.addEventListener('dragover', e => {\n e.preventDefault();\n dz.setAttribute('data-drag', 'over');\n });\n dz.addEventListener('dragleave', () => dz.removeAttribute('data-drag'));\n dz.addEventListener('drop', e => {\n e.preventDefault();\n dz.removeAttribute('data-drag');\n const dropped = e.dataTransfer?.files;\n if (dropped) this.addFiles(Array.from(dropped));\n });\n\n return dz;\n }\n\n private unmount() {\n if (this.$backdrop?.parentNode) this.$backdrop.parentNode.removeChild(this.$backdrop);\n this.$backdrop = null;\n this.opts.onClose?.();\n }\n\n // ---- file selection -----------------------------------------------------\n\n private addFiles(files: File[]) {\n const cap = this.opts.maxFiles ?? Infinity;\n const remaining = cap - this.items.length;\n if (remaining <= 0) return;\n const chosen = files.slice(0, remaining);\n\n for (const file of chosen) {\n if (this.opts.maxFileSize && file.size > this.opts.maxFileSize) {\n // Skip the file but surface a row in the list so the user sees why.\n const item: FileItem = {\n uploadId: cryptoId(),\n file, state: 'failed', progress: 0,\n error: `File exceeds ${formatBytes(this.opts.maxFileSize)} limit`,\n };\n this.items.push(item);\n this.renderItem(item);\n continue;\n }\n\n const item: FileItem = {\n uploadId: cryptoId(),\n file, state: 'queued', progress: 0,\n };\n this.items.push(item);\n this.renderItem(item);\n }\n\n this.refreshConfirm();\n }\n\n private renderItem(item: FileItem) {\n if (!this.$list) return;\n const row = el('div', 'us-file');\n row.dataset.state = item.state;\n row.dataset.uploadId = item.uploadId;\n\n const main = el('div', '', '');\n main.style.flex = '1';\n main.style.minWidth = '0';\n main.appendChild(el('div', 'us-file-name', item.file.name));\n\n const meta = el('div', 'us-file-meta', formatBytes(item.file.size));\n main.appendChild(meta);\n\n const progress = el('div', 'us-file-progress');\n const bar = el('div', 'us-file-progress-bar');\n progress.appendChild(bar);\n main.appendChild(progress);\n row.appendChild(main);\n\n const status = el('div', 'us-file-meta');\n status.style.minWidth = '60px';\n status.style.textAlign = 'right';\n status.textContent = item.state === 'failed'\n ? (item.error || 'failed')\n : item.state === 'done' ? 'done' : '0%';\n row.appendChild(status);\n\n item.$row = row;\n item.$bar = bar;\n item.$status = status;\n\n this.$list.appendChild(row);\n }\n\n private setItemState(item: FileItem, state: FileItemState, progress?: number) {\n item.state = state;\n if (progress !== undefined) item.progress = progress;\n if (item.$row) item.$row.dataset.state = state;\n if (item.$bar) item.$bar.style.width = `${item.progress}%`;\n if (item.$status) {\n if (state === 'failed') item.$status.textContent = item.error || 'failed';\n else if (state === 'done') item.$status.textContent = 'done';\n else item.$status.textContent = `${Math.round(item.progress)}%`;\n }\n }\n\n private refreshConfirm() {\n if (!this.$confirm) return;\n const queued = this.items.filter(i => i.state === 'queued').length;\n this.$confirm.disabled = queued === 0 || this.uploadStarted;\n }\n\n // ---- upload -------------------------------------------------------------\n\n private async startUpload() {\n if (this.uploadStarted) return;\n const queued = this.items.filter(i => i.state === 'queued');\n if (queued.length === 0) return;\n\n this.uploadStarted = true;\n if (this.$confirm) {\n this.$confirm.disabled = true;\n this.$confirm.textContent = 'Uploading…';\n }\n if (this.$cancel) this.$cancel.textContent = 'Stop';\n if (this.$closeBtn) this.$closeBtn.disabled = true;\n if (this.$input) this.$input.disabled = true;\n\n // Map PickedFile.uploadId → FileItem so callbacks update the right row.\n const itemByUploadId = new Map<string, FileItem>();\n const filesToUpload = queued.map(i => i.file);\n\n try {\n await this.client.uploadMany(filesToUpload, {\n ...this.opts,\n signal: this.abortCtrl.signal,\n onUploadStarted: (pickedFiles: PickedFile[]) => {\n // Pair each PickedFile to the queued FileItem in order.\n pickedFiles.forEach((p, idx) => {\n const item = queued[idx];\n if (item) {\n item.uploadId = p.uploadId;\n if (item.$row) item.$row.dataset.uploadId = p.uploadId;\n itemByUploadId.set(p.uploadId, item);\n }\n });\n this.opts.onUploadStarted?.(pickedFiles);\n },\n onFileUploadStarted: p => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) this.setItemState(item, 'uploading', 0);\n this.opts.onFileUploadStarted?.(p);\n },\n onFileUploadProgress: (p, ev) => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) this.setItemState(item, 'uploading', ev.totalPercent);\n this.opts.onFileUploadProgress?.(p, ev);\n },\n onFileUploadFinished: f => {\n const item = itemByUploadId.get(f.uploadId);\n if (item) {\n item.uploaded = f;\n this.setItemState(item, 'done', 100);\n }\n this.opts.onFileUploadFinished?.(f);\n },\n onFileUploadFailed: (p, err) => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) {\n item.error = err.message;\n this.setItemState(item, 'failed');\n }\n this.opts.onFileUploadFailed?.(p, err);\n },\n onUploadDone: r => {\n this.opts.onUploadDone?.(r);\n this.resolveResult(r);\n this.unmount();\n },\n onError: (err: UploadError) => {\n this.opts.onError?.(err);\n this.resolveResult();\n this.unmount();\n },\n });\n } catch {\n // Errors already surfaced via onError / onFileUploadFailed.\n if (!this.resolved) {\n this.resolveResult();\n this.unmount();\n }\n }\n }\n\n private resolveResult(result?: PickResponse) {\n if (this.resolved) return;\n this.resolved = true;\n const fallback: PickResponse = result ?? {\n filesUploaded: this.items.filter(i => i.uploaded).map(i => i.uploaded!),\n filesFailed: this.items\n .filter(i => i.state === 'failed')\n .map(i => ({\n file: {\n uploadId: i.uploadId,\n filename: i.file.name,\n mimetype: i.file.type || 'application/octet-stream',\n size: i.file.size,\n source: 'local',\n },\n error: {\n code: 'VALIDATION',\n message: i.error || 'failed',\n retryable: false,\n },\n })),\n };\n this.resolvePromise(fallback);\n }\n}\n\n// ---- helpers --------------------------------------------------------------\n\nfunction el(tag: string, className: string, text?: string): HTMLElement {\n const node = document.createElement(tag);\n if (className) node.className = className;\n if (text !== undefined) node.textContent = text;\n return node;\n}\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;\n return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;\n}\n\nfunction cryptoId(): string {\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\nexport function openPicker(client: UnionStackClient, opts: PickerOptions): PickerHandle {\n const picker = new Picker(client, opts);\n return {\n open: () => picker.open(),\n close: () => picker.close(),\n cancel: () => picker.cancel(),\n };\n}\n","export { Picker, openPicker } from './picker.js';\nexport type {\n PickerOptions,\n PickerHandle,\n PickerTheme,\n PickerBranding,\n} from './types.js';\n","// IIFE loader entry — bundled as a single drop-in <script>.\n//\n// <script src=\"https://unionstack.mastersunion.link/_sdk/v1/loader.js\"></script>\n// <script>\n// const client = UnionStack.init({ apiKey: 'unionstack_live_…', apiBase: '…' });\n// client.picker({ onUploadDone: r => console.log(r) }).open();\n// </script>\n//\n// Everything (core + picker UI) ships in this single file. The /react entry\n// is intentionally not included here — React users install from npm.\n\nimport { UnionStack, UnionStackClient } from '../index.js';\nimport { Picker, openPicker } from '../picker/index.js';\nimport type { ClientConfig } from '../types.js';\n\n// tsup's IIFE wrapper attaches every named export as a property on the\n// global `UnionStack`. To make `UnionStack.init({...})` work directly (rather\n// than `UnionStack.UnionStack.init(...)`), we flatten `init` to a top-level\n// export and keep the constructor classes available for advanced users.\nconst init = UnionStack.init.bind(UnionStack);\nexport { init, UnionStackClient, Picker, openPicker };\n\nexport type { ClientConfig };\n\n// Auto-init via data attribute — wire the loader without any inline script:\n//\n// <script src=\".../loader.js\" data-unionstack-key=\"unionstack_live_…\"></script>\n//\n// The resulting client lands on `window.UnionStack.client`.\ndeclare global {\n interface Window {\n UnionStack?: {\n init: typeof UnionStack.init;\n client?: UnionStackClient;\n };\n }\n}\n\n(function autoInit() {\n if (typeof document === 'undefined') return;\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return;\n const apiKey = script.getAttribute('data-unionstack-key');\n if (!apiKey) return;\n try {\n const client = UnionStack.init({ apiKey });\n queueMicrotask(() => {\n if (window.UnionStack) window.UnionStack.client = client;\n });\n } catch (err) {\n console.error('[UnionStack] auto-init failed:', err);\n }\n})();\n","import type { UploadError, UploadErrorCode } from './types.js';\n\nexport function makeError(\n code: UploadErrorCode,\n message: string,\n opts: { status?: number; retryable?: boolean; cause?: unknown } = {}\n): UploadError {\n return {\n code,\n message,\n status: opts.status,\n retryable: opts.retryable ?? defaultRetryable(code, opts.status),\n cause: opts.cause,\n };\n}\n\nfunction defaultRetryable(code: UploadErrorCode, status?: number): boolean {\n if (code === 'NETWORK' || code === 'PART_FAILED') return true;\n if (code === 'SERVER' && status && status >= 500) return true;\n return false;\n}\n\n/** Map an HTTP error response from the cdn-be API to an UploadError. */\nexport function fromApiResponse(status: number, body: unknown): UploadError {\n const err = (body as { error?: { code?: string; message?: string } } | null)?.error;\n const msg = err?.message || `Request failed with status ${status}`;\n const code = (err?.code || '').toUpperCase();\n\n if (status === 401) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 403) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 413) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 415) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 429) {\n const isQuota = code === 'QUOTA_EXCEEDED';\n return makeError(isQuota ? 'QUOTA' : 'NETWORK', msg, { status, retryable: !isQuota });\n }\n if (status >= 500) {\n return makeError('SERVER', msg, { status, retryable: true });\n }\n return makeError('SERVER', msg, { status, retryable: false });\n}\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError } from './errors.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 etag?: string;\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 /**\n * Upload a single Blob/File. Returns the persisted UploadedFile.\n * Fires Filestack-style per-file callbacks from `opts`.\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 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 status: 'Stored',\n etag: completed.etag,\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 },\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","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://cdn-api.mastersunion.org/cdn-api';\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\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 if (!cfg.apiKey) throw makeError('CONFIG', 'apiKey is required.', { retryable: false });\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = this.resolvedCfg.skipConfigPrefetch\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig().catch(() => null);\n }\n\n /** Upload a single file. Mirrors Filestack's `client.upload()`. */\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n return this.uploader.upload(file, opts);\n }\n\n /**\n * Upload multiple files concurrently. Mirrors Filestack's batch behavior:\n * onUploadDone fires once even if some files failed — failures land in\n * `filesFailed`, successes in `filesUploaded`. `onError` is reserved for\n * batch-level failures (no files even started).\n */\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\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 // Process per-file in parallel; the per-part concurrency from `opts` still\n // applies inside each upload.\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 /**\n * Open the file picker modal. Lazy-loads the picker bundle so the core\n * SDK stays small for callers that only use `upload()` directly.\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 opened = true;\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, opts);\n const result = await real.open();\n pendingResolve(result);\n return result;\n } catch (err) {\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","import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"],"mappings":"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","names":["ensureStyles","STYLE_ID","el","BASE_CSS","themeToCssVars","theme","_a","_b","_c","_d","_e","_f","defaults","DARK_DEFAULTS","LIGHT_DEFAULTS","init_styles","__esmMin","mergeConfig","server","runtime","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","merged","__spreadValues","runtimeBranding","runtimeTheme","types","t","el","tag","className","text","node","formatBytes","n","cryptoId","openPicker","client","opts","picker","Picker","DEFAULT_TITLE","FOOTER_LINK","init_picker","__esmMin","init_styles","res","serverConfig","e","ensureStyles","root","themeToCssVars","k","v","panel","header","logo","title","body","actions","footer","dz","input","dropped","files","remaining","chosen","file","item","row","main","meta","progress","bar","status","state","queued","i","itemByUploadId","filesToUpload","__spreadProps","pickedFiles","p","idx","ev","f","err","r","result","fallback","picker_exports","__export","Picker","openPicker","init_picker","__esmMin","loader_exports","__export","Picker","UnionStackClient","init","openPicker","makeError","code","message","opts","_a","defaultRetryable","status","fromApiResponse","body","err","msg","isQuota","DEFAULT_CONCURRENCY","DEFAULT_MAX_RETRIES_PER_PART","BACKOFF_MS","Uploader","cfg","file","opts","isFile","filename","mimetype","cryptoRandomId","_a","_b","_c","picked","init","parts","completed","uploaded","__spreadProps","__spreadValues","rawErr","err","normalizeError","sessionId","totalParts","chunkSize","concurrency","maxRetries","urlByPart","p","results","loadedPerPart","cursor","totalBytes","reportProgress","loaded","a","b","totalPercent","ev","worker","_d","_e","makeError","partNumber","start","end","chunk","attempt","lastErr","url","res","etag","sleep","withSessionId","workers","e","method","path","body","signal","fetchImpl","cause","parsed","fromApiResponse","ms","r","msg","API_BASE","UnionStackClient","cfg","makeError","__spreadProps","__spreadValues","Uploader","file","opts","files","_a","_b","_c","err","picked","f","filesUploaded","filesFailed","i","uploaded","result","real","opened","pendingResolve","pendingReject","donePromise","res","rej","e","UnionStack","cfg","UnionStackClient","init_picker","init","UnionStack","script","apiKey","client","UnionStack","err"]}
|
|
1
|
+
{"version":3,"sources":["../../src/picker/styles.ts","../../src/picker/picker.ts","../../src/picker/index.ts","../../src/loader/index.ts","../../src/errors.ts","../../src/uploader.ts","../../src/client.ts","../../src/index.ts"],"sourcesContent":["import type { PickerTheme } from './types.js';\n\nconst STYLE_ID = 'unionstack-picker-styles';\n\n/** Inject the picker stylesheet once. Idempotent — safe to call on every open. */\nexport function ensureStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = BASE_CSS;\n document.head.appendChild(el);\n}\n\n/** Resolve a (possibly partial) theme into the CSS variables the picker reads. */\nexport function themeToCssVars(theme: PickerTheme | undefined): Record<string, string> {\n const mode = theme?.mode || 'light';\n const defaults = mode === 'dark' ? DARK_DEFAULTS : LIGHT_DEFAULTS;\n return {\n '--us-primary': theme?.primary ?? defaults.primary,\n '--us-bg': theme?.background ?? defaults.background,\n '--us-fg': theme?.foreground ?? defaults.foreground,\n '--us-muted': defaults.muted,\n '--us-subtle': defaults.subtle,\n '--us-border': theme?.border ?? defaults.border,\n '--us-border-strong': defaults.borderStrong,\n '--us-elevated': defaults.elevated,\n '--us-success': defaults.success,\n '--us-danger': defaults.danger,\n '--us-radius': theme?.radius ?? '12px',\n };\n}\n\n// WCAG-verified pairs. Each token has a deliberate role; nothing here is by\n// vibes alone.\nconst LIGHT_DEFAULTS = {\n primary: '#4f46e5', // indigo-600 — confident, restrained\n background: '#ffffff',\n foreground: '#0f172a', // slate-900 — 15.4:1 on white\n muted: '#64748b', // slate-500 — 4.7:1 on white\n subtle: '#f8fafc', // slate-50 — chips, icon wells\n border: '#e2e8f0', // slate-200\n borderStrong: '#cbd5e1', // slate-300 — drag-over emphasis\n elevated: '#ffffff',\n success: '#16a34a',\n danger: '#dc2626',\n};\n\nconst DARK_DEFAULTS = {\n primary: '#818cf8', // indigo-400 — desaturated for dark mode\n background: '#0b0f1a', // near-black, not pure\n foreground: '#f1f5f9', // slate-100 — 15:1 on bg\n muted: '#94a3b8', // slate-400 — 6.4:1 on bg\n subtle: '#111827', // slightly elevated surface\n border: '#1f2937',\n borderStrong: '#334155',\n elevated: '#0f1625',\n success: '#4ade80',\n danger: '#f87171',\n};\n\n// Everything is namespaced under `.us-picker` and uses CSS variables so the\n// host page's styles never leak in, and theme overrides flow cleanly.\nconst BASE_CSS = `\n.us-picker-backdrop {\n position: fixed; inset: 0; z-index: 2147483000;\n background: color-mix(in srgb, #02060f 55%, transparent);\n -webkit-backdrop-filter: blur(8px);\n backdrop-filter: blur(8px);\n display: flex; align-items: center; justify-content: center;\n padding: 16px;\n font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n animation: us-fade 140ms ease-out;\n}\n@keyframes us-fade { from { opacity: 0; } to { opacity: 1; } }\n\n.us-picker {\n background: var(--us-bg); color: var(--us-fg);\n border: 1px solid var(--us-border);\n border-radius: var(--us-radius);\n width: 100%; max-width: 480px;\n max-height: min(calc(100dvh - 32px), 680px);\n display: flex; flex-direction: column;\n box-shadow:\n 0 1px 1px rgba(0,0,0,0.04),\n 0 18px 40px -8px rgba(0,0,0,0.18),\n 0 32px 80px -16px rgba(0,0,0,0.22);\n overflow: hidden;\n animation: us-rise 240ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n@keyframes us-rise {\n from { opacity: 0; transform: translateY(8px) scale(0.985); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n.us-picker * { box-sizing: border-box; }\n\n/* ──────────────────── header ──────────────────── */\n.us-picker-header {\n display: flex; align-items: center; gap: 12px;\n padding: 14px 16px;\n border-bottom: 1px solid var(--us-border);\n}\n.us-picker-header-logo {\n display: inline-flex; align-items: center; justify-content: center;\n width: 28px; height: 28px; flex-shrink: 0;\n border-radius: 8px;\n background: var(--us-subtle);\n color: var(--us-primary);\n}\n.us-picker-header-logo svg { width: 16px; height: 16px; }\n.us-picker-header-logo img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }\n.us-picker-title { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; flex: 1; }\n.us-picker-close {\n background: none; border: 0; cursor: pointer;\n width: 32px; height: 32px;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--us-muted); border-radius: 8px;\n transition: color 140ms, background 140ms;\n}\n.us-picker-close:hover { background: var(--us-subtle); color: var(--us-fg); }\n.us-picker-close:focus-visible { outline: 2px solid var(--us-primary); outline-offset: 1px; }\n.us-picker-close svg { width: 16px; height: 16px; }\n\n/* ──────────────────── body / dropzone ──────────────────── */\n.us-picker-body { padding: 16px; overflow-y: auto; }\n\n.us-dropzone {\n position: relative;\n border: 1.5px dashed var(--us-border-strong);\n border-radius: calc(var(--us-radius) - 2px);\n padding: 28px 20px;\n text-align: center;\n cursor: pointer;\n transition: border-color 160ms, background 160ms, transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n background: color-mix(in srgb, var(--us-subtle) 60%, transparent);\n}\n.us-dropzone:hover {\n border-color: var(--us-primary);\n background: color-mix(in srgb, var(--us-primary) 4%, var(--us-bg));\n}\n.us-dropzone:focus-visible {\n outline: 2px solid var(--us-primary); outline-offset: 2px;\n}\n.us-dropzone[data-drag=\"over\"] {\n border-style: solid;\n border-color: var(--us-primary);\n background: color-mix(in srgb, var(--us-primary) 8%, var(--us-bg));\n transform: scale(1.005);\n}\n.us-dropzone-icon {\n width: 44px; height: 44px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--us-primary) 12%, var(--us-bg));\n color: var(--us-primary);\n display: inline-flex; align-items: center; justify-content: center;\n margin-bottom: 12px;\n transition: transform 240ms cubic-bezier(0.16, 1.4, 0.3, 1);\n}\n.us-dropzone:hover .us-dropzone-icon { transform: translateY(-2px); }\n.us-dropzone[data-drag=\"over\"] .us-dropzone-icon {\n transform: translateY(-3px) scale(1.06);\n background: color-mix(in srgb, var(--us-primary) 18%, var(--us-bg));\n}\n.us-dropzone-icon svg { width: 22px; height: 22px; }\n.us-dropzone-title {\n font-size: 14px; font-weight: 600; letter-spacing: -0.01em;\n margin-bottom: 2px;\n}\n.us-dropzone-hint { color: var(--us-muted); font-size: 12.5px; }\n.us-dropzone-constraints {\n margin-top: 10px;\n font-size: 11px; color: var(--us-muted);\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n letter-spacing: 0.02em;\n}\n\n.us-dropzone--compact {\n padding: 12px 16px;\n display: flex; align-items: center; gap: 12px;\n text-align: left;\n}\n.us-dropzone--compact .us-dropzone-icon {\n width: 32px; height: 32px; border-radius: 8px; margin-bottom: 0;\n}\n.us-dropzone--compact .us-dropzone-icon svg { width: 16px; height: 16px; }\n.us-dropzone--compact .us-dropzone-title { font-size: 13px; margin: 0; }\n.us-dropzone--compact .us-dropzone-hint { display: none; }\n.us-dropzone--compact .us-dropzone-constraints { display: none; }\n\n/* ──────────────────── file list ──────────────────── */\n.us-file-list { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }\n\n.us-file {\n display: flex; align-items: center; gap: 12px;\n padding: 10px 12px;\n background: var(--us-elevated);\n border: 1px solid var(--us-border);\n border-radius: 10px;\n transition: border-color 140ms, background 140ms;\n animation: us-row-in 280ms cubic-bezier(0.16, 1, 0.3, 1) backwards;\n position: relative;\n}\n@keyframes us-row-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.us-file[data-state=\"done\"] { border-color: color-mix(in srgb, var(--us-success) 30%, var(--us-border)); }\n.us-file[data-state=\"failed\"] { border-color: color-mix(in srgb, var(--us-danger) 30%, var(--us-border)); }\n\n.us-file-thumb {\n width: 40px; height: 40px; flex-shrink: 0;\n border-radius: 8px;\n background: var(--us-subtle);\n background-size: cover; background-position: center;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--us-muted);\n overflow: hidden;\n}\n.us-file-thumb[data-image=\"true\"] { color: transparent; }\n.us-file-thumb svg { width: 18px; height: 18px; }\n\n.us-file-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }\n.us-file-row1 { display: flex; align-items: center; gap: 8px; }\n.us-file-name {\n font-size: 13px; font-weight: 500;\n flex: 1; min-width: 0;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n letter-spacing: -0.005em;\n}\n.us-file-meta { color: var(--us-muted); font-size: 11.5px; flex-shrink: 0; font-variant-numeric: tabular-nums; }\n\n.us-file-progress {\n height: 3px; background: var(--us-border); border-radius: 999px; overflow: hidden;\n position: relative;\n}\n.us-file-progress-bar {\n height: 100%; width: 0%;\n background: var(--us-primary);\n border-radius: inherit;\n transition: width 260ms cubic-bezier(0.4, 0.0, 0.2, 1);\n position: relative;\n}\n/* Shimmer overlay while uploading. Stops on terminal states. */\n.us-file[data-state=\"uploading\"] .us-file-progress-bar::after {\n content: \"\"; position: absolute; inset: 0;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n color-mix(in srgb, #fff 35%, transparent) 50%,\n transparent 100%\n );\n animation: us-shimmer 1.4s linear infinite;\n}\n@keyframes us-shimmer {\n from { transform: translateX(-100%); }\n to { transform: translateX(100%); }\n}\n.us-file[data-state=\"done\"] .us-file-progress-bar { width: 100% !important; background: var(--us-success); }\n.us-file[data-state=\"failed\"] .us-file-progress-bar { background: var(--us-danger); }\n\n.us-file-status {\n flex-shrink: 0;\n display: inline-flex; align-items: center; justify-content: center;\n width: 24px; height: 24px;\n color: var(--us-muted);\n}\n.us-file-status svg { width: 18px; height: 18px; }\n.us-file[data-state=\"done\"] .us-file-status { color: var(--us-success); animation: us-pop 320ms cubic-bezier(0.16, 1.4, 0.3, 1); }\n.us-file[data-state=\"failed\"] .us-file-status { color: var(--us-danger); animation: us-pop 320ms cubic-bezier(0.16, 1.4, 0.3, 1); }\n.us-file[data-state=\"uploading\"] .us-file-status { animation: us-spin 0.9s linear infinite; }\n@keyframes us-pop {\n from { transform: scale(0.5); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n@keyframes us-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n/* ──────────────────── actions / footer ──────────────────── */\n.us-actions {\n display: flex; gap: 8px; justify-content: space-between; align-items: center;\n padding: 12px 16px;\n border-top: 1px solid var(--us-border);\n}\n.us-actions-summary { font-size: 12px; color: var(--us-muted); font-variant-numeric: tabular-nums; }\n.us-actions-buttons { display: flex; gap: 8px; }\n\n.us-btn {\n appearance: none;\n display: inline-flex; align-items: center; justify-content: center; gap: 6px;\n padding: 8px 14px; min-height: 36px;\n border-radius: 8px; border: 1px solid var(--us-border);\n background: transparent; color: var(--us-fg);\n cursor: pointer; font-size: 13px; font-weight: 500;\n font-family: inherit; letter-spacing: -0.005em;\n transition: background 140ms, border-color 140ms, transform 80ms ease-out;\n}\n.us-btn:hover { background: var(--us-subtle); border-color: var(--us-border-strong); }\n.us-btn:active { transform: scale(0.98); }\n.us-btn:focus-visible { outline: 2px solid var(--us-primary); outline-offset: 2px; }\n.us-btn-primary {\n background: var(--us-primary); color: white;\n border-color: var(--us-primary);\n}\n.us-btn-primary:hover { filter: brightness(0.95); background: var(--us-primary); }\n.us-btn[disabled] { opacity: 0.5; cursor: not-allowed; }\n.us-btn[disabled]:hover { transform: none; }\n.us-btn svg { width: 14px; height: 14px; }\n\n.us-footer {\n padding: 8px 16px 12px;\n font-size: 11px; color: var(--us-muted); text-align: center;\n display: flex; align-items: center; justify-content: center; gap: 6px;\n}\n.us-footer svg { width: 11px; height: 11px; opacity: 0.7; }\n.us-footer a { color: var(--us-muted); text-decoration: none; font-weight: 500; }\n.us-footer a:hover { color: var(--us-fg); }\n\n/* ──────────────────── reduced motion ──────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .us-picker-backdrop,\n .us-picker,\n .us-file,\n .us-dropzone,\n .us-dropzone-icon,\n .us-btn,\n .us-file-status,\n .us-file-progress-bar { animation: none !important; transition: none !important; }\n .us-file[data-state=\"uploading\"] .us-file-progress-bar::after { animation: none; opacity: 0; }\n}\n\n/* ──────────────────── empty state niceties ──────────────────── */\n.us-file-list:empty { display: none; }\n`;\n","import type { UnionStackClient } from '../client.js';\nimport type { PickerConfig, UploadError } from '../types.js';\nimport type {\n PickResponse,\n PickedFile,\n PickerHandle,\n PickerOptions,\n UploadedFile,\n} from './types.js';\nimport { ensureStyles, themeToCssVars } from './styles.js';\n\n// Merge server-managed picker config with runtime options. Runtime options\n// always win — they're the explicit dev escape hatch.\nfunction mergeConfig(server: PickerConfig, runtime: PickerOptions): PickerOptions {\n const merged: PickerOptions = { ...runtime };\n\n // Branding: shallow merge, runtime wins per-field.\n const runtimeBranding = runtime.branding || {};\n merged.branding = {\n logoUrl: runtimeBranding.logoUrl ?? server.branding.logoUrl ?? undefined,\n title: runtimeBranding.title ?? server.branding.title ?? undefined,\n hideFooter: runtimeBranding.hideFooter ?? server.branding.hideFooter,\n // PickerBranding has no footerText today — keep server's value internal.\n };\n\n // Theme: shallow merge.\n const runtimeTheme = runtime.theme || {};\n merged.theme = {\n primary: runtimeTheme.primary ?? server.theme.primary ?? undefined,\n background: runtimeTheme.background ?? server.theme.background ?? undefined,\n foreground: runtimeTheme.foreground ?? server.theme.foreground ?? undefined,\n border: runtimeTheme.border ?? server.theme.border ?? undefined,\n radius: runtimeTheme.radius ?? server.theme.radius ?? undefined,\n mode: runtimeTheme.mode ?? server.theme.mode ?? undefined,\n };\n\n // Constraints inform the dropzone (accept attr, size cap).\n merged.maxFileSize = runtime.maxFileSize ?? server.constraints.maxFileSizeBytes;\n merged.maxFiles = runtime.maxFiles ?? server.constraints.maxFilesPerUpload;\n if (!runtime.accept && server.constraints.allowedMimeTypes?.length) {\n const types = server.constraints.allowedMimeTypes.filter(t => t !== '*/*');\n if (types.length > 0) merged.accept = types.join(',');\n }\n return merged;\n}\n\ntype FileItemState = 'queued' | 'uploading' | 'done' | 'failed' | 'cancelled';\n\ninterface FileItem {\n uploadId: string; // matches PickedFile.uploadId once described\n file: File;\n state: FileItemState;\n progress: number; // 0-100\n error?: string;\n uploaded?: UploadedFile;\n objectUrl?: string; // for image thumbnails (revoked on unmount)\n // DOM refs we mutate on progress.\n $row?: HTMLElement;\n $bar?: HTMLElement;\n $status?: HTMLElement;\n $meta?: HTMLElement;\n}\n\nconst DEFAULT_TITLE = 'Upload files';\nconst FOOTER_LINK = 'https://unionstack.mastersunion.link';\n\n// ──────────────────────────────────────────────────────────────────\n// Inline SVG icons. Single source — Lucide-style, 1.5px stroke, 24px\n// viewBox. Keeping them as string templates so the picker bundle has\n// no asset/image dependencies.\n// ──────────────────────────────────────────────────────────────────\nconst ICON = {\n upload: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><polyline points=\"17 8 12 3 7 8\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"/></svg>`,\n close: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`,\n check: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`,\n alert: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>`,\n spinner: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" opacity=\"0.2\"/><path d=\"M21 12a9 9 0 0 0-9-9\" stroke=\"currentColor\"/></svg>`,\n image: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/></svg>`,\n video: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"23 7 16 12 23 17 23 7\"/><rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\"/></svg>`,\n audio: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18V5l12-2v13\"/><circle cx=\"6\" cy=\"18\" r=\"3\"/><circle cx=\"18\" cy=\"16\" r=\"3\"/></svg>`,\n pdf: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"9\" y1=\"13\" x2=\"15\" y2=\"13\"/><line x1=\"9\" y1=\"17\" x2=\"13\" y2=\"17\"/></svg>`,\n archive: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"5\" rx=\"2\"/><path d=\"M4 9v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9\"/><line x1=\"10\" y1=\"13\" x2=\"14\" y2=\"13\"/></svg>`,\n file: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/></svg>`,\n zap: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"/></svg>`,\n};\n\nfunction iconForMime(mime: string): string {\n if (!mime) return ICON.file;\n if (mime.startsWith('image/')) return ICON.image;\n if (mime.startsWith('video/')) return ICON.video;\n if (mime.startsWith('audio/')) return ICON.audio;\n if (mime === 'application/pdf') return ICON.pdf;\n if (\n mime.startsWith('application/zip') ||\n mime.includes('compressed') ||\n mime === 'application/x-tar' ||\n mime === 'application/gzip'\n ) return ICON.archive;\n return ICON.file;\n}\n\n/**\n * Single-shot file picker modal. Built imperatively (no framework) so it can\n * be lazy-loaded by either the vanilla SDK or the React wrapper.\n */\nexport class Picker {\n private $backdrop: HTMLElement | null = null;\n private $list: HTMLElement | null = null;\n private $confirm: HTMLButtonElement | null = null;\n private $cancel: HTMLButtonElement | null = null;\n private $closeBtn: HTMLButtonElement | null = null;\n private $input: HTMLInputElement | null = null;\n\n private items: FileItem[] = [];\n private abortCtrl = new AbortController();\n private uploadStarted = false;\n private resolved = false;\n private resolvePromise!: (r: PickResponse) => void;\n private donePromise: Promise<PickResponse>;\n\n constructor(\n private client: UnionStackClient,\n private opts: PickerOptions,\n ) {\n this.donePromise = new Promise<PickResponse>(res => { this.resolvePromise = res; });\n }\n\n // ---- public api ---------------------------------------------------------\n\n async open(): Promise<PickResponse> {\n if (typeof document === 'undefined') {\n throw new Error('[union-stack] Picker requires a browser environment.');\n }\n // Pull server-side branding/theme defaults before painting the modal.\n // Runtime opts win over server config — see mergeConfig below.\n try {\n const serverConfig = await this.client.pickerConfigPromise;\n if (serverConfig) this.opts = mergeConfig(serverConfig, this.opts);\n } catch { /* fall through with whatever opts the caller passed */ }\n\n ensureStyles();\n this.mount();\n this.opts.onOpen?.();\n return this.donePromise;\n }\n\n close(): void {\n this.unmount();\n // Resolve with whatever was collected so callers awaiting open() never hang.\n if (!this.resolved) this.resolveResult();\n }\n\n cancel(): void {\n this.abortCtrl.abort();\n this.opts.onCancel?.();\n this.close();\n }\n\n // ---- mount / dom --------------------------------------------------------\n\n private $summary: HTMLElement | null = null;\n\n private mount() {\n const root = document.createElement('div');\n root.className = 'us-picker-backdrop';\n Object.entries(themeToCssVars(this.opts.theme)).forEach(([k, v]) => {\n root.style.setProperty(k, v);\n });\n root.addEventListener('click', e => {\n if (e.target === root && !this.uploadStarted) this.cancel();\n });\n\n const panel = el('div', 'us-picker');\n\n // ─── Header ────────────────────────────────────────────────────\n const header = el('div', 'us-picker-header');\n const logoWrap = el('div', 'us-picker-header-logo');\n if (this.opts.branding?.logoUrl) {\n const logo = document.createElement('img');\n logo.src = this.opts.branding.logoUrl;\n logo.alt = '';\n logoWrap.appendChild(logo);\n } else {\n logoWrap.innerHTML = ICON.zap;\n }\n header.appendChild(logoWrap);\n\n const title = el('div', 'us-picker-title', this.opts.branding?.title ?? DEFAULT_TITLE);\n header.appendChild(title);\n\n this.$closeBtn = document.createElement('button');\n this.$closeBtn.type = 'button';\n this.$closeBtn.className = 'us-picker-close';\n this.$closeBtn.setAttribute('aria-label', 'Close');\n this.$closeBtn.innerHTML = ICON.close;\n this.$closeBtn.onclick = () => this.cancel();\n header.appendChild(this.$closeBtn);\n panel.appendChild(header);\n\n // ─── Body ──────────────────────────────────────────────────────\n const body = el('div', 'us-picker-body');\n body.appendChild(this.renderDropzone());\n this.$list = el('div', 'us-file-list');\n body.appendChild(this.$list);\n panel.appendChild(body);\n\n // ─── Actions ───────────────────────────────────────────────────\n const autoUpload = this.opts.autoUpload !== false;\n const actions = el('div', 'us-actions');\n\n this.$summary = el('div', 'us-actions-summary', '');\n actions.appendChild(this.$summary);\n\n const buttons = el('div', 'us-actions-buttons');\n this.$cancel = document.createElement('button');\n this.$cancel.type = 'button';\n this.$cancel.className = 'us-btn';\n this.$cancel.textContent = 'Cancel';\n this.$cancel.onclick = () => this.cancel();\n buttons.appendChild(this.$cancel);\n\n if (!autoUpload) {\n this.$confirm = document.createElement('button');\n this.$confirm.type = 'button';\n this.$confirm.className = 'us-btn us-btn-primary';\n this.$confirm.innerHTML = `${ICON.upload} <span>Upload</span>`;\n this.$confirm.disabled = true;\n this.$confirm.onclick = () => this.startUpload();\n buttons.appendChild(this.$confirm);\n }\n actions.appendChild(buttons);\n panel.appendChild(actions);\n\n // ─── Footer ────────────────────────────────────────────────────\n if (!this.opts.branding?.hideFooter) {\n const footer = el('div', 'us-footer');\n footer.innerHTML =\n `${ICON.zap} <span>Powered by <a href=\"${FOOTER_LINK}\" target=\"_blank\" rel=\"noopener\">UnionStack</a></span>`;\n panel.appendChild(footer);\n }\n\n root.appendChild(panel);\n (this.opts.container ?? document.body).appendChild(root);\n this.$backdrop = root;\n }\n\n private renderDropzone(): HTMLElement {\n const dz = el('div', 'us-dropzone');\n dz.setAttribute('role', 'button');\n dz.setAttribute('tabindex', '0');\n dz.setAttribute('aria-label', 'Drop files here or click to browse');\n\n const icon = el('div', 'us-dropzone-icon');\n icon.innerHTML = ICON.upload;\n dz.appendChild(icon);\n\n dz.appendChild(el('div', 'us-dropzone-title', 'Drop files to upload'));\n dz.appendChild(el('div', 'us-dropzone-hint', 'or click to browse from your device'));\n\n // Constraints line — surfaces max file size + accepted types so users\n // know the rules before they pick something that gets rejected.\n const constraintBits: string[] = [];\n if (this.opts.maxFileSize) constraintBits.push(`max ${formatBytes(this.opts.maxFileSize)}`);\n if (this.opts.accept) {\n const types = this.opts.accept\n .split(',')\n .map(s => s.trim())\n .filter(s => s && s !== '*/*')\n .map(s => s.replace('/*', ''));\n if (types.length > 0 && types.length <= 4) {\n constraintBits.push(types.join(' · '));\n }\n }\n if (constraintBits.length > 0) {\n dz.appendChild(el('div', 'us-dropzone-constraints', constraintBits.join(' · ')));\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = (this.opts.maxFiles ?? 10) > 1;\n if (this.opts.accept) input.accept = this.opts.accept;\n input.style.display = 'none';\n input.onchange = () => {\n if (input.files) this.addFiles(Array.from(input.files));\n input.value = '';\n };\n this.$input = input;\n dz.appendChild(input);\n\n dz.onclick = () => input.click();\n dz.onkeydown = e => {\n if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); input.click(); }\n };\n\n dz.addEventListener('dragover', e => {\n e.preventDefault();\n dz.setAttribute('data-drag', 'over');\n });\n dz.addEventListener('dragleave', () => dz.removeAttribute('data-drag'));\n dz.addEventListener('drop', e => {\n e.preventDefault();\n dz.removeAttribute('data-drag');\n const dropped = e.dataTransfer?.files;\n if (dropped) this.addFiles(Array.from(dropped));\n });\n\n return dz;\n }\n\n private unmount() {\n if (this.$backdrop?.parentNode) this.$backdrop.parentNode.removeChild(this.$backdrop);\n this.$backdrop = null;\n // Release any image-thumbnail object URLs we created.\n for (const item of this.items) {\n if (item.objectUrl) URL.revokeObjectURL(item.objectUrl);\n }\n this.opts.onClose?.();\n }\n\n // ---- file selection -----------------------------------------------------\n\n private addFiles(files: File[]) {\n const cap = this.opts.maxFiles ?? Infinity;\n const remaining = cap - this.items.length;\n if (remaining <= 0) return;\n const chosen = files.slice(0, remaining);\n\n for (const file of chosen) {\n if (this.opts.maxFileSize && file.size > this.opts.maxFileSize) {\n // Skip the file but surface a row in the list so the user sees why.\n const item: FileItem = {\n uploadId: cryptoId(),\n file, state: 'failed', progress: 0,\n error: `File exceeds ${formatBytes(this.opts.maxFileSize)} limit`,\n };\n this.items.push(item);\n this.renderItem(item);\n continue;\n }\n\n const item: FileItem = {\n uploadId: cryptoId(),\n file, state: 'queued', progress: 0,\n };\n this.items.push(item);\n this.renderItem(item);\n }\n\n this.refreshConfirm();\n\n // Auto-upload: kick off as soon as the selection is complete. Deferred a\n // frame so the just-added rows render before \"uploading…\" status flips on.\n const autoUpload = this.opts.autoUpload !== false;\n const hasQueued = this.items.some(i => i.state === 'queued');\n if (autoUpload && hasQueued && !this.uploadStarted) {\n requestAnimationFrame(() => {\n if (!this.uploadStarted) this.startUpload();\n });\n }\n }\n\n private renderItem(item: FileItem) {\n if (!this.$list) return;\n\n const row = el('div', 'us-file');\n row.dataset.state = item.state;\n row.dataset.uploadId = item.uploadId;\n // Stagger entrance so multiple files don't all pop in at once. Cap delay\n // so a 50-file drop doesn't take forever to fully render.\n const idx = Math.min(this.items.length - 1, 8);\n row.style.animationDelay = `${idx * 35}ms`;\n\n // Thumbnail: image preview for image MIMEs, type-specific icon otherwise.\n const thumb = el('div', 'us-file-thumb');\n if (item.file.type.startsWith('image/') && typeof URL !== 'undefined' && URL.createObjectURL) {\n try {\n const objectUrl = URL.createObjectURL(item.file);\n item.objectUrl = objectUrl;\n thumb.style.backgroundImage = `url(\"${objectUrl}\")`;\n thumb.dataset.image = 'true';\n } catch {\n thumb.innerHTML = iconForMime(item.file.type);\n }\n } else {\n thumb.innerHTML = iconForMime(item.file.type);\n }\n row.appendChild(thumb);\n\n // Main column: name + meta (with progress bar tucked under)\n const main = el('div', 'us-file-main');\n\n const row1 = el('div', 'us-file-row1');\n row1.appendChild(el('div', 'us-file-name', item.file.name));\n const meta = el('div', 'us-file-meta', formatBytes(item.file.size));\n row1.appendChild(meta);\n main.appendChild(row1);\n\n const progress = el('div', 'us-file-progress');\n const bar = el('div', 'us-file-progress-bar');\n progress.appendChild(bar);\n main.appendChild(progress);\n\n row.appendChild(main);\n\n // Status icon (spinner / check / alert)\n const status = el('div', 'us-file-status');\n status.setAttribute('aria-label', this.statusLabel(item));\n status.innerHTML = this.statusIcon(item.state);\n row.appendChild(status);\n\n item.$row = row;\n item.$bar = bar;\n item.$status = status;\n item.$meta = meta;\n\n this.$list.appendChild(row);\n this.updateSummary();\n }\n\n private statusIcon(state: FileItemState): string {\n switch (state) {\n case 'uploading': return ICON.spinner;\n case 'done': return ICON.check;\n case 'failed': return ICON.alert;\n case 'cancelled': return ICON.alert;\n default: return ICON.spinner; // queued — also spinner (waiting)\n }\n }\n\n private statusLabel(item: FileItem): string {\n switch (item.state) {\n case 'queued': return 'Waiting to upload';\n case 'uploading': return `Uploading ${Math.round(item.progress)} percent`;\n case 'done': return 'Upload complete';\n case 'failed': return item.error ? `Failed: ${item.error}` : 'Upload failed';\n case 'cancelled': return 'Cancelled';\n }\n }\n\n private setItemState(item: FileItem, state: FileItemState, progress?: number) {\n item.state = state;\n if (progress !== undefined) item.progress = progress;\n if (item.$row) item.$row.dataset.state = state;\n if (item.$bar) item.$bar.style.width = `${item.progress}%`;\n if (item.$status) {\n item.$status.innerHTML = this.statusIcon(state);\n item.$status.setAttribute('aria-label', this.statusLabel(item));\n }\n if (item.$meta) {\n // Augment the meta line with live state — keeps the eye on a single spot\n // for \"what's happening\" without adding another text row.\n const size = formatBytes(item.file.size);\n switch (state) {\n case 'uploading':\n item.$meta.textContent = `${size} · ${Math.round(item.progress)}%`;\n break;\n case 'done':\n item.$meta.textContent = size;\n break;\n case 'failed':\n item.$meta.textContent = item.error || 'Failed';\n break;\n default:\n item.$meta.textContent = size;\n }\n }\n this.updateSummary();\n }\n\n private updateSummary() {\n if (!this.$summary) return;\n const total = this.items.length;\n if (total === 0) { this.$summary.textContent = ''; return; }\n const done = this.items.filter(i => i.state === 'done').length;\n const failed = this.items.filter(i => i.state === 'failed').length;\n const active = this.items.filter(i => i.state === 'uploading' || i.state === 'queued').length;\n if (active > 0) {\n this.$summary.textContent = `Uploading ${done + 1} of ${total}`;\n } else if (failed > 0) {\n this.$summary.textContent = `${done} of ${total} uploaded · ${failed} failed`;\n } else if (done === total) {\n this.$summary.textContent = `${total} file${total === 1 ? '' : 's'} uploaded`;\n } else {\n this.$summary.textContent = `${total} file${total === 1 ? '' : 's'} ready`;\n }\n }\n\n private refreshConfirm() {\n if (!this.$confirm) return;\n const queued = this.items.filter(i => i.state === 'queued').length;\n this.$confirm.disabled = queued === 0 || this.uploadStarted;\n }\n\n // ---- upload -------------------------------------------------------------\n\n private async startUpload() {\n if (this.uploadStarted) return;\n const queued = this.items.filter(i => i.state === 'queued');\n if (queued.length === 0) return;\n\n this.uploadStarted = true;\n if (this.$confirm) {\n this.$confirm.disabled = true;\n this.$confirm.textContent = 'Uploading…';\n }\n if (this.$cancel) this.$cancel.textContent = 'Stop';\n if (this.$closeBtn) this.$closeBtn.disabled = true;\n if (this.$input) this.$input.disabled = true;\n\n // Map PickedFile.uploadId → FileItem so callbacks update the right row.\n const itemByUploadId = new Map<string, FileItem>();\n const filesToUpload = queued.map(i => i.file);\n\n try {\n await this.client.uploadMany(filesToUpload, {\n ...this.opts,\n signal: this.abortCtrl.signal,\n onUploadStarted: (pickedFiles: PickedFile[]) => {\n // Pair each PickedFile to the queued FileItem in order.\n pickedFiles.forEach((p, idx) => {\n const item = queued[idx];\n if (item) {\n item.uploadId = p.uploadId;\n if (item.$row) item.$row.dataset.uploadId = p.uploadId;\n itemByUploadId.set(p.uploadId, item);\n }\n });\n this.opts.onUploadStarted?.(pickedFiles);\n },\n onFileUploadStarted: p => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) this.setItemState(item, 'uploading', 0);\n this.opts.onFileUploadStarted?.(p);\n },\n onFileUploadProgress: (p, ev) => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) this.setItemState(item, 'uploading', ev.totalPercent);\n this.opts.onFileUploadProgress?.(p, ev);\n },\n onFileUploadFinished: f => {\n const item = itemByUploadId.get(f.uploadId);\n if (item) {\n item.uploaded = f;\n this.setItemState(item, 'done', 100);\n }\n this.opts.onFileUploadFinished?.(f);\n },\n onFileUploadFailed: (p, err) => {\n const item = itemByUploadId.get(p.uploadId);\n if (item) {\n item.error = err.message;\n this.setItemState(item, 'failed');\n }\n this.opts.onFileUploadFailed?.(p, err);\n },\n onUploadDone: r => {\n this.opts.onUploadDone?.(r);\n this.resolveResult(r);\n this.unmount();\n },\n onError: (err: UploadError) => {\n this.opts.onError?.(err);\n this.resolveResult();\n this.unmount();\n },\n });\n } catch {\n // Errors already surfaced via onError / onFileUploadFailed.\n if (!this.resolved) {\n this.resolveResult();\n this.unmount();\n }\n }\n }\n\n private resolveResult(result?: PickResponse) {\n if (this.resolved) return;\n this.resolved = true;\n const fallback: PickResponse = result ?? {\n filesUploaded: this.items.filter(i => i.uploaded).map(i => i.uploaded!),\n filesFailed: this.items\n .filter(i => i.state === 'failed')\n .map(i => ({\n file: {\n uploadId: i.uploadId,\n filename: i.file.name,\n mimetype: i.file.type || 'application/octet-stream',\n size: i.file.size,\n source: 'local',\n },\n error: {\n code: 'VALIDATION',\n message: i.error || 'failed',\n retryable: false,\n },\n })),\n };\n this.resolvePromise(fallback);\n }\n}\n\n// ---- helpers --------------------------------------------------------------\n\nfunction el(tag: string, className: string, text?: string): HTMLElement {\n const node = document.createElement(tag);\n if (className) node.className = className;\n if (text !== undefined) node.textContent = text;\n return node;\n}\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;\n return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;\n}\n\nfunction cryptoId(): string {\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\nexport function openPicker(client: UnionStackClient, opts: PickerOptions): PickerHandle {\n const picker = new Picker(client, opts);\n return {\n open: () => picker.open(),\n close: () => picker.close(),\n cancel: () => picker.cancel(),\n };\n}\n","export { Picker, openPicker } from './picker.js';\nexport type {\n PickerOptions,\n PickerHandle,\n PickerTheme,\n PickerBranding,\n} from './types.js';\n","// IIFE loader entry — bundled as a single drop-in <script>.\n//\n// <script src=\"https://unionstack.mastersunion.link/_sdk/v1/loader.js\"></script>\n// <script>\n// const client = UnionStack.init({ apiKey: 'unionstack_live_…', apiBase: '…' });\n// client.picker({ onUploadDone: r => console.log(r) }).open();\n// </script>\n//\n// Everything (core + picker UI) ships in this single file. The /react entry\n// is intentionally not included here — React users install from npm.\n\nimport { UnionStack, UnionStackClient } from '../index.js';\nimport { Picker, openPicker } from '../picker/index.js';\nimport type { ClientConfig } from '../types.js';\n\n// tsup's IIFE wrapper attaches every named export as a property on the\n// global `UnionStack`. To make `UnionStack.init({...})` work directly (rather\n// than `UnionStack.UnionStack.init(...)`), we flatten `init` to a top-level\n// export and keep the constructor classes available for advanced users.\nconst init = UnionStack.init.bind(UnionStack);\nexport { init, UnionStackClient, Picker, openPicker };\n\nexport type { ClientConfig };\n\n// Auto-init via data attribute — wire the loader without any inline script:\n//\n// <script src=\".../loader.js\" data-unionstack-key=\"unionstack_live_…\"></script>\n//\n// The resulting client lands on `window.UnionStack.client`.\ndeclare global {\n interface Window {\n UnionStack?: {\n init: typeof UnionStack.init;\n client?: UnionStackClient;\n };\n }\n}\n\n(function autoInit() {\n if (typeof document === 'undefined') return;\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return;\n const apiKey = script.getAttribute('data-unionstack-key');\n if (!apiKey) return;\n try {\n const client = UnionStack.init({ apiKey });\n queueMicrotask(() => {\n if (window.UnionStack) window.UnionStack.client = client;\n });\n } catch (err) {\n console.error('[UnionStack] auto-init failed:', err);\n }\n})();\n","import type { UploadError, UploadErrorCode } from './types.js';\n\nexport function makeError(\n code: UploadErrorCode,\n message: string,\n opts: { status?: number; retryable?: boolean; cause?: unknown } = {}\n): UploadError {\n return {\n code,\n message,\n status: opts.status,\n retryable: opts.retryable ?? defaultRetryable(code, opts.status),\n cause: opts.cause,\n };\n}\n\nfunction defaultRetryable(code: UploadErrorCode, status?: number): boolean {\n if (code === 'NETWORK' || code === 'PART_FAILED') return true;\n if (code === 'SERVER' && status && status >= 500) return true;\n return false;\n}\n\n/** Map an HTTP error response from the cdn-be API to an UploadError. */\nexport function fromApiResponse(status: number, body: unknown): UploadError {\n const err = (body as { error?: { code?: string; message?: string } } | null)?.error;\n const msg = err?.message || `Request failed with status ${status}`;\n const code = (err?.code || '').toUpperCase();\n\n if (status === 401) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 403) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 413) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 415) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 429) {\n const isQuota = code === 'QUOTA_EXCEEDED';\n return makeError(isQuota ? 'QUOTA' : 'NETWORK', msg, { status, retryable: !isQuota });\n }\n if (status >= 500) {\n return makeError('SERVER', msg, { status, retryable: true });\n }\n return makeError('SERVER', msg, { status, retryable: false });\n}\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError } from './errors.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 etag?: string;\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 /**\n * Upload a single Blob/File. Returns the persisted UploadedFile.\n * Fires Filestack-style per-file callbacks from `opts`.\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 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 status: 'Stored',\n etag: completed.etag,\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 },\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","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://cdn-api.mastersunion.org/cdn-api';\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\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 if (!cfg.apiKey) throw makeError('CONFIG', 'apiKey is required.', { retryable: false });\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = this.resolvedCfg.skipConfigPrefetch\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig().catch(() => null);\n }\n\n /** Upload a single file. Mirrors Filestack's `client.upload()`. */\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n return this.uploader.upload(file, opts);\n }\n\n /**\n * Upload multiple files concurrently. Mirrors Filestack's batch behavior:\n * onUploadDone fires once even if some files failed — failures land in\n * `filesFailed`, successes in `filesUploaded`. `onError` is reserved for\n * batch-level failures (no files even started).\n */\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\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 // Process per-file in parallel; the per-part concurrency from `opts` still\n // applies inside each upload.\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 /**\n * Open the file picker modal. Lazy-loads the picker bundle so the core\n * SDK stays small for callers that only use `upload()` directly.\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 opened = true;\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, opts);\n const result = await real.open();\n pendingResolve(result);\n return result;\n } catch (err) {\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","import { UnionStackClient } from './client.js';\nimport type { ClientConfig } from './types.js';\n\nexport const UnionStack = {\n init(cfg: ClientConfig): UnionStackClient {\n return new UnionStackClient(cfg);\n },\n};\n\nexport { UnionStackClient } from './client.js';\nexport type {\n ClientConfig,\n UploadOptions,\n BatchUploadOptions,\n PickedFile,\n UploadedFile,\n ProgressEvent,\n PickResponse,\n UploadError,\n UploadErrorCode,\n Source,\n} from './types.js';\n"],"mappings":"y0BAKO,SAASA,IAAqB,CAEnC,GADI,OAAO,UAAa,aACpB,SAAS,eAAeC,EAAQ,EAAG,OACvC,IAAMC,EAAK,SAAS,cAAc,OAAO,EACzCA,EAAG,GAAKD,GACRC,EAAG,YAAcC,GACjB,SAAS,KAAK,YAAYD,CAAE,CAC9B,CAGO,SAASE,GAAeC,EAAwD,CAfvF,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAiBE,IAAMC,IADON,GAAA,YAAAA,EAAO,OAAQ,WACF,OAASO,GAAgBC,GACnD,MAAO,CACL,gBAAmBP,EAAAD,GAAA,YAAAA,EAAO,UAAP,KAAAC,EAAqBK,EAAS,QACjD,WAAmBJ,EAAAF,GAAA,YAAAA,EAAO,aAAP,KAAAE,EAAqBI,EAAS,WACjD,WAAmBH,EAAAH,GAAA,YAAAA,EAAO,aAAP,KAAAG,EAAqBG,EAAS,WACjD,aAAmBA,EAAS,MAC5B,cAAmBA,EAAS,OAC5B,eAAmBF,EAAAJ,GAAA,YAAAA,EAAO,SAAP,KAAAI,EAAqBE,EAAS,OACjD,qBAAsBA,EAAS,aAC/B,gBAAmBA,EAAS,SAC5B,eAAmBA,EAAS,QAC5B,cAAmBA,EAAS,OAC5B,eAAmBD,EAAAL,GAAA,YAAAA,EAAO,SAAP,KAAAK,EAAqB,MAC1C,CACF,CA/BA,IAEMT,GAiCAY,GAaAD,GAeAT,GA/DNW,GAAAC,EAAA,kBAEMd,GAAW,2BAiCXY,GAAiB,CACrB,QAAc,UACd,WAAc,UACd,WAAc,UACd,MAAc,UACd,OAAc,UACd,OAAc,UACd,aAAc,UACd,SAAc,UACd,QAAc,UACd,OAAc,SAChB,EAEMD,GAAgB,CACpB,QAAc,UACd,WAAc,UACd,WAAc,UACd,MAAc,UACd,OAAc,UACd,OAAc,UACd,aAAc,UACd,SAAc,UACd,QAAc,UACd,OAAc,SAChB,EAIMT,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IClDjB,SAASa,GAAYC,EAAsBC,EAAuC,CAblF,I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","names":["ensureStyles","STYLE_ID","el","BASE_CSS","themeToCssVars","theme","_a","_b","_c","_d","_e","defaults","DARK_DEFAULTS","LIGHT_DEFAULTS","init_styles","__esmMin","mergeConfig","server","runtime","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","merged","__spreadValues","runtimeBranding","runtimeTheme","types","t","iconForMime","mime","ICON","el","tag","className","text","node","formatBytes","n","cryptoId","openPicker","client","opts","picker","Picker","DEFAULT_TITLE","FOOTER_LINK","init_picker","__esmMin","init_styles","res","serverConfig","e","ensureStyles","root","themeToCssVars","k","v","panel","header","logoWrap","logo","title","body","autoUpload","actions","buttons","footer","dz","icon","constraintBits","s","input","dropped","item","files","remaining","chosen","file","hasQueued","i","row","idx","thumb","objectUrl","main","row1","meta","progress","bar","status","state","size","total","done","failed","queued","itemByUploadId","filesToUpload","__spreadProps","pickedFiles","p","ev","f","err","r","result","fallback","picker_exports","__export","Picker","openPicker","init_picker","__esmMin","loader_exports","__export","Picker","UnionStackClient","init","openPicker","makeError","code","message","opts","_a","defaultRetryable","status","fromApiResponse","body","err","msg","isQuota","DEFAULT_CONCURRENCY","DEFAULT_MAX_RETRIES_PER_PART","BACKOFF_MS","Uploader","cfg","file","opts","isFile","filename","mimetype","cryptoRandomId","_a","_b","_c","picked","init","parts","completed","uploaded","__spreadProps","__spreadValues","rawErr","err","normalizeError","sessionId","totalParts","chunkSize","concurrency","maxRetries","urlByPart","p","results","loadedPerPart","cursor","totalBytes","reportProgress","loaded","a","b","totalPercent","ev","worker","_d","_e","makeError","partNumber","start","end","chunk","attempt","lastErr","url","res","etag","sleep","withSessionId","workers","e","method","path","body","signal","fetchImpl","cause","parsed","fromApiResponse","ms","r","msg","API_BASE","UnionStackClient","cfg","makeError","__spreadProps","__spreadValues","Uploader","file","opts","files","_a","_b","_c","err","picked","f","filesUploaded","filesFailed","i","uploaded","result","real","opened","pendingResolve","pendingReject","donePromise","res","rej","e","UnionStack","cfg","UnionStackClient","init_picker","init","UnionStack","script","apiKey","client","UnionStack","err"]}
|
|
@@ -342,5 +342,5 @@ var UnionStackClient = class {
|
|
|
342
342
|
};
|
|
343
343
|
|
|
344
344
|
exports.UnionStackClient = UnionStackClient;
|
|
345
|
-
//# sourceMappingURL=chunk-
|
|
346
|
-
//# sourceMappingURL=chunk-
|
|
345
|
+
//# sourceMappingURL=chunk-GJ2ORKJM.cjs.map
|
|
346
|
+
//# sourceMappingURL=chunk-GJ2ORKJM.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/uploader.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-445C5G3Q.cjs","sourcesContent":["import type { UploadError, UploadErrorCode } from './types.js';\n\nexport function makeError(\n code: UploadErrorCode,\n message: string,\n opts: { status?: number; retryable?: boolean; cause?: unknown } = {}\n): UploadError {\n return {\n code,\n message,\n status: opts.status,\n retryable: opts.retryable ?? defaultRetryable(code, opts.status),\n cause: opts.cause,\n };\n}\n\nfunction defaultRetryable(code: UploadErrorCode, status?: number): boolean {\n if (code === 'NETWORK' || code === 'PART_FAILED') return true;\n if (code === 'SERVER' && status && status >= 500) return true;\n return false;\n}\n\n/** Map an HTTP error response from the cdn-be API to an UploadError. */\nexport function fromApiResponse(status: number, body: unknown): UploadError {\n const err = (body as { error?: { code?: string; message?: string } } | null)?.error;\n const msg = err?.message || `Request failed with status ${status}`;\n const code = (err?.code || '').toUpperCase();\n\n if (status === 401) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 403) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 413) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 415) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 429) {\n const isQuota = code === 'QUOTA_EXCEEDED';\n return makeError(isQuota ? 'QUOTA' : 'NETWORK', msg, { status, retryable: !isQuota });\n }\n if (status >= 500) {\n return makeError('SERVER', msg, { status, retryable: true });\n }\n return makeError('SERVER', msg, { status, retryable: false });\n}\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError } from './errors.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 etag?: string;\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 /**\n * Upload a single Blob/File. Returns the persisted UploadedFile.\n * Fires Filestack-style per-file callbacks from `opts`.\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 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 status: 'Stored',\n etag: completed.etag,\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 },\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","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://cdn-api.mastersunion.org/cdn-api';\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\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 if (!cfg.apiKey) throw makeError('CONFIG', 'apiKey is required.', { retryable: false });\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = this.resolvedCfg.skipConfigPrefetch\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig().catch(() => null);\n }\n\n /** Upload a single file. Mirrors Filestack's `client.upload()`. */\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n return this.uploader.upload(file, opts);\n }\n\n /**\n * Upload multiple files concurrently. Mirrors Filestack's batch behavior:\n * onUploadDone fires once even if some files failed — failures land in\n * `filesFailed`, successes in `filesUploaded`. `onError` is reserved for\n * batch-level failures (no files even started).\n */\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\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 // Process per-file in parallel; the per-part concurrency from `opts` still\n // applies inside each upload.\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 /**\n * Open the file picker modal. Lazy-loads the picker bundle so the core\n * SDK stays small for callers that only use `upload()` directly.\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 opened = true;\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, opts);\n const result = await real.open();\n pendingResolve(result);\n return result;\n } catch (err) {\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
|
+
{"version":3,"sources":["../src/errors.ts","../src/uploader.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-GJ2ORKJM.cjs","sourcesContent":["import type { UploadError, UploadErrorCode } from './types.js';\n\nexport function makeError(\n code: UploadErrorCode,\n message: string,\n opts: { status?: number; retryable?: boolean; cause?: unknown } = {}\n): UploadError {\n return {\n code,\n message,\n status: opts.status,\n retryable: opts.retryable ?? defaultRetryable(code, opts.status),\n cause: opts.cause,\n };\n}\n\nfunction defaultRetryable(code: UploadErrorCode, status?: number): boolean {\n if (code === 'NETWORK' || code === 'PART_FAILED') return true;\n if (code === 'SERVER' && status && status >= 500) return true;\n return false;\n}\n\n/** Map an HTTP error response from the cdn-be API to an UploadError. */\nexport function fromApiResponse(status: number, body: unknown): UploadError {\n const err = (body as { error?: { code?: string; message?: string } } | null)?.error;\n const msg = err?.message || `Request failed with status ${status}`;\n const code = (err?.code || '').toUpperCase();\n\n if (status === 401) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 403) {\n return makeError('AUTH', msg, { status, retryable: false });\n }\n if (status === 413) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 415) {\n return makeError('VALIDATION', msg, { status, retryable: false });\n }\n if (status === 429) {\n const isQuota = code === 'QUOTA_EXCEEDED';\n return makeError(isQuota ? 'QUOTA' : 'NETWORK', msg, { status, retryable: !isQuota });\n }\n if (status >= 500) {\n return makeError('SERVER', msg, { status, retryable: true });\n }\n return makeError('SERVER', msg, { status, retryable: false });\n}\n","import type {\n ResolvedClientConfig,\n PickedFile,\n PickerConfig,\n UploadedFile,\n UploadOptions,\n ProgressEvent as USProgressEvent,\n} from './types.js';\nimport { fromApiResponse, makeError } from './errors.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 etag?: string;\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 /**\n * Upload a single Blob/File. Returns the persisted UploadedFile.\n * Fires Filestack-style per-file callbacks from `opts`.\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 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 status: 'Stored',\n etag: completed.etag,\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 },\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","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://cdn-api.mastersunion.org/cdn-api';\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\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 if (!cfg.apiKey) throw makeError('CONFIG', 'apiKey is required.', { retryable: false });\n this.resolvedCfg = { ...cfg, apiBase: API_BASE };\n this.uploader = new Uploader(this.resolvedCfg);\n this.pickerConfigPromise = this.resolvedCfg.skipConfigPrefetch\n ? Promise.resolve(null)\n : this.uploader.fetchPickerConfig().catch(() => null);\n }\n\n /** Upload a single file. Mirrors Filestack's `client.upload()`. */\n upload(file: File | Blob, opts: UploadOptions = {}): Promise<UploadedFile> {\n return this.uploader.upload(file, opts);\n }\n\n /**\n * Upload multiple files concurrently. Mirrors Filestack's batch behavior:\n * onUploadDone fires once even if some files failed — failures land in\n * `filesFailed`, successes in `filesUploaded`. `onError` is reserved for\n * batch-level failures (no files even started).\n */\n async uploadMany(\n files: (File | Blob)[],\n opts: BatchUploadOptions = {},\n ): Promise<PickResponse> {\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 // Process per-file in parallel; the per-part concurrency from `opts` still\n // applies inside each upload.\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 /**\n * Open the file picker modal. Lazy-loads the picker bundle so the core\n * SDK stays small for callers that only use `upload()` directly.\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 opened = true;\n try {\n const mod = await import('./picker/index.js');\n real = mod.openPicker(this, opts);\n const result = await real.open();\n pendingResolve(result);\n return result;\n } catch (err) {\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"]}
|
|
@@ -340,5 +340,5 @@ var UnionStackClient = class {
|
|
|
340
340
|
};
|
|
341
341
|
|
|
342
342
|
export { UnionStackClient };
|
|
343
|
-
//# sourceMappingURL=chunk-
|
|
344
|
-
//# sourceMappingURL=chunk-
|
|
343
|
+
//# sourceMappingURL=chunk-YLAPR7HG.js.map
|
|
344
|
+
//# sourceMappingURL=chunk-YLAPR7HG.js.map
|