@uplift-io/uplift 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Uplift contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Uplift
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@uplift-io/uplift?color=0f766e)](https://www.npmjs.com/package/@uplift-io/uplift)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@uplift-io/uplift?color=2563eb)](https://www.npmjs.com/package/@uplift-io/uplift)
5
+ [![npm downloads total](https://img.shields.io/npm/dt/@uplift-io/uplift?color=7c3aed)](https://www.npmjs.com/package/@uplift-io/uplift)
6
+ [![CI](https://github.com/Itzfeminisce/uplift/actions/workflows/ci.yml/badge.svg)](https://github.com/Itzfeminisce/uplift/actions/workflows/ci.yml)
7
+ [![bundle size](https://img.shields.io/badge/bundle-measured%20locally-14b8a6)](https://github.com/Itzfeminisce/uplift/blob/main/docs/BUNDLE_SIZE.md)
8
+ [![license](https://img.shields.io/npm/l/@uplift-io/uplift)](https://github.com/Itzfeminisce/uplift/blob/main/LICENSE)
9
+
10
+ Dead-simple, type-safe file uploads for TypeScript applications.
11
+
12
+ Define upload routes once on the server. Get a typed client on the frontend.
13
+
14
+ ```ts
15
+ await upload.avatar(file);
16
+ await upload.gallery(files);
17
+ ```
18
+
19
+ ## Install
20
+
21
+ Install core plus the adapters you use:
22
+
23
+ ```bash
24
+ pnpm add @uplift-io/uplift @uplift-io/next @uplift-io/s3
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```ts
30
+ import { image, uplift } from "@uplift-io/uplift";
31
+ import { s3 } from "@uplift-io/s3";
32
+
33
+ export const uploads = uplift({
34
+ storage: s3({
35
+ bucket: process.env.S3_BUCKET!,
36
+ region: "us-east-1",
37
+ accessKeyId: process.env.S3_ACCESS_KEY_ID!,
38
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!
39
+ }),
40
+ routes: {
41
+ avatar: image()
42
+ .max("2mb")
43
+ .auth(async ({ req }) => ({ id: req.headers.get("x-user-id")! }))
44
+ .key(({ user }) => `avatars/${user.id}.png`)
45
+ .done(async ({ file }) => {
46
+ console.log(file.url);
47
+ }),
48
+ gallery: image().max("8mb").multiple(10)
49
+ }
50
+ });
51
+
52
+ export type Uploads = typeof uploads;
53
+ ```
54
+
55
+ ```ts
56
+ import { createUploadClient } from "@uplift-io/uplift/client";
57
+ import type { Uploads } from "./uploads";
58
+
59
+ export const upload = createUploadClient<Uploads>("/api/upload");
60
+
61
+ const avatar = await upload.avatar(file);
62
+ const gallery = await upload.gallery(fileList);
63
+ ```
64
+
65
+ ## More
66
+
67
+ - Full docs: [itzfeminisce.github.io/uplift](https://itzfeminisce.github.io/uplift/)
68
+ - Bundle size report: [docs/BUNDLE_SIZE.md](https://github.com/Itzfeminisce/uplift/blob/main/docs/BUNDLE_SIZE.md)
69
+ - Next local example: [examples/next-local](https://github.com/Itzfeminisce/uplift/tree/main/examples/next-local)
70
+ - GitHub: [github.com/Itzfeminisce/uplift](https://github.com/Itzfeminisce/uplift)
71
+ - License: MIT
72
+
73
+ ## Storage
74
+
75
+ Uplift publishes S3, R2, Bunny, Cloudinary, local, memory, and UploadThing-compatible adapters as separate packages. The UploadThing adapter accepts a server-side uploader compatible with `UTApi.uploadFiles()` and keeps UploadThing optional:
76
+
77
+ ```ts
78
+ import { uploadthing } from "@uplift-io/uploadthing";
79
+ import { UTApi } from "uploadthing/server";
80
+
81
+ const utapi = new UTApi();
82
+ const storage = uploadthing({
83
+ uploader: (file) => utapi.uploadFiles(file)
84
+ });
85
+ ```
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client.ts
21
+ var client_exports = {};
22
+ __export(client_exports, {
23
+ createUploadClient: () => createUploadClient
24
+ });
25
+ module.exports = __toCommonJS(client_exports);
26
+
27
+ // src/types.ts
28
+ var UploadError = class extends Error {
29
+ code;
30
+ constructor(code, message) {
31
+ super(message);
32
+ this.name = "UploadError";
33
+ this.code = code;
34
+ }
35
+ toJSON() {
36
+ return {
37
+ message: this.message,
38
+ code: this.code
39
+ };
40
+ }
41
+ };
42
+
43
+ // src/client.ts
44
+ function createUploadClient(baseUrl, options = {}) {
45
+ const fetcher = options.fetch ?? fetch;
46
+ return new Proxy({}, {
47
+ get(_target, property) {
48
+ if (typeof property !== "string") return void 0;
49
+ return async (input) => {
50
+ const files = input instanceof File ? [input] : Array.from(input);
51
+ const form = new FormData();
52
+ const field = files.length === 1 ? "file" : "files";
53
+ for (const file of files) form.append(field, file);
54
+ const url = routeUrl(baseUrl, property);
55
+ if (!options.fetch && typeof XMLHttpRequest !== "undefined") {
56
+ return uploadWithXhr(url, form, property, options.onProgress);
57
+ }
58
+ options.onProgress?.(property, 0);
59
+ const response = await fetcher(url, { method: "POST", body: form });
60
+ const body = await response.json();
61
+ if (!response.ok) {
62
+ throw new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed.");
63
+ }
64
+ options.onProgress?.(property, 100);
65
+ return body.result;
66
+ };
67
+ }
68
+ });
69
+ }
70
+ function routeUrl(baseUrl, route) {
71
+ const url = new URL(baseUrl, globalThis.location?.href ?? "http://localhost");
72
+ url.searchParams.set("route", route);
73
+ const value = url.toString();
74
+ return baseUrl.startsWith("/") ? `${url.pathname}${url.search}` : value;
75
+ }
76
+ function uploadWithXhr(url, form, route, onProgress) {
77
+ return new Promise((resolve, reject) => {
78
+ const xhr = new XMLHttpRequest();
79
+ xhr.open("POST", url);
80
+ xhr.upload.onprogress = (event) => {
81
+ if (!event.lengthComputable) return;
82
+ onProgress?.(route, Math.round(event.loaded / event.total * 100));
83
+ };
84
+ xhr.onload = () => {
85
+ const body = JSON.parse(xhr.responseText || "{}");
86
+ if (xhr.status < 200 || xhr.status >= 300) {
87
+ reject(new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed."));
88
+ return;
89
+ }
90
+ onProgress?.(route, 100);
91
+ resolve(body.result);
92
+ };
93
+ xhr.onerror = () => reject(new UploadError("UPLOAD_FAILED", "Upload request failed."));
94
+ onProgress?.(route, 0);
95
+ xhr.send(form);
96
+ });
97
+ }
98
+ // Annotate the CommonJS export names for ESM import in node:
99
+ 0 && (module.exports = {
100
+ createUploadClient
101
+ });
102
+ //# sourceMappingURL=client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/types.ts"],"sourcesContent":["import { UploadError, type UpliftApp, type UploadClient } from \"./types\";\r\n\r\nexport type UploadProgressHandler = (progress: number) => void;\r\n\r\nexport function createUploadClient<TApp extends UpliftApp>(\r\n baseUrl: string,\r\n options: { fetch?: typeof fetch; onProgress?: (route: string, progress: number) => void } = {}\r\n): UploadClient<TApp> {\r\n const fetcher = options.fetch ?? fetch;\r\n\r\n return new Proxy({}, {\r\n get(_target, property) {\r\n if (typeof property !== \"string\") return undefined;\r\n return async (input: File | File[] | FileList) => {\r\n const files = input instanceof File ? [input] : Array.from(input);\r\n const form = new FormData();\r\n const field = files.length === 1 ? \"file\" : \"files\";\r\n for (const file of files) form.append(field, file);\r\n\r\n const url = routeUrl(baseUrl, property);\r\n if (!options.fetch && typeof XMLHttpRequest !== \"undefined\") {\r\n return uploadWithXhr(url, form, property, options.onProgress);\r\n }\r\n\r\n options.onProgress?.(property, 0);\r\n const response = await fetcher(url, { method: \"POST\", body: form });\r\n const body = await response.json() as { result?: unknown; error?: { code: string; message: string } };\r\n if (!response.ok) {\r\n throw new UploadError((body.error?.code ?? \"UNKNOWN\") as never, body.error?.message ?? \"Upload failed.\");\r\n }\r\n options.onProgress?.(property, 100);\r\n return body.result;\r\n };\r\n }\r\n }) as UploadClient<TApp>;\r\n}\r\n\r\nfunction routeUrl(baseUrl: string, route: string): string {\r\n const url = new URL(baseUrl, globalThis.location?.href ?? \"http://localhost\");\r\n url.searchParams.set(\"route\", route);\r\n const value = url.toString();\r\n return baseUrl.startsWith(\"/\") ? `${url.pathname}${url.search}` : value;\r\n}\r\n\r\nfunction uploadWithXhr(\r\n url: string,\r\n form: FormData,\r\n route: string,\r\n onProgress?: (route: string, progress: number) => void\r\n): Promise<unknown> {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"POST\", url);\r\n xhr.upload.onprogress = (event) => {\r\n if (!event.lengthComputable) return;\r\n onProgress?.(route, Math.round((event.loaded / event.total) * 100));\r\n };\r\n xhr.onload = () => {\r\n const body = JSON.parse(xhr.responseText || \"{}\") as {\r\n result?: unknown;\r\n error?: { code: string; message: string };\r\n };\r\n if (xhr.status < 200 || xhr.status >= 300) {\r\n reject(new UploadError((body.error?.code ?? \"UNKNOWN\") as never, body.error?.message ?? \"Upload failed.\"));\r\n return;\r\n }\r\n onProgress?.(route, 100);\r\n resolve(body.result);\r\n };\r\n xhr.onerror = () => reject(new UploadError(\"UPLOAD_FAILED\", \"Upload request failed.\"));\r\n onProgress?.(route, 0);\r\n xhr.send(form);\r\n });\r\n}\r\n","export type SizeValue = `${number}b` | `${number}kb` | `${number}mb` | `${number}gb`;\r\nexport type DurationValue = `${number}s` | `${number}m` | `${number}h`;\r\n\r\nexport type UploadInputFile = {\r\n name: string;\r\n type: string;\r\n size: number;\r\n extension?: string;\r\n file?: File;\r\n};\r\n\r\nexport type UploadedFile = {\r\n url: string;\r\n key: string;\r\n name: string;\r\n type: string;\r\n size: number;\r\n extension?: string | undefined;\r\n provider: string;\r\n};\r\n\r\nexport type UploadErrorCode =\r\n | \"FILE_TOO_LARGE\"\r\n | \"FILE_TOO_SMALL\"\r\n | \"INVALID_TYPE\"\r\n | \"AUTH_FAILED\"\r\n | \"VALIDATION_FAILED\"\r\n | \"UPLOAD_FAILED\"\r\n | \"UNKNOWN\";\r\n\r\nexport class UploadError extends Error {\r\n readonly code: UploadErrorCode;\r\n\r\n constructor(code: UploadErrorCode, message: string) {\r\n super(message);\r\n this.name = \"UploadError\";\r\n this.code = code;\r\n }\r\n\r\n toJSON() {\r\n return {\r\n message: this.message,\r\n code: this.code\r\n };\r\n }\r\n}\r\n\r\nexport type StandardSchema<T = unknown> = {\r\n parse(input: unknown): T;\r\n};\r\n\r\nexport type KeyContext<TAuth = unknown, TMeta = unknown> = {\r\n req: Request;\r\n file: UploadInputFile;\r\n user: TAuth;\r\n meta: TMeta;\r\n};\r\n\r\nexport type DoneContext<\r\n TAuth = unknown,\r\n TMeta = unknown,\r\n TMultiple extends boolean = false\r\n> = TMultiple extends true\r\n ? { req: Request; files: UploadedFile[]; user: TAuth; meta: TMeta[] }\r\n : { req: Request; file: UploadedFile; user: TAuth; meta: TMeta };\r\n\r\nexport type StoragePutInput = {\r\n key: string;\r\n file: UploadInputFile;\r\n body: File;\r\n};\r\n\r\nexport type StorageAdapter = {\r\n provider: string;\r\n put(input: StoragePutInput): Promise<UploadedFile>;\r\n};\r\n\r\nexport type Middleware<TUser = unknown> = (ctx: { req: Request }) => TUser | Promise<TUser>;\r\n\r\nexport type UploadKind =\r\n | \"any\"\r\n | \"image\"\r\n | \"pdf\"\r\n | \"video\"\r\n | \"audio\"\r\n | \"text\"\r\n | \"json\"\r\n | \"csv\"\r\n | \"custom\";\r\n\r\nexport type UploadRouteDefinition = {\r\n kind: UploadKind;\r\n maxBytes?: number;\r\n minBytes?: number;\r\n multiple: boolean;\r\n multipleLimit?: number;\r\n auth?: Middleware<unknown>;\r\n overrideAuth: boolean;\r\n key?: (ctx: KeyContext<unknown, unknown>) => string | Promise<string>;\r\n meta?: (ctx: { req: Request; file: UploadInputFile; user: unknown }) => unknown | Promise<unknown>;\r\n validate?: (ctx: {\r\n req: Request;\r\n file: UploadInputFile;\r\n user: unknown;\r\n meta: unknown;\r\n }) => true | string | Promise<true | string>;\r\n done?: (ctx: DoneContext<unknown, unknown, boolean>) => void | Promise<void>;\r\n extensions?: string[];\r\n mimeTypes?: string[];\r\n dimensionRule?: { minWidth?: number; minHeight?: number; maxWidth?: number; maxHeight?: number };\r\n requireSquare?: boolean;\r\n aspectRatio?: `${number}:${number}`;\r\n encoding?: \"utf-8\" | \"utf-16\" | \"ascii\";\r\n schema?: StandardSchema;\r\n headers?: string[];\r\n delimiter?: \",\" | \";\" | \"\\t\" | \"|\";\r\n pageRule?: { min?: number; max?: number };\r\n encrypted?: boolean;\r\n durationRule?: { min?: DurationValue; max?: DurationValue };\r\n};\r\n\r\nexport type UploadRoutes = Record<string, { _def: UploadRouteDefinition }>;\r\n\r\nexport type UpliftApp<TRoutes extends UploadRoutes = UploadRoutes> = {\r\n storage: StorageAdapter;\r\n routes: TRoutes;\r\n middleware?: Middleware<unknown> | undefined;\r\n onUploadComplete?: ((ctx: {\r\n route: keyof TRoutes & string;\r\n result: UploadedFile | UploadedFile[];\r\n user: unknown;\r\n }) => void | Promise<void>) | undefined;\r\n};\r\n\r\nexport type IsMultiple<TRoute> = TRoute extends { __multiple?: infer TMultiple }\r\n ? TMultiple extends true\r\n ? true\r\n : false\r\n : false;\r\n\r\nexport type ClientInput<TRoute> = IsMultiple<TRoute> extends true ? File[] | FileList : File;\r\nexport type ClientOutput<TRoute> = IsMultiple<TRoute> extends true ? UploadedFile[] : UploadedFile;\r\n\r\nexport type UploadClient<TApp extends UpliftApp> = {\r\n [TRouteName in keyof TApp[\"routes\"] & string]: (\r\n input: ClientInput<TApp[\"routes\"][TRouteName]>\r\n ) => Promise<ClientOutput<TApp[\"routes\"][TRouteName]>>;\r\n};\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC8BO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC5B;AAAA,EAET,YAAY,MAAuB,SAAiB;AAClD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,SAAS;AACP,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;;;ADzCO,SAAS,mBACd,SACA,UAA4F,CAAC,GACzE;AACpB,QAAM,UAAU,QAAQ,SAAS;AAEjC,SAAO,IAAI,MAAM,CAAC,GAAG;AAAA,IACnB,IAAI,SAAS,UAAU;AACrB,UAAI,OAAO,aAAa,SAAU,QAAO;AACzC,aAAO,OAAO,UAAoC;AAChD,cAAM,QAAQ,iBAAiB,OAAO,CAAC,KAAK,IAAI,MAAM,KAAK,KAAK;AAChE,cAAM,OAAO,IAAI,SAAS;AAC1B,cAAM,QAAQ,MAAM,WAAW,IAAI,SAAS;AAC5C,mBAAW,QAAQ,MAAO,MAAK,OAAO,OAAO,IAAI;AAEjD,cAAM,MAAM,SAAS,SAAS,QAAQ;AACtC,YAAI,CAAC,QAAQ,SAAS,OAAO,mBAAmB,aAAa;AAC3D,iBAAO,cAAc,KAAK,MAAM,UAAU,QAAQ,UAAU;AAAA,QAC9D;AAEA,gBAAQ,aAAa,UAAU,CAAC;AAChC,cAAM,WAAW,MAAM,QAAQ,KAAK,EAAE,QAAQ,QAAQ,MAAM,KAAK,CAAC;AAClE,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,IAAI,YAAa,KAAK,OAAO,QAAQ,WAAqB,KAAK,OAAO,WAAW,gBAAgB;AAAA,QACzG;AACA,gBAAQ,aAAa,UAAU,GAAG;AAClC,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SAAS,SAAiB,OAAuB;AACxD,QAAM,MAAM,IAAI,IAAI,SAAS,WAAW,UAAU,QAAQ,kBAAkB;AAC5E,MAAI,aAAa,IAAI,SAAS,KAAK;AACnC,QAAM,QAAQ,IAAI,SAAS;AAC3B,SAAO,QAAQ,WAAW,GAAG,IAAI,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM,KAAK;AACpE;AAEA,SAAS,cACP,KACA,MACA,OACA,YACkB;AAClB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,eAAe;AAC/B,QAAI,KAAK,QAAQ,GAAG;AACpB,QAAI,OAAO,aAAa,CAAC,UAAU;AACjC,UAAI,CAAC,MAAM,iBAAkB;AAC7B,mBAAa,OAAO,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG,CAAC;AAAA,IACpE;AACA,QAAI,SAAS,MAAM;AACjB,YAAM,OAAO,KAAK,MAAM,IAAI,gBAAgB,IAAI;AAIhD,UAAI,IAAI,SAAS,OAAO,IAAI,UAAU,KAAK;AACzC,eAAO,IAAI,YAAa,KAAK,OAAO,QAAQ,WAAqB,KAAK,OAAO,WAAW,gBAAgB,CAAC;AACzG;AAAA,MACF;AACA,mBAAa,OAAO,GAAG;AACvB,cAAQ,KAAK,MAAM;AAAA,IACrB;AACA,QAAI,UAAU,MAAM,OAAO,IAAI,YAAY,iBAAiB,wBAAwB,CAAC;AACrF,iBAAa,OAAO,CAAC;AACrB,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;","names":[]}
@@ -0,0 +1,9 @@
1
+ import { g as UpliftApp, j as UploadClient } from './types-BdcszAj8.cjs';
2
+
3
+ type UploadProgressHandler = (progress: number) => void;
4
+ declare function createUploadClient<TApp extends UpliftApp>(baseUrl: string, options?: {
5
+ fetch?: typeof fetch;
6
+ onProgress?: (route: string, progress: number) => void;
7
+ }): UploadClient<TApp>;
8
+
9
+ export { type UploadProgressHandler, createUploadClient };
@@ -0,0 +1,9 @@
1
+ import { g as UpliftApp, j as UploadClient } from './types-BdcszAj8.js';
2
+
3
+ type UploadProgressHandler = (progress: number) => void;
4
+ declare function createUploadClient<TApp extends UpliftApp>(baseUrl: string, options?: {
5
+ fetch?: typeof fetch;
6
+ onProgress?: (route: string, progress: number) => void;
7
+ }): UploadClient<TApp>;
8
+
9
+ export { type UploadProgressHandler, createUploadClient };
package/dist/client.js ADDED
@@ -0,0 +1,75 @@
1
+ // src/types.ts
2
+ var UploadError = class extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "UploadError";
7
+ this.code = code;
8
+ }
9
+ toJSON() {
10
+ return {
11
+ message: this.message,
12
+ code: this.code
13
+ };
14
+ }
15
+ };
16
+
17
+ // src/client.ts
18
+ function createUploadClient(baseUrl, options = {}) {
19
+ const fetcher = options.fetch ?? fetch;
20
+ return new Proxy({}, {
21
+ get(_target, property) {
22
+ if (typeof property !== "string") return void 0;
23
+ return async (input) => {
24
+ const files = input instanceof File ? [input] : Array.from(input);
25
+ const form = new FormData();
26
+ const field = files.length === 1 ? "file" : "files";
27
+ for (const file of files) form.append(field, file);
28
+ const url = routeUrl(baseUrl, property);
29
+ if (!options.fetch && typeof XMLHttpRequest !== "undefined") {
30
+ return uploadWithXhr(url, form, property, options.onProgress);
31
+ }
32
+ options.onProgress?.(property, 0);
33
+ const response = await fetcher(url, { method: "POST", body: form });
34
+ const body = await response.json();
35
+ if (!response.ok) {
36
+ throw new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed.");
37
+ }
38
+ options.onProgress?.(property, 100);
39
+ return body.result;
40
+ };
41
+ }
42
+ });
43
+ }
44
+ function routeUrl(baseUrl, route) {
45
+ const url = new URL(baseUrl, globalThis.location?.href ?? "http://localhost");
46
+ url.searchParams.set("route", route);
47
+ const value = url.toString();
48
+ return baseUrl.startsWith("/") ? `${url.pathname}${url.search}` : value;
49
+ }
50
+ function uploadWithXhr(url, form, route, onProgress) {
51
+ return new Promise((resolve, reject) => {
52
+ const xhr = new XMLHttpRequest();
53
+ xhr.open("POST", url);
54
+ xhr.upload.onprogress = (event) => {
55
+ if (!event.lengthComputable) return;
56
+ onProgress?.(route, Math.round(event.loaded / event.total * 100));
57
+ };
58
+ xhr.onload = () => {
59
+ const body = JSON.parse(xhr.responseText || "{}");
60
+ if (xhr.status < 200 || xhr.status >= 300) {
61
+ reject(new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed."));
62
+ return;
63
+ }
64
+ onProgress?.(route, 100);
65
+ resolve(body.result);
66
+ };
67
+ xhr.onerror = () => reject(new UploadError("UPLOAD_FAILED", "Upload request failed."));
68
+ onProgress?.(route, 0);
69
+ xhr.send(form);
70
+ });
71
+ }
72
+ export {
73
+ createUploadClient
74
+ };
75
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/client.ts"],"sourcesContent":["export type SizeValue = `${number}b` | `${number}kb` | `${number}mb` | `${number}gb`;\r\nexport type DurationValue = `${number}s` | `${number}m` | `${number}h`;\r\n\r\nexport type UploadInputFile = {\r\n name: string;\r\n type: string;\r\n size: number;\r\n extension?: string;\r\n file?: File;\r\n};\r\n\r\nexport type UploadedFile = {\r\n url: string;\r\n key: string;\r\n name: string;\r\n type: string;\r\n size: number;\r\n extension?: string | undefined;\r\n provider: string;\r\n};\r\n\r\nexport type UploadErrorCode =\r\n | \"FILE_TOO_LARGE\"\r\n | \"FILE_TOO_SMALL\"\r\n | \"INVALID_TYPE\"\r\n | \"AUTH_FAILED\"\r\n | \"VALIDATION_FAILED\"\r\n | \"UPLOAD_FAILED\"\r\n | \"UNKNOWN\";\r\n\r\nexport class UploadError extends Error {\r\n readonly code: UploadErrorCode;\r\n\r\n constructor(code: UploadErrorCode, message: string) {\r\n super(message);\r\n this.name = \"UploadError\";\r\n this.code = code;\r\n }\r\n\r\n toJSON() {\r\n return {\r\n message: this.message,\r\n code: this.code\r\n };\r\n }\r\n}\r\n\r\nexport type StandardSchema<T = unknown> = {\r\n parse(input: unknown): T;\r\n};\r\n\r\nexport type KeyContext<TAuth = unknown, TMeta = unknown> = {\r\n req: Request;\r\n file: UploadInputFile;\r\n user: TAuth;\r\n meta: TMeta;\r\n};\r\n\r\nexport type DoneContext<\r\n TAuth = unknown,\r\n TMeta = unknown,\r\n TMultiple extends boolean = false\r\n> = TMultiple extends true\r\n ? { req: Request; files: UploadedFile[]; user: TAuth; meta: TMeta[] }\r\n : { req: Request; file: UploadedFile; user: TAuth; meta: TMeta };\r\n\r\nexport type StoragePutInput = {\r\n key: string;\r\n file: UploadInputFile;\r\n body: File;\r\n};\r\n\r\nexport type StorageAdapter = {\r\n provider: string;\r\n put(input: StoragePutInput): Promise<UploadedFile>;\r\n};\r\n\r\nexport type Middleware<TUser = unknown> = (ctx: { req: Request }) => TUser | Promise<TUser>;\r\n\r\nexport type UploadKind =\r\n | \"any\"\r\n | \"image\"\r\n | \"pdf\"\r\n | \"video\"\r\n | \"audio\"\r\n | \"text\"\r\n | \"json\"\r\n | \"csv\"\r\n | \"custom\";\r\n\r\nexport type UploadRouteDefinition = {\r\n kind: UploadKind;\r\n maxBytes?: number;\r\n minBytes?: number;\r\n multiple: boolean;\r\n multipleLimit?: number;\r\n auth?: Middleware<unknown>;\r\n overrideAuth: boolean;\r\n key?: (ctx: KeyContext<unknown, unknown>) => string | Promise<string>;\r\n meta?: (ctx: { req: Request; file: UploadInputFile; user: unknown }) => unknown | Promise<unknown>;\r\n validate?: (ctx: {\r\n req: Request;\r\n file: UploadInputFile;\r\n user: unknown;\r\n meta: unknown;\r\n }) => true | string | Promise<true | string>;\r\n done?: (ctx: DoneContext<unknown, unknown, boolean>) => void | Promise<void>;\r\n extensions?: string[];\r\n mimeTypes?: string[];\r\n dimensionRule?: { minWidth?: number; minHeight?: number; maxWidth?: number; maxHeight?: number };\r\n requireSquare?: boolean;\r\n aspectRatio?: `${number}:${number}`;\r\n encoding?: \"utf-8\" | \"utf-16\" | \"ascii\";\r\n schema?: StandardSchema;\r\n headers?: string[];\r\n delimiter?: \",\" | \";\" | \"\\t\" | \"|\";\r\n pageRule?: { min?: number; max?: number };\r\n encrypted?: boolean;\r\n durationRule?: { min?: DurationValue; max?: DurationValue };\r\n};\r\n\r\nexport type UploadRoutes = Record<string, { _def: UploadRouteDefinition }>;\r\n\r\nexport type UpliftApp<TRoutes extends UploadRoutes = UploadRoutes> = {\r\n storage: StorageAdapter;\r\n routes: TRoutes;\r\n middleware?: Middleware<unknown> | undefined;\r\n onUploadComplete?: ((ctx: {\r\n route: keyof TRoutes & string;\r\n result: UploadedFile | UploadedFile[];\r\n user: unknown;\r\n }) => void | Promise<void>) | undefined;\r\n};\r\n\r\nexport type IsMultiple<TRoute> = TRoute extends { __multiple?: infer TMultiple }\r\n ? TMultiple extends true\r\n ? true\r\n : false\r\n : false;\r\n\r\nexport type ClientInput<TRoute> = IsMultiple<TRoute> extends true ? File[] | FileList : File;\r\nexport type ClientOutput<TRoute> = IsMultiple<TRoute> extends true ? UploadedFile[] : UploadedFile;\r\n\r\nexport type UploadClient<TApp extends UpliftApp> = {\r\n [TRouteName in keyof TApp[\"routes\"] & string]: (\r\n input: ClientInput<TApp[\"routes\"][TRouteName]>\r\n ) => Promise<ClientOutput<TApp[\"routes\"][TRouteName]>>;\r\n};\r\n","import { UploadError, type UpliftApp, type UploadClient } from \"./types\";\r\n\r\nexport type UploadProgressHandler = (progress: number) => void;\r\n\r\nexport function createUploadClient<TApp extends UpliftApp>(\r\n baseUrl: string,\r\n options: { fetch?: typeof fetch; onProgress?: (route: string, progress: number) => void } = {}\r\n): UploadClient<TApp> {\r\n const fetcher = options.fetch ?? fetch;\r\n\r\n return new Proxy({}, {\r\n get(_target, property) {\r\n if (typeof property !== \"string\") return undefined;\r\n return async (input: File | File[] | FileList) => {\r\n const files = input instanceof File ? [input] : Array.from(input);\r\n const form = new FormData();\r\n const field = files.length === 1 ? \"file\" : \"files\";\r\n for (const file of files) form.append(field, file);\r\n\r\n const url = routeUrl(baseUrl, property);\r\n if (!options.fetch && typeof XMLHttpRequest !== \"undefined\") {\r\n return uploadWithXhr(url, form, property, options.onProgress);\r\n }\r\n\r\n options.onProgress?.(property, 0);\r\n const response = await fetcher(url, { method: \"POST\", body: form });\r\n const body = await response.json() as { result?: unknown; error?: { code: string; message: string } };\r\n if (!response.ok) {\r\n throw new UploadError((body.error?.code ?? \"UNKNOWN\") as never, body.error?.message ?? \"Upload failed.\");\r\n }\r\n options.onProgress?.(property, 100);\r\n return body.result;\r\n };\r\n }\r\n }) as UploadClient<TApp>;\r\n}\r\n\r\nfunction routeUrl(baseUrl: string, route: string): string {\r\n const url = new URL(baseUrl, globalThis.location?.href ?? \"http://localhost\");\r\n url.searchParams.set(\"route\", route);\r\n const value = url.toString();\r\n return baseUrl.startsWith(\"/\") ? `${url.pathname}${url.search}` : value;\r\n}\r\n\r\nfunction uploadWithXhr(\r\n url: string,\r\n form: FormData,\r\n route: string,\r\n onProgress?: (route: string, progress: number) => void\r\n): Promise<unknown> {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"POST\", url);\r\n xhr.upload.onprogress = (event) => {\r\n if (!event.lengthComputable) return;\r\n onProgress?.(route, Math.round((event.loaded / event.total) * 100));\r\n };\r\n xhr.onload = () => {\r\n const body = JSON.parse(xhr.responseText || \"{}\") as {\r\n result?: unknown;\r\n error?: { code: string; message: string };\r\n };\r\n if (xhr.status < 200 || xhr.status >= 300) {\r\n reject(new UploadError((body.error?.code ?? \"UNKNOWN\") as never, body.error?.message ?? \"Upload failed.\"));\r\n return;\r\n }\r\n onProgress?.(route, 100);\r\n resolve(body.result);\r\n };\r\n xhr.onerror = () => reject(new UploadError(\"UPLOAD_FAILED\", \"Upload request failed.\"));\r\n onProgress?.(route, 0);\r\n xhr.send(form);\r\n });\r\n}\r\n"],"mappings":";AA8BO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC5B;AAAA,EAET,YAAY,MAAuB,SAAiB;AAClD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,SAAS;AACP,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;;;ACzCO,SAAS,mBACd,SACA,UAA4F,CAAC,GACzE;AACpB,QAAM,UAAU,QAAQ,SAAS;AAEjC,SAAO,IAAI,MAAM,CAAC,GAAG;AAAA,IACnB,IAAI,SAAS,UAAU;AACrB,UAAI,OAAO,aAAa,SAAU,QAAO;AACzC,aAAO,OAAO,UAAoC;AAChD,cAAM,QAAQ,iBAAiB,OAAO,CAAC,KAAK,IAAI,MAAM,KAAK,KAAK;AAChE,cAAM,OAAO,IAAI,SAAS;AAC1B,cAAM,QAAQ,MAAM,WAAW,IAAI,SAAS;AAC5C,mBAAW,QAAQ,MAAO,MAAK,OAAO,OAAO,IAAI;AAEjD,cAAM,MAAM,SAAS,SAAS,QAAQ;AACtC,YAAI,CAAC,QAAQ,SAAS,OAAO,mBAAmB,aAAa;AAC3D,iBAAO,cAAc,KAAK,MAAM,UAAU,QAAQ,UAAU;AAAA,QAC9D;AAEA,gBAAQ,aAAa,UAAU,CAAC;AAChC,cAAM,WAAW,MAAM,QAAQ,KAAK,EAAE,QAAQ,QAAQ,MAAM,KAAK,CAAC;AAClE,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,IAAI,YAAa,KAAK,OAAO,QAAQ,WAAqB,KAAK,OAAO,WAAW,gBAAgB;AAAA,QACzG;AACA,gBAAQ,aAAa,UAAU,GAAG;AAClC,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SAAS,SAAiB,OAAuB;AACxD,QAAM,MAAM,IAAI,IAAI,SAAS,WAAW,UAAU,QAAQ,kBAAkB;AAC5E,MAAI,aAAa,IAAI,SAAS,KAAK;AACnC,QAAM,QAAQ,IAAI,SAAS;AAC3B,SAAO,QAAQ,WAAW,GAAG,IAAI,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM,KAAK;AACpE;AAEA,SAAS,cACP,KACA,MACA,OACA,YACkB;AAClB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,eAAe;AAC/B,QAAI,KAAK,QAAQ,GAAG;AACpB,QAAI,OAAO,aAAa,CAAC,UAAU;AACjC,UAAI,CAAC,MAAM,iBAAkB;AAC7B,mBAAa,OAAO,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG,CAAC;AAAA,IACpE;AACA,QAAI,SAAS,MAAM;AACjB,YAAM,OAAO,KAAK,MAAM,IAAI,gBAAgB,IAAI;AAIhD,UAAI,IAAI,SAAS,OAAO,IAAI,UAAU,KAAK;AACzC,eAAO,IAAI,YAAa,KAAK,OAAO,QAAQ,WAAqB,KAAK,OAAO,WAAW,gBAAgB,CAAC;AACzG;AAAA,MACF;AACA,mBAAa,OAAO,GAAG;AACvB,cAAQ,KAAK,MAAM;AAAA,IACrB;AACA,QAAI,UAAU,MAAM,OAAO,IAAI,YAAY,iBAAiB,wBAAwB,CAAC;AACrF,iBAAa,OAAO,CAAC;AACrB,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ UploadBuilder: () => UploadBuilder,
24
+ UploadError: () => UploadError,
25
+ any: () => any,
26
+ audio: () => audio,
27
+ createUploadClient: () => createUploadClient,
28
+ csv: () => csv,
29
+ custom: () => custom,
30
+ image: () => image,
31
+ json: () => json,
32
+ pdf: () => pdf,
33
+ text: () => text,
34
+ uplift: () => uplift,
35
+ video: () => video
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/types.ts
40
+ var UploadError = class extends Error {
41
+ code;
42
+ constructor(code, message) {
43
+ super(message);
44
+ this.name = "UploadError";
45
+ this.code = code;
46
+ }
47
+ toJSON() {
48
+ return {
49
+ message: this.message,
50
+ code: this.code
51
+ };
52
+ }
53
+ };
54
+
55
+ // src/utils.ts
56
+ var sizeUnits = {
57
+ b: 1,
58
+ kb: 1024,
59
+ mb: 1024 * 1024,
60
+ gb: 1024 * 1024 * 1024
61
+ };
62
+ function parseSize(value) {
63
+ const match = /^(\d+(?:\.\d+)?)(b|kb|mb|gb)$/.exec(value);
64
+ if (!match) throw new UploadError("VALIDATION_FAILED", `Invalid size value: ${value}`);
65
+ const amount = Number(match[1]);
66
+ const unit = match[2];
67
+ return Math.floor(amount * sizeUnits[unit]);
68
+ }
69
+
70
+ // src/builder.ts
71
+ var UploadBuilder = class {
72
+ __auth;
73
+ __meta;
74
+ __multiple;
75
+ __kind;
76
+ _def;
77
+ constructor(kind, mimeTypes = [], extensions = []) {
78
+ this._def = {
79
+ kind,
80
+ multiple: false,
81
+ overrideAuth: false
82
+ };
83
+ if (mimeTypes.length > 0) this._def.mimeTypes = mimeTypes;
84
+ if (extensions.length > 0) this._def.extensions = extensions;
85
+ }
86
+ max(size) {
87
+ this._def.maxBytes = parseSize(size);
88
+ return this;
89
+ }
90
+ min(size) {
91
+ this._def.minBytes = parseSize(size);
92
+ return this;
93
+ }
94
+ multiple(count) {
95
+ this._def.multiple = true;
96
+ if (count !== void 0) this._def.multipleLimit = count;
97
+ return this;
98
+ }
99
+ auth(handler) {
100
+ this._def.auth = handler;
101
+ this._def.overrideAuth = false;
102
+ return this;
103
+ }
104
+ overrideAuth() {
105
+ this._def.overrideAuth = true;
106
+ delete this._def.auth;
107
+ return this;
108
+ }
109
+ key(handler) {
110
+ this._def.key = handler;
111
+ return this;
112
+ }
113
+ meta(handler) {
114
+ this._def.meta = handler;
115
+ return this;
116
+ }
117
+ validate(handler) {
118
+ this._def.validate = handler;
119
+ return this;
120
+ }
121
+ done(handler) {
122
+ this._def.done = handler;
123
+ return this;
124
+ }
125
+ types(types) {
126
+ this._def.extensions = types.map((type) => type.toLowerCase());
127
+ return this;
128
+ }
129
+ dimensions(rule) {
130
+ this._def.dimensionRule = rule;
131
+ return this;
132
+ }
133
+ square() {
134
+ this._def.requireSquare = true;
135
+ return this;
136
+ }
137
+ aspectRatio(value) {
138
+ this._def.aspectRatio = value;
139
+ return this;
140
+ }
141
+ encoding(value) {
142
+ this._def.encoding = value;
143
+ return this;
144
+ }
145
+ schema(schema) {
146
+ this._def.schema = schema;
147
+ return this;
148
+ }
149
+ headers(headers) {
150
+ this._def.headers = headers;
151
+ return this;
152
+ }
153
+ delimiter(value) {
154
+ this._def.delimiter = value;
155
+ return this;
156
+ }
157
+ pages(rule) {
158
+ this._def.pageRule = rule;
159
+ return this;
160
+ }
161
+ encrypted(value) {
162
+ this._def.encrypted = value;
163
+ return this;
164
+ }
165
+ duration(rule) {
166
+ this._def.durationRule = rule;
167
+ return this;
168
+ }
169
+ };
170
+ function any() {
171
+ return new UploadBuilder("any");
172
+ }
173
+ function image() {
174
+ return new UploadBuilder("image", ["image/"], ["png", "jpg", "jpeg", "webp", "gif", "avif"]);
175
+ }
176
+ function pdf() {
177
+ return new UploadBuilder("pdf", ["application/pdf"], ["pdf"]);
178
+ }
179
+ function video() {
180
+ return new UploadBuilder("video", ["video/"], ["mp4", "webm", "mov", "avi", "mkv"]);
181
+ }
182
+ function audio() {
183
+ return new UploadBuilder("audio", ["audio/"], ["mp3", "wav", "ogg", "m4a", "aac", "flac"]);
184
+ }
185
+ function text() {
186
+ return new UploadBuilder("text", ["text/"], ["txt", "md", "log"]);
187
+ }
188
+ function json() {
189
+ return new UploadBuilder("json", ["application/json"], ["json"]);
190
+ }
191
+ function csv() {
192
+ return new UploadBuilder("csv", ["text/csv"], ["csv"]);
193
+ }
194
+ function custom(type) {
195
+ const mimeTypes = Array.isArray(type) ? type : [type];
196
+ return new UploadBuilder("custom", mimeTypes);
197
+ }
198
+
199
+ // src/client.ts
200
+ function createUploadClient(baseUrl, options = {}) {
201
+ const fetcher = options.fetch ?? fetch;
202
+ return new Proxy({}, {
203
+ get(_target, property) {
204
+ if (typeof property !== "string") return void 0;
205
+ return async (input) => {
206
+ const files = input instanceof File ? [input] : Array.from(input);
207
+ const form = new FormData();
208
+ const field = files.length === 1 ? "file" : "files";
209
+ for (const file of files) form.append(field, file);
210
+ const url = routeUrl(baseUrl, property);
211
+ if (!options.fetch && typeof XMLHttpRequest !== "undefined") {
212
+ return uploadWithXhr(url, form, property, options.onProgress);
213
+ }
214
+ options.onProgress?.(property, 0);
215
+ const response = await fetcher(url, { method: "POST", body: form });
216
+ const body = await response.json();
217
+ if (!response.ok) {
218
+ throw new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed.");
219
+ }
220
+ options.onProgress?.(property, 100);
221
+ return body.result;
222
+ };
223
+ }
224
+ });
225
+ }
226
+ function routeUrl(baseUrl, route) {
227
+ const url = new URL(baseUrl, globalThis.location?.href ?? "http://localhost");
228
+ url.searchParams.set("route", route);
229
+ const value = url.toString();
230
+ return baseUrl.startsWith("/") ? `${url.pathname}${url.search}` : value;
231
+ }
232
+ function uploadWithXhr(url, form, route, onProgress) {
233
+ return new Promise((resolve, reject) => {
234
+ const xhr = new XMLHttpRequest();
235
+ xhr.open("POST", url);
236
+ xhr.upload.onprogress = (event) => {
237
+ if (!event.lengthComputable) return;
238
+ onProgress?.(route, Math.round(event.loaded / event.total * 100));
239
+ };
240
+ xhr.onload = () => {
241
+ const body = JSON.parse(xhr.responseText || "{}");
242
+ if (xhr.status < 200 || xhr.status >= 300) {
243
+ reject(new UploadError(body.error?.code ?? "UNKNOWN", body.error?.message ?? "Upload failed."));
244
+ return;
245
+ }
246
+ onProgress?.(route, 100);
247
+ resolve(body.result);
248
+ };
249
+ xhr.onerror = () => reject(new UploadError("UPLOAD_FAILED", "Upload request failed."));
250
+ onProgress?.(route, 0);
251
+ xhr.send(form);
252
+ });
253
+ }
254
+
255
+ // src/index.ts
256
+ function uplift(config) {
257
+ return config;
258
+ }
259
+ // Annotate the CommonJS export names for ESM import in node:
260
+ 0 && (module.exports = {
261
+ UploadBuilder,
262
+ UploadError,
263
+ any,
264
+ audio,
265
+ createUploadClient,
266
+ csv,
267
+ custom,
268
+ image,
269
+ json,
270
+ pdf,
271
+ text,
272
+ uplift,
273
+ video
274
+ });
275
+ //# sourceMappingURL=index.cjs.map