@edkstack/files 0.1.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/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # @bunstack/core
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run src/index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.3.8. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
@@ -0,0 +1,17 @@
1
+ import { BunSQLDatabase as BunSQLDatabase2 } from "drizzle-orm/bun-sql";
2
+ type Visibility = "private" | "public";
3
+ interface PurposePolicy {
4
+ maxSize?: number;
5
+ allowedMimeTypes?: string[];
6
+ visibility?: Visibility;
7
+ }
8
+ import { S3Client as S3Client2 } from "bun";
9
+ interface FilesBackendOptions<TPurposes extends string> {
10
+ db: BunSQLDatabase2;
11
+ client: S3Client2;
12
+ policies: Record<TPurposes, PurposePolicy>;
13
+ publicBaseUrl: string;
14
+ presignExpiresIn?: number;
15
+ }
16
+ declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {};
17
+ export { createFilesBackend, Visibility, PurposePolicy, FilesBackendOptions };
@@ -0,0 +1,204 @@
1
+ // src/backend/routes.ts
2
+ import { Elysia, t } from "elysia";
3
+ function createRoutes(options) {
4
+ const {
5
+ services,
6
+ policies
7
+ } = options;
8
+ return new Elysia({
9
+ prefix: "/api"
10
+ }).post("/files/upload", async ({ status, body }) => {
11
+ const { file, purpose } = body;
12
+ const policy = policies[purpose];
13
+ if (!policy) {
14
+ return status(400, {
15
+ message: "Purpose not supported"
16
+ });
17
+ }
18
+ if (policy.maxSize !== undefined && file.size > policy.maxSize) {
19
+ return status(400, {
20
+ message: "File size exceeds the maximum allowed size"
21
+ });
22
+ }
23
+ if (policy.allowedMimeTypes !== undefined && !policy.allowedMimeTypes.includes(file.type)) {
24
+ return status(400, {
25
+ message: "File type not allowed"
26
+ });
27
+ }
28
+ const uploaded = await services.uploadFile({
29
+ file,
30
+ purpose,
31
+ visibility: policy.visibility ?? "private"
32
+ });
33
+ return status(200, {
34
+ id: uploaded.id,
35
+ name: uploaded.name,
36
+ key: uploaded.key,
37
+ size: uploaded.size,
38
+ mimeType: uploaded.mimeType,
39
+ createdAt: uploaded.createdAt
40
+ });
41
+ }, {
42
+ body: UploadRequest(Object.keys(policies)),
43
+ response: {
44
+ 200: FileResponse,
45
+ 400: ErrorResponse,
46
+ 500: ErrorResponse
47
+ }
48
+ });
49
+ }
50
+ function UploadRequest(purposes) {
51
+ return t.Object({
52
+ file: t.File(),
53
+ purpose: t.Union(purposes.map((p) => t.Literal(p)))
54
+ });
55
+ }
56
+ var ErrorResponse = t.Object({
57
+ message: t.String()
58
+ });
59
+ var FileResponse = t.Object({
60
+ id: t.String(),
61
+ name: t.Nullable(t.String()),
62
+ key: t.String(),
63
+ size: t.Number(),
64
+ mimeType: t.String(),
65
+ createdAt: t.Date()
66
+ });
67
+
68
+ // src/backend/schemas.ts
69
+ import { nanoid } from "nanoid";
70
+ import { index, integer, pgTable, text, timestamp, pgEnum } from "drizzle-orm/pg-core";
71
+ function createSchemas() {
72
+ const files = pgTable("files", {
73
+ id: text("id").primaryKey().$defaultFn(() => `file_${nanoid()}`),
74
+ purpose: text("purpose").notNull(),
75
+ name: text("name"),
76
+ key: text("key").notNull().unique(),
77
+ size: integer("size").notNull(),
78
+ mimeType: text("mime_type").notNull().default("application/octet-stream"),
79
+ refCount: integer("ref_count").notNull().default(0),
80
+ visibility: pgEnum("visibility", ["private", "public"])().notNull().default("private"),
81
+ createdAt: timestamp("created_at").notNull().defaultNow(),
82
+ updatedAt: timestamp("updated_at").notNull().defaultNow()
83
+ }, (table) => [
84
+ index("files_key_idx").on(table.key),
85
+ index("files_created_at_idx").on(table.createdAt)
86
+ ]);
87
+ return {
88
+ files
89
+ };
90
+ }
91
+
92
+ // src/backend/services.ts
93
+ import { nanoid as nanoid2 } from "nanoid";
94
+ import { extname } from "path";
95
+ import { eq, sql, and } from "drizzle-orm";
96
+ function createServices(options) {
97
+ const {
98
+ db,
99
+ schemas,
100
+ s3Client,
101
+ publicBaseUrl,
102
+ keyPrefix = "files",
103
+ presignExpiresIn = 3600
104
+ } = options;
105
+ return {
106
+ s3Client,
107
+ async getFile(params) {
108
+ const [found] = await db.select().from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
109
+ if (!found) {
110
+ throw new Error("File not found");
111
+ }
112
+ return found;
113
+ },
114
+ async getUrl(params) {
115
+ const [found] = await db.select({
116
+ key: schemas.files.key,
117
+ visibility: schemas.files.visibility
118
+ }).from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
119
+ if (!found) {
120
+ throw new Error("File not found");
121
+ }
122
+ if (found.visibility === "public") {
123
+ return `${publicBaseUrl}/${found.key}`;
124
+ }
125
+ return s3Client.presign(found.key, { expiresIn: presignExpiresIn });
126
+ },
127
+ async uploadFile(params) {
128
+ const id = nanoid2();
129
+ const ext = extname(params.file.name);
130
+ const key = [keyPrefix, params.visibility, params.purpose, `${id}${ext}`].join("/");
131
+ const s3file = s3Client.file(key);
132
+ await s3file.write(params.file, {
133
+ type: params.file.type,
134
+ acl: params.visibility === "public" ? "public-read" : "private"
135
+ });
136
+ try {
137
+ const [created] = await db.insert(schemas.files).values({
138
+ purpose: params.purpose,
139
+ key,
140
+ size: s3file.size,
141
+ name: s3file.name ?? null,
142
+ mimeType: s3file.type,
143
+ visibility: params.visibility
144
+ }).returning();
145
+ if (!created) {
146
+ throw new Error("Failed to create file record");
147
+ }
148
+ return created;
149
+ } catch (error) {
150
+ await s3file.delete().catch();
151
+ throw error;
152
+ }
153
+ },
154
+ async deleteFile(params) {
155
+ const [deleted] = await db.delete(schemas.files).where(eq(schemas.files.id, params.id)).returning();
156
+ if (!deleted)
157
+ return;
158
+ await s3Client.delete(deleted.key);
159
+ },
160
+ async acquireFile(params) {
161
+ const [updated] = await db.update(schemas.files).set({ refCount: sql`${schemas.files.refCount} + 1` }).where(and(eq(schemas.files.id, params.id), params.purpose ? eq(schemas.files.purpose, params.purpose) : undefined)).returning();
162
+ if (!updated) {
163
+ throw new Error("File not found");
164
+ }
165
+ return updated;
166
+ },
167
+ async releaseFile(params) {
168
+ const [updated] = await db.update(schemas.files).set({ refCount: sql`${schemas.files.refCount} - 1` }).where(eq(schemas.files.id, params.id)).returning();
169
+ if (!updated) {
170
+ throw new Error("File not found");
171
+ }
172
+ if (updated.refCount < 1) {
173
+ await this.deleteFile({ id: params.id });
174
+ }
175
+ }
176
+ };
177
+ }
178
+
179
+ // src/backend/backend.ts
180
+ function createFilesBackend(options) {
181
+ const schemas = createSchemas();
182
+ const services = createServices({
183
+ db: options.db,
184
+ schemas,
185
+ s3Client: options.client,
186
+ publicBaseUrl: options.publicBaseUrl,
187
+ presignExpiresIn: options.presignExpiresIn
188
+ });
189
+ const routes = createRoutes({
190
+ services,
191
+ policies: options.policies
192
+ });
193
+ return {
194
+ schemas,
195
+ routes,
196
+ services
197
+ };
198
+ }
199
+ export {
200
+ createFilesBackend
201
+ };
202
+
203
+ //# debugId=6563BBC77836F87F64756E2164756E21
204
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjXFxiYWNrZW5kXFxyb3V0ZXMudHMiLCAic3JjXFxiYWNrZW5kXFxzY2hlbWFzLnRzIiwgInNyY1xcYmFja2VuZFxcc2VydmljZXMudHMiLCAic3JjXFxiYWNrZW5kXFxiYWNrZW5kLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCB7IEVseXNpYSwgdCB9IGZyb20gXCJlbHlzaWFcIjtcclxuaW1wb3J0IHR5cGUgeyBTZXJ2aWNlcyB9IGZyb20gXCIuL3NlcnZpY2VzXCI7XHJcblxyXG5leHBvcnQgdHlwZSBWaXNpYmlsaXR5ID0gXCJwcml2YXRlXCIgfCBcInB1YmxpY1wiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQdXJwb3NlUG9saWN5IHtcclxuICBtYXhTaXplPzogbnVtYmVyO1xyXG4gIGFsbG93ZWRNaW1lVHlwZXM/OiBzdHJpbmdbXTtcclxuICB2aXNpYmlsaXR5PzogVmlzaWJpbGl0eTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJvdXRlczxjb25zdCBUUHVycG9zZSBleHRlbmRzIHN0cmluZz4oXHJcbiAgb3B0aW9uczoge1xyXG4gICAgc2VydmljZXM6IFNlcnZpY2VzO1xyXG4gICAgcG9saWNpZXM6IFJlY29yZDxUUHVycG9zZSwgUHVycG9zZVBvbGljeT5cclxuICB9XHJcbikge1xyXG4gIFxyXG4gIGNvbnN0IHsgXHJcbiAgICBzZXJ2aWNlcywgXHJcbiAgICBwb2xpY2llcyxcclxuICB9ID0gb3B0aW9ucztcclxuXHJcbiAgcmV0dXJuIG5ldyBFbHlzaWEoe1xyXG4gICAgcHJlZml4OiBcIi9hcGlcIixcclxuICB9KS5wb3N0KFwiL2ZpbGVzL3VwbG9hZFwiLCBhc3luYyAoeyBzdGF0dXMsIGJvZHkgfSkgPT4ge1xyXG4gICAgY29uc3QgeyBmaWxlLCBwdXJwb3NlIH0gPSBib2R5O1xyXG4gICAgY29uc3QgcG9saWN5ID0gcG9saWNpZXNbcHVycG9zZSBhcyBUUHVycG9zZV07XHJcbiAgICBpZiAoIXBvbGljeSkge1xyXG4gICAgICByZXR1cm4gc3RhdHVzKDQwMCwge1xyXG4gICAgICAgIG1lc3NhZ2U6IFwiUHVycG9zZSBub3Qgc3VwcG9ydGVkXCIsXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgaWYgKHBvbGljeS5tYXhTaXplICE9PSB1bmRlZmluZWQgJiYgZmlsZS5zaXplID4gcG9saWN5Lm1heFNpemUpIHtcclxuICAgICAgcmV0dXJuIHN0YXR1cyg0MDAsIHtcclxuICAgICAgICBtZXNzYWdlOiBcIkZpbGUgc2l6ZSBleGNlZWRzIHRoZSBtYXhpbXVtIGFsbG93ZWQgc2l6ZVwiLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIGlmIChwb2xpY3kuYWxsb3dlZE1pbWVUeXBlcyAhPT0gdW5kZWZpbmVkICYmICFwb2xpY3kuYWxsb3dlZE1pbWVUeXBlcy5pbmNsdWRlcyhmaWxlLnR5cGUpKSB7XHJcbiAgICAgIHJldHVybiBzdGF0dXMoNDAwLCB7XHJcbiAgICAgICAgbWVzc2FnZTogXCJGaWxlIHR5cGUgbm90IGFsbG93ZWRcIixcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjb25zdCB1cGxvYWRlZCA9IGF3YWl0IHNlcnZpY2VzLnVwbG9hZEZpbGUoeyBcclxuICAgICAgZmlsZSwgXHJcbiAgICAgIHB1cnBvc2UsIFxyXG4gICAgICB2aXNpYmlsaXR5OiBwb2xpY3kudmlzaWJpbGl0eSA/PyBcInByaXZhdGVcIiBcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHN0YXR1cygyMDAsIHtcclxuICAgICAgaWQ6IHVwbG9hZGVkLmlkLFxyXG4gICAgICBuYW1lOiB1cGxvYWRlZC5uYW1lLFxyXG4gICAgICBrZXk6IHVwbG9hZGVkLmtleSxcclxuICAgICAgc2l6ZTogdXBsb2FkZWQuc2l6ZSxcclxuICAgICAgbWltZVR5cGU6IHVwbG9hZGVkLm1pbWVUeXBlLFxyXG4gICAgICBjcmVhdGVkQXQ6IHVwbG9hZGVkLmNyZWF0ZWRBdCxcclxuICAgIH0pO1xyXG4gIH0sIHtcclxuICAgIGJvZHk6IFVwbG9hZFJlcXVlc3QoT2JqZWN0LmtleXMocG9saWNpZXMpIGFzIFRQdXJwb3NlW10pLFxyXG4gICAgcmVzcG9uc2U6IHtcclxuICAgICAgMjAwOiBGaWxlUmVzcG9uc2UsXHJcbiAgICAgIDQwMDogRXJyb3JSZXNwb25zZSxcclxuICAgICAgNTAwOiBFcnJvclJlc3BvbnNlLFxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG5mdW5jdGlvbiBVcGxvYWRSZXF1ZXN0PGNvbnN0IFRQdXJwb3NlIGV4dGVuZHMgc3RyaW5nPihcclxuICBwdXJwb3NlczogVFB1cnBvc2VbXVxyXG4pIHtcclxuICByZXR1cm4gdC5PYmplY3Qoe1xyXG4gICAgZmlsZTogdC5GaWxlKCksXHJcbiAgICBwdXJwb3NlOiB0LlVuaW9uKFxyXG4gICAgICBwdXJwb3Nlcy5tYXAoKHApID0+IHQuTGl0ZXJhbChwKSkgYXMgW1xyXG4gICAgICAgIFJldHVyblR5cGU8dHlwZW9mIHQuTGl0ZXJhbDxUUHVycG9zZT4+LFxyXG4gICAgICAgIC4uLlJldHVyblR5cGU8dHlwZW9mIHQuTGl0ZXJhbDxUUHVycG9zZT4+W10sXHJcbiAgICAgIF1cclxuICAgIClcclxuICB9KTtcclxufVxyXG5cclxuY29uc3QgRXJyb3JSZXNwb25zZSA9IHQuT2JqZWN0KHtcclxuICBtZXNzYWdlOiB0LlN0cmluZygpLFxyXG59KTtcclxuXHJcbmNvbnN0IEZpbGVSZXNwb25zZSA9IHQuT2JqZWN0KHtcclxuICBpZDogdC5TdHJpbmcoKSxcclxuICBuYW1lOiB0Lk51bGxhYmxlKHQuU3RyaW5nKCkpLFxyXG4gIGtleTogdC5TdHJpbmcoKSxcclxuICBzaXplOiB0Lk51bWJlcigpLFxyXG4gIG1pbWVUeXBlOiB0LlN0cmluZygpLFxyXG4gIGNyZWF0ZWRBdDogdC5EYXRlKCksXHJcbn0pOyIsCiAgICAiaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xyXG5pbXBvcnQgeyBpbmRleCwgaW50ZWdlciwgcGdUYWJsZSwgdGV4dCwgdGltZXN0YW1wLCBwZ0VudW0gfSBmcm9tIFwiZHJpenpsZS1vcm0vcGctY29yZVwiO1xyXG5cclxuXHJcbmV4cG9ydCB0eXBlIEFsbFNjaGVtYXMgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVTY2hlbWFzPjtcclxuZXhwb3J0IHR5cGUgRmlsZVNjaGVtYSA9IEFsbFNjaGVtYXNbXCJmaWxlc1wiXTtcclxuZXhwb3J0IHR5cGUgRmlsZVNlbGVjdCA9IEZpbGVTY2hlbWFbXCIkaW5mZXJTZWxlY3RcIl07XHJcbmV4cG9ydCB0eXBlIEZpbGVJbnNlcnQgPSBGaWxlU2NoZW1hW1wiJGluZmVySW5zZXJ0XCJdO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNjaGVtYXMoKSB7XHJcblxyXG4gIGNvbnN0IGZpbGVzID0gcGdUYWJsZShcImZpbGVzXCIsIHtcclxuICAgIGlkOiB0ZXh0KFwiaWRcIikucHJpbWFyeUtleSgpLiRkZWZhdWx0Rm4oKCkgPT4gYGZpbGVfJHtuYW5vaWQoKX1gKSxcclxuICAgIHB1cnBvc2U6IHRleHQoXCJwdXJwb3NlXCIpLm5vdE51bGwoKSxcclxuICAgIG5hbWU6IHRleHQoXCJuYW1lXCIpLFxyXG4gICAga2V5OiB0ZXh0KFwia2V5XCIpLm5vdE51bGwoKS51bmlxdWUoKSxcclxuICAgIHNpemU6IGludGVnZXIoXCJzaXplXCIpLm5vdE51bGwoKSxcclxuICAgIG1pbWVUeXBlOiB0ZXh0KFwibWltZV90eXBlXCIpLm5vdE51bGwoKS5kZWZhdWx0KFwiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtXCIpLFxyXG4gICAgcmVmQ291bnQ6IGludGVnZXIoXCJyZWZfY291bnRcIikubm90TnVsbCgpLmRlZmF1bHQoMCksXHJcbiAgICB2aXNpYmlsaXR5OiBwZ0VudW0oXCJ2aXNpYmlsaXR5XCIsIFtcInByaXZhdGVcIiwgXCJwdWJsaWNcIl0pKCkubm90TnVsbCgpLmRlZmF1bHQoXCJwcml2YXRlXCIpLFxyXG4gICAgY3JlYXRlZEF0OiB0aW1lc3RhbXAoXCJjcmVhdGVkX2F0XCIpLm5vdE51bGwoKS5kZWZhdWx0Tm93KCksXHJcbiAgICB1cGRhdGVkQXQ6IHRpbWVzdGFtcChcInVwZGF0ZWRfYXRcIikubm90TnVsbCgpLmRlZmF1bHROb3coKSxcclxuICB9LCAodGFibGUpID0+IFtcclxuICAgIGluZGV4KFwiZmlsZXNfa2V5X2lkeFwiKS5vbih0YWJsZS5rZXkpLFxyXG4gICAgaW5kZXgoXCJmaWxlc19jcmVhdGVkX2F0X2lkeFwiKS5vbih0YWJsZS5jcmVhdGVkQXQpLFxyXG4gIF0pO1xyXG5cclxuICByZXR1cm4ge1xyXG4gICAgZmlsZXMsXHJcbiAgfVxyXG59IiwKICAgICJpbXBvcnQgdHlwZSB7IFMzQ2xpZW50LCBTM0ZpbGUgfSBmcm9tIFwiYnVuXCI7XHJcbmltcG9ydCB7IG5hbm9pZCB9IGZyb20gXCJuYW5vaWRcIjtcclxuaW1wb3J0IHsgZXh0bmFtZSB9IGZyb20gXCJwYXRoXCI7XHJcbmltcG9ydCB7IGVxLCBzcWwsIGx0LCBhbmQgfSBmcm9tIFwiZHJpenpsZS1vcm1cIjtcclxuaW1wb3J0IHR5cGUgeyBCdW5TUUxEYXRhYmFzZSB9IGZyb20gXCJkcml6emxlLW9ybS9idW4tc3FsXCI7XHJcbmltcG9ydCB0eXBlIHsgQWxsU2NoZW1hcywgRmlsZVNlbGVjdCB9IGZyb20gXCIuL3NjaGVtYXNcIjtcclxuXHJcbmV4cG9ydCB0eXBlIFNlcnZpY2VzID0gUmV0dXJuVHlwZTx0eXBlb2YgY3JlYXRlU2VydmljZXM+O1xyXG5cclxudHlwZSBCeUlkID0geyBpZDogc3RyaW5nIH07XHJcbnR5cGUgQnlLZXkgPSB7IGtleTogc3RyaW5nIH07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2VydmljZXMoXHJcbiAgb3B0aW9uczoge1xyXG4gICAgZGI6IEJ1blNRTERhdGFiYXNlO1xyXG4gICAgc2NoZW1hczogQWxsU2NoZW1hcztcclxuICAgIHMzQ2xpZW50OiBTM0NsaWVudDtcclxuICAgIHB1YmxpY0Jhc2VVcmw6IHN0cmluZztcclxuICAgIGtleVByZWZpeD86IHN0cmluZztcclxuICAgIHByZXNpZ25FeHBpcmVzSW4/OiBudW1iZXI7XHJcbiAgfVxyXG4pIHtcclxuICBjb25zdCB7IFxyXG4gICAgZGIsIFxyXG4gICAgc2NoZW1hcywgXHJcbiAgICBzM0NsaWVudCwgXHJcbiAgICBwdWJsaWNCYXNlVXJsLCBcclxuICAgIGtleVByZWZpeCA9IFwiZmlsZXNcIixcclxuICAgIHByZXNpZ25FeHBpcmVzSW4gPSAzNjAwXHJcbiAgfSA9IG9wdGlvbnM7XHJcbiAgXHJcbiAgcmV0dXJuIHtcclxuXHJcbiAgICBzM0NsaWVudCxcclxuXHJcbiAgICBhc3luYyBnZXRGaWxlKHBhcmFtczogQnlJZCk6IFByb21pc2U8RmlsZVNlbGVjdD4ge1xyXG4gICAgICBjb25zdCBbZm91bmRdID0gYXdhaXQgZGJcclxuICAgICAgICAuc2VsZWN0KClcclxuICAgICAgICAuZnJvbShzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgIC53aGVyZShlcShzY2hlbWFzLmZpbGVzLmlkLCBwYXJhbXMuaWQpKVxyXG4gICAgICAgIC5saW1pdCgxKTtcclxuICAgICAgaWYgKCFmb3VuZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkZpbGUgbm90IGZvdW5kXCIpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmb3VuZDtcclxuICAgIH0sXHJcblxyXG4gICAgYXN5bmMgZ2V0VXJsKHBhcmFtczogQnlJZCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgIGNvbnN0IFtmb3VuZF0gPSBhd2FpdCBkYlxyXG4gICAgICAgIC5zZWxlY3QoeyBcclxuICAgICAgICAgIGtleTogc2NoZW1hcy5maWxlcy5rZXksXHJcbiAgICAgICAgICB2aXNpYmlsaXR5OiBzY2hlbWFzLmZpbGVzLnZpc2liaWxpdHksXHJcbiAgICAgICAgfSlcclxuICAgICAgICAuZnJvbShzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgIC53aGVyZShlcShzY2hlbWFzLmZpbGVzLmlkLCBwYXJhbXMuaWQpKVxyXG4gICAgICAgIC5saW1pdCgxKTtcclxuICAgICAgaWYgKCFmb3VuZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkZpbGUgbm90IGZvdW5kXCIpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChmb3VuZC52aXNpYmlsaXR5ID09PSBcInB1YmxpY1wiKSB7XHJcbiAgICAgICAgcmV0dXJuIGAke3B1YmxpY0Jhc2VVcmx9LyR7Zm91bmQua2V5fWA7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHMzQ2xpZW50LnByZXNpZ24oZm91bmQua2V5LCB7IGV4cGlyZXNJbjogcHJlc2lnbkV4cGlyZXNJbiB9KTtcclxuICAgIH0sXHJcblxyXG4gICAgYXN5bmMgdXBsb2FkRmlsZShwYXJhbXM6IHtcclxuICAgICAgZmlsZTogRmlsZTtcclxuICAgICAgcHVycG9zZTogc3RyaW5nO1xyXG4gICAgICB2aXNpYmlsaXR5OiBcInByaXZhdGVcIiB8IFwicHVibGljXCI7XHJcbiAgICB9KTogUHJvbWlzZTxGaWxlU2VsZWN0PiB7XHJcbiAgICAgIGNvbnN0IGlkID0gbmFub2lkKCk7XHJcbiAgICAgIGNvbnN0IGV4dCA9IGV4dG5hbWUocGFyYW1zLmZpbGUubmFtZSk7XHJcbiAgICAgIGNvbnN0IGtleSA9IFtrZXlQcmVmaXgsIHBhcmFtcy52aXNpYmlsaXR5LCBwYXJhbXMucHVycG9zZSwgYCR7aWR9JHtleHR9YF0uam9pbihcIi9cIik7XHJcbiAgICAgIGNvbnN0IHMzZmlsZSA9IHMzQ2xpZW50LmZpbGUoa2V5KTtcclxuICAgICAgYXdhaXQgczNmaWxlLndyaXRlKHBhcmFtcy5maWxlLCB7XHJcbiAgICAgICAgdHlwZTogcGFyYW1zLmZpbGUudHlwZSxcclxuICAgICAgICBhY2w6IHBhcmFtcy52aXNpYmlsaXR5ID09PSBcInB1YmxpY1wiID8gXCJwdWJsaWMtcmVhZFwiIDogXCJwcml2YXRlXCIsXHJcbiAgICAgIH0pO1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IFtjcmVhdGVkXSA9IGF3YWl0IGRiLmluc2VydChzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgICAgLnZhbHVlcyh7XHJcbiAgICAgICAgICAgIHB1cnBvc2U6IHBhcmFtcy5wdXJwb3NlLFxyXG4gICAgICAgICAgICBrZXksXHJcbiAgICAgICAgICAgIHNpemU6IHMzZmlsZS5zaXplLFxyXG4gICAgICAgICAgICBuYW1lOiBzM2ZpbGUubmFtZSA/PyBudWxsLFxyXG4gICAgICAgICAgICBtaW1lVHlwZTogczNmaWxlLnR5cGUsXHJcbiAgICAgICAgICAgIHZpc2liaWxpdHk6IHBhcmFtcy52aXNpYmlsaXR5LFxyXG4gICAgICAgICAgfSlcclxuICAgICAgICAgIC5yZXR1cm5pbmcoKTtcclxuICAgICAgICBpZiAoIWNyZWF0ZWQpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkZhaWxlZCB0byBjcmVhdGUgZmlsZSByZWNvcmRcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjcmVhdGVkO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGF3YWl0IHMzZmlsZS5kZWxldGUoKS5jYXRjaCgpO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGFzeW5jIGRlbGV0ZUZpbGUocGFyYW1zOiB7IGlkOiBzdHJpbmcgfSk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICBjb25zdCBbZGVsZXRlZF0gPSBhd2FpdCBkYlxyXG4gICAgICAgIC5kZWxldGUoc2NoZW1hcy5maWxlcylcclxuICAgICAgICAud2hlcmUoZXEoc2NoZW1hcy5maWxlcy5pZCwgcGFyYW1zLmlkKSlcclxuICAgICAgICAucmV0dXJuaW5nKCk7XHJcbiAgICAgIGlmICghZGVsZXRlZCkgcmV0dXJuO1xyXG4gICAgICBhd2FpdCBzM0NsaWVudC5kZWxldGUoZGVsZXRlZC5rZXkpO1xyXG4gICAgfSxcclxuXHJcbiAgICBhc3luYyBhY3F1aXJlRmlsZShwYXJhbXM6IEJ5SWQgJiB7IFxyXG4gICAgICBwdXJwb3NlPzogc3RyaW5nIFxyXG4gICAgfSk6IFByb21pc2U8RmlsZVNlbGVjdD4ge1xyXG4gICAgICBjb25zdCBbdXBkYXRlZF0gPSBhd2FpdCBkYlxyXG4gICAgICAgIC51cGRhdGUoc2NoZW1hcy5maWxlcylcclxuICAgICAgICAuc2V0KHsgcmVmQ291bnQ6IHNxbGAke3NjaGVtYXMuZmlsZXMucmVmQ291bnR9ICsgMWAgfSlcclxuICAgICAgICAud2hlcmUoXHJcbiAgICAgICAgICBhbmQoXHJcbiAgICAgICAgICAgIGVxKHNjaGVtYXMuZmlsZXMuaWQsIHBhcmFtcy5pZCksXHJcbiAgICAgICAgICAgIHBhcmFtcy5wdXJwb3NlID8gZXEoc2NoZW1hcy5maWxlcy5wdXJwb3NlLCBwYXJhbXMucHVycG9zZSkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5yZXR1cm5pbmcoKTtcclxuICAgICAgaWYgKCF1cGRhdGVkKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmlsZSBub3QgZm91bmRcIik7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHVwZGF0ZWQ7XHJcbiAgICB9LFxyXG5cclxuICAgIGFzeW5jIHJlbGVhc2VGaWxlKHBhcmFtczogQnlJZCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICBjb25zdCBbdXBkYXRlZF0gPSBhd2FpdCBkYlxyXG4gICAgICAgIC51cGRhdGUoc2NoZW1hcy5maWxlcylcclxuICAgICAgICAuc2V0KHsgcmVmQ291bnQ6IHNxbGAke3NjaGVtYXMuZmlsZXMucmVmQ291bnR9IC0gMWAgfSlcclxuICAgICAgICAud2hlcmUoZXEoc2NoZW1hcy5maWxlcy5pZCwgcGFyYW1zLmlkKSlcclxuICAgICAgICAucmV0dXJuaW5nKCk7XHJcbiAgICAgIGlmICghdXBkYXRlZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkZpbGUgbm90IGZvdW5kXCIpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh1cGRhdGVkLnJlZkNvdW50IDwgMSkge1xyXG4gICAgICAgIGF3YWl0IHRoaXMuZGVsZXRlRmlsZSh7IGlkOiBwYXJhbXMuaWQgfSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgfTtcclxufSIsCiAgICAiaW1wb3J0IHR5cGUgeyBCdW5TUUxEYXRhYmFzZSB9IGZyb20gXCJkcml6emxlLW9ybS9idW4tc3FsXCI7XHJcbmltcG9ydCB7IGNyZWF0ZVJvdXRlcywgdHlwZSBQdXJwb3NlUG9saWN5IH0gZnJvbSBcIi4vcm91dGVzXCI7XHJcbmltcG9ydCB7IGNyZWF0ZVNjaGVtYXMgfSBmcm9tIFwiLi9zY2hlbWFzXCI7XHJcbmltcG9ydCB7IGNyZWF0ZVNlcnZpY2VzIH0gZnJvbSBcIi4vc2VydmljZXNcIjtcclxuaW1wb3J0IHR5cGUgeyBTM0NsaWVudCB9IGZyb20gXCJidW5cIjtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRmlsZXNCYWNrZW5kT3B0aW9uczxUUHVycG9zZXMgZXh0ZW5kcyBzdHJpbmc+IHtcclxuICBkYjogQnVuU1FMRGF0YWJhc2U7XHJcbiAgY2xpZW50OiBTM0NsaWVudDtcclxuICBwb2xpY2llczogUmVjb3JkPFRQdXJwb3NlcywgUHVycG9zZVBvbGljeT47XHJcbiAgcHVibGljQmFzZVVybDogc3RyaW5nO1xyXG4gIHByZXNpZ25FeHBpcmVzSW4/OiBudW1iZXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVGaWxlc0JhY2tlbmQ8Y29uc3QgVFB1cnBvc2UgZXh0ZW5kcyBzdHJpbmc+KFxyXG4gIG9wdGlvbnM6IEZpbGVzQmFja2VuZE9wdGlvbnM8VFB1cnBvc2U+XHJcbikge1xyXG4gIGNvbnN0IHNjaGVtYXMgPSBjcmVhdGVTY2hlbWFzKCk7XHJcbiAgY29uc3Qgc2VydmljZXMgPSBjcmVhdGVTZXJ2aWNlcyh7XHJcbiAgICBkYjogb3B0aW9ucy5kYixcclxuICAgIHNjaGVtYXMsXHJcbiAgICBzM0NsaWVudDogb3B0aW9ucy5jbGllbnQsXHJcbiAgICBwdWJsaWNCYXNlVXJsOiBvcHRpb25zLnB1YmxpY0Jhc2VVcmwsXHJcbiAgICBwcmVzaWduRXhwaXJlc0luOiBvcHRpb25zLnByZXNpZ25FeHBpcmVzSW4sXHJcbiAgfSk7XHJcbiAgY29uc3Qgcm91dGVzID0gY3JlYXRlUm91dGVzKHtcclxuICAgIHNlcnZpY2VzLFxyXG4gICAgcG9saWNpZXM6IG9wdGlvbnMucG9saWNpZXMsXHJcbiAgfSk7XHJcbiAgcmV0dXJuIHtcclxuICAgIHNjaGVtYXMsXHJcbiAgICByb3V0ZXMsXHJcbiAgICBzZXJ2aWNlcyxcclxuICB9IGFzIGNvbnN0O1xyXG59IgogIF0sCiAgIm1hcHBpbmdzIjogIjtBQUFBO0FBV08sU0FBUyxZQUEyQyxDQUN6RCxTQUlBO0FBQUEsRUFFQTtBQUFBLElBQ0U7QUFBQSxJQUNBO0FBQUEsTUFDRTtBQUFBLEVBRUosT0FBTyxJQUFJLE9BQU87QUFBQSxJQUNoQixRQUFRO0FBQUEsRUFDVixDQUFDLEVBQUUsS0FBSyxpQkFBaUIsU0FBUyxRQUFRLFdBQVc7QUFBQSxJQUNuRCxRQUFRLE1BQU0sWUFBWTtBQUFBLElBQzFCLE1BQU0sU0FBUyxTQUFTO0FBQUEsSUFDeEIsSUFBSSxDQUFDLFFBQVE7QUFBQSxNQUNYLE9BQU8sT0FBTyxLQUFLO0FBQUEsUUFDakIsU0FBUztBQUFBLE1BQ1gsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBLElBQUksT0FBTyxZQUFZLGFBQWEsS0FBSyxPQUFPLE9BQU8sU0FBUztBQUFBLE1BQzlELE9BQU8sT0FBTyxLQUFLO0FBQUEsUUFDakIsU0FBUztBQUFBLE1BQ1gsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBLElBQUksT0FBTyxxQkFBcUIsYUFBYSxDQUFDLE9BQU8saUJBQWlCLFNBQVMsS0FBSyxJQUFJLEdBQUc7QUFBQSxNQUN6RixPQUFPLE9BQU8sS0FBSztBQUFBLFFBQ2pCLFNBQVM7QUFBQSxNQUNYLENBQUM7QUFBQSxJQUNIO0FBQUEs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WUFBVyxDQUFDLFFBQTZCO0FBQUEsTUFDN0MsT0FBTyxXQUFXLE1BQU0sR0FDckIsT0FBTyxRQUFRLEtBQUssRUFDcEIsSUFBSSxFQUFFLFVBQVUsTUFBTSxRQUFRLE1BQU0sZUFBZSxDQUFDLEVBQ3BELE1BQU0sR0FBRyxRQUFRLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQyxFQUNyQyxVQUFVO0FBQUEsTUFDYixJQUFJLENBQUMsU0FBUztBQUFBLFFBQ1osTUFBTSxJQUFJLE1BQU0sZ0JBQWdCO0FBQUEsTUFDbEM7QUFBQSxNQUNBLElBQUksUUFBUSxXQUFXLEdBQUc7QUFBQSxRQUN4QixNQUFNLEtBQUssV0FBVyxFQUFFLElBQUksT0FBTyxHQUFHLENBQUM7QUFBQSxNQUN6QztBQUFBO0FBQUEsRUFFSjtBQUFBOzs7QUM5SEssU0FBUyxrQkFBaUQsQ0FDL0QsU0FDQTtBQUFBLEVBQ0EsTUFBTSxVQUFVLGNBQWM7QUFBQSxFQUM5QixNQUFNLFdBQVcsZUFBZTtBQUFBLElBQzlCLElBQUksUUFBUTtBQUFBLElBQ1o7QUFBQSxJQUNBLFVBQVUsUUFBUTtBQUFBLElBQ2xCLGVBQWUsUUFBUTtBQUFBLElBQ3ZCLGtCQUFrQixRQUFRO0FBQUEsRUFDNUIsQ0FBQztBQUFBLEVBQ0QsTUFBTSxTQUFTLGFBQWE7QUFBQSxJQUMxQjtBQUFBLElBQ0EsVUFBVSxRQUFRO0FBQUEsRUFDcEIsQ0FBQztBQUFBLEVBQ0QsT0FBTztBQUFBLElBQ0w7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0Y7QUFBQTsiLAogICJkZWJ1Z0lkIjogIjY1NjNCQkM3NzgzNkY4N0Y2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from "react";
2
+ import { Treaty } from "@elysiajs/eden";
3
+ import { BunSQLDatabase as BunSQLDatabase2 } from "drizzle-orm/bun-sql";
4
+ type Visibility = "private" | "public";
5
+ interface PurposePolicy {
6
+ maxSize?: number;
7
+ allowedMimeTypes?: string[];
8
+ visibility?: Visibility;
9
+ }
10
+ import { S3Client as S3Client2 } from "bun";
11
+ interface FilesBackendOptions<TPurposes extends string> {
12
+ db: BunSQLDatabase2;
13
+ client: S3Client2;
14
+ policies: Record<TPurposes, PurposePolicy>;
15
+ publicBaseUrl: string;
16
+ presignExpiresIn?: number;
17
+ }
18
+ declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {};
19
+ declare function createFilesClient<TBackend extends ReturnType<typeof createFilesBackend<any>>>(domain: string, config?: Treaty.Config);
20
+ type FilesClient = ReturnType<typeof createFilesClient>;
21
+ declare function FilesClientProvider(props: {
22
+ filesClient: FilesClient;
23
+ children: ReactNode;
24
+ });
25
+ declare function useFilesClient();
26
+ import { InferMutationOptions } from "eden2query";
27
+ declare function useUpload(options: InferMutationOptions<FilesClient["api"]["files"]["upload"]["post"]>);
28
+ export { useUpload, useFilesClient, createFilesClient, FilesClientProvider, FilesClient };
@@ -0,0 +1,41 @@
1
+ // src/client/provider.tsx
2
+ import { createContext, useContext } from "react";
3
+ import { jsxDEV } from "react/jsx-dev-runtime";
4
+ var FilesClientContext = createContext(null);
5
+ function FilesClientProvider(props) {
6
+ return /* @__PURE__ */ jsxDEV(FilesClientContext.Provider, {
7
+ value: props.filesClient,
8
+ children: props.children
9
+ }, undefined, false, undefined, this);
10
+ }
11
+ function useFilesClient() {
12
+ const context = useContext(FilesClientContext);
13
+ if (!context) {
14
+ throw new Error("useFilesClient must be used within a FilesClientProvider");
15
+ }
16
+ return context;
17
+ }
18
+ // src/client/client.ts
19
+ import { treaty } from "@elysiajs/eden";
20
+ function createFilesClient(domain, config) {
21
+ return treaty(domain, config);
22
+ }
23
+ // src/client/hooks.ts
24
+ import { useMutation } from "@tanstack/react-query";
25
+ import { edenMutationOptions } from "eden2query";
26
+ function useUpload(options) {
27
+ const filesClient = useFilesClient();
28
+ return useMutation({
29
+ ...options,
30
+ ...edenMutationOptions(filesClient.api.files.upload.post)
31
+ });
32
+ }
33
+ export {
34
+ useUpload,
35
+ useFilesClient,
36
+ createFilesClient,
37
+ FilesClientProvider
38
+ };
39
+
40
+ //# debugId=A2BBBD5C97CF307B64756E2164756E21
41
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjXFxjbGllbnRcXHByb3ZpZGVyLnRzeCIsICJzcmNcXGNsaWVudFxcY2xpZW50LnRzIiwgInNyY1xcY2xpZW50XFxob29rcy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICAgICJpbXBvcnQgeyBjcmVhdGVDb250ZXh0LCB1c2VDb250ZXh0LCB0eXBlIFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xyXG5pbXBvcnQgdHlwZSB7IEZpbGVzQ2xpZW50IH0gZnJvbSBcIi4vY2xpZW50XCI7XHJcblxyXG5cclxuY29uc3QgRmlsZXNDbGllbnRDb250ZXh0ID0gY3JlYXRlQ29udGV4dDxGaWxlc0NsaWVudCB8IG51bGw+KG51bGwpO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIEZpbGVzQ2xpZW50UHJvdmlkZXIocHJvcHM6IHtcclxuICBmaWxlc0NsaWVudDogRmlsZXNDbGllbnQ7XHJcbiAgY2hpbGRyZW46IFJlYWN0Tm9kZTtcclxufSkge1xyXG4gIHJldHVybiAoXHJcbiAgICA8RmlsZXNDbGllbnRDb250ZXh0LlByb3ZpZGVyIHZhbHVlPXtwcm9wcy5maWxlc0NsaWVudH0+XHJcbiAgICAgIHtwcm9wcy5jaGlsZHJlbn1cclxuICAgIDwvRmlsZXNDbGllbnRDb250ZXh0LlByb3ZpZGVyPlxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VGaWxlc0NsaWVudCgpIHtcclxuICBjb25zdCBjb250ZXh0ID0gdXNlQ29udGV4dChGaWxlc0NsaWVudENvbnRleHQpO1xyXG4gIGlmICghY29udGV4dCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwidXNlRmlsZXNDbGllbnQgbXVzdCBiZSB1c2VkIHdpdGhpbiBhIEZpbGVzQ2xpZW50UHJvdmlkZXJcIik7XHJcbiAgfVxyXG4gIHJldHVybiBjb250ZXh0O1xyXG59XHJcbiIsCiAgICAiaW1wb3J0IHsgdHJlYXR5LCB0eXBlIFRyZWF0eSB9IGZyb20gXCJAZWx5c2lhanMvZWRlblwiO1xyXG5pbXBvcnQgdHlwZSB7IGNyZWF0ZUZpbGVzQmFja2VuZCB9IGZyb20gXCIuLi9iYWNrZW5kXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRmlsZXNDbGllbnQ8XHJcbiAgVEJhY2tlbmQgZXh0ZW5kcyBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVGaWxlc0JhY2tlbmQ8YW55Pj5cclxuPihcclxuICBkb21haW46IHN0cmluZyxcclxuICBjb25maWc/OiBUcmVhdHkuQ29uZmlnXHJcbikge1xyXG4gIHJldHVybiB0cmVhdHk8VEJhY2tlbmRbXCJyb3V0ZXNcIl0+KGRvbWFpbiwgY29uZmlnKTtcclxufVxyXG5cclxuZXhwb3J0IHR5cGUgRmlsZXNDbGllbnQgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVGaWxlc0NsaWVudD47IiwKICAgICJpbXBvcnQgeyB1c2VNdXRhdGlvbiwgdHlwZSBVc2VNdXRhdGlvbk9wdGlvbnMgfSBmcm9tIFwiQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5XCI7XHJcbmltcG9ydCB0eXBlIHsgRmlsZXNDbGllbnQgfSBmcm9tIFwiLi9jbGllbnRcIjtcclxuaW1wb3J0IHsgZWRlbk11dGF0aW9uT3B0aW9ucywgdHlwZSBJbmZlck11dGF0aW9uT3B0aW9ucyB9IGZyb20gXCJlZGVuMnF1ZXJ5XCI7XHJcbmltcG9ydCB7IHVzZUZpbGVzQ2xpZW50IH0gZnJvbSBcIi4vcHJvdmlkZXJcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VVcGxvYWQoXHJcbiAgb3B0aW9uczogSW5mZXJNdXRhdGlvbk9wdGlvbnM8RmlsZXNDbGllbnRbXCJhcGlcIl1bXCJmaWxlc1wiXVtcInVwbG9hZFwiXVtcInBvc3RcIl0+XHJcbikge1xyXG4gIGNvbnN0IGZpbGVzQ2xpZW50ID0gdXNlRmlsZXNDbGllbnQoKSA7XHJcbiAgcmV0dXJuIHVzZU11dGF0aW9uKHtcclxuICAgIC4uLm9wdGlvbnMsXHJcbiAgICAuLi5lZGVuTXV0YXRpb25PcHRpb25zKFxyXG4gICAgICBmaWxlc0NsaWVudC5hcGkuZmlsZXMudXBsb2FkLnBvc3QsXHJcbiAgICApLFxyXG4gIH0pO1xyXG59IgogIF0sCiAgIm1hcHBpbmdzIjogIjtBQUFBO0FBQUE7QUFJQSxJQUFNLHFCQUFxQixjQUFrQyxJQUFJO0FBRTFELFNBQVMsbUJBQW1CLENBQUMsT0FHakM7QUFBQSxFQUNELHVCQUNFLE9BRUUsbUJBQW1CLFVBRnJCO0FBQUEsSUFBNkIsT0FBTyxNQUFNO0FBQUEsSUFBMUMsVUFDRyxNQUFNO0FBQUEsS0FEVCxpQ0FFRTtBQUFBO0FBSUMsU0FBUyxjQUFjLEdBQUc7QUFBQSxFQUMvQixNQUFNLFVBQVUsV0FBVyxrQkFBa0I7QUFBQSxFQUM3QyxJQUFJLENBQUMsU0FBUztBQUFBLElBQ1osTUFBTSxJQUFJLE1BQU0sMERBQTBEO0FBQUEsRUFDNUU7QUFBQSxFQUNBLE9BQU87QUFBQTs7QUN0QlQ7QUFHTyxTQUFTLGlCQUVmLENBQ0MsUUFDQSxRQUNBO0FBQUEsRUFDQSxPQUFPLE9BQTJCLFFBQVEsTUFBTTtBQUFBOztBQ1RsRDtBQUVBO0FBR08sU0FBUyxTQUFTLENBQ3ZCLFNBQ0E7QUFBQSxFQUNBLE1BQU0sY0FBYyxlQUFlO0FBQUEsRUFDbkMsT0FBTyxZQUFZO0FBQUEsT0FDZDtBQUFBLE9BQ0Esb0JBQ0QsWUFBWSxJQUFJLE1BQU0sT0FBTyxJQUMvQjtBQUFBLEVBQ0YsQ0FBQztBQUFBOyIsCiAgImRlYnVnSWQiOiAiQTJCQkJENUM5N0NGMzA3QjY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@edkstack/files",
3
+ "description": "File management utilities for EDK Stack",
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "README.md"
9
+ ],
10
+ "exports": {
11
+ "./backend": {
12
+ "import": {
13
+ "types": "./dist/backend/index.d.ts",
14
+ "default": "./dist/backend/index.js"
15
+ }
16
+ },
17
+ "./client": {
18
+ "import": {
19
+ "types": "./dist/client/index.d.ts",
20
+ "default": "./dist/client/index.js"
21
+ }
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "scripts": {
26
+ "build": "bunup",
27
+ "prepublishOnly": "bun run build"
28
+ },
29
+ "keywords": [
30
+ "files",
31
+ "file-management",
32
+ "edkstack",
33
+ "elysia",
34
+ "drizzle"
35
+ ],
36
+ "author": "",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": ""
41
+ },
42
+ "bugs": {
43
+ "url": ""
44
+ },
45
+ "homepage": "",
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "devDependencies": {
50
+ "@types/bun": "latest",
51
+ "@types/react": "^19.2.13",
52
+ "bunup": "^0.16.25"
53
+ },
54
+ "peerDependencies": {
55
+ "@elysiajs/eden": "^1.4.6",
56
+ "@tanstack/react-query": "^5.90.20",
57
+ "drizzle-orm": "^0.45.1",
58
+ "elysia": "^1.4.22",
59
+ "react": "^19.2.4",
60
+ "typescript": "^5"
61
+ },
62
+ "dependencies": {
63
+ "eden2query": "^0.2.0",
64
+ "nanoid": "^5.1.6"
65
+ }
66
+ }