@edkstack/files 0.1.6 → 0.1.8

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.
@@ -0,0 +1,2 @@
1
+ import { a as FileRecord, i as Visibility, n as createFilesBackend, r as PurposePolicy, t as FilesBackendOptions } from "../backend-DpyA_n4-.mjs";
2
+ export { type FileRecord, type FilesBackendOptions, type PurposePolicy, type Visibility, createFilesBackend };
@@ -0,0 +1,3 @@
1
+ import { t as createFilesBackend } from "../backend-BOAJlrA-.mjs";
2
+
3
+ export { createFilesBackend };
@@ -0,0 +1,163 @@
1
+ import { Elysia, t } from "elysia";
2
+ import { nanoid } from "nanoid";
3
+ import { index, integer, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
4
+ import { S3Client } from "bun";
5
+ import { extname } from "path";
6
+ import { and, eq, sql } from "drizzle-orm";
7
+
8
+ //#region src/backend/routes.ts
9
+ function createRoutes(options) {
10
+ const { services, policies } = options;
11
+ return new Elysia({ prefix: "/api" }).post("/files/upload", async ({ status, body }) => {
12
+ const { file, purpose } = body;
13
+ const policy = policies[purpose];
14
+ if (!policy) return status(400, { message: "Purpose not supported" });
15
+ if (policy.maxSize !== void 0 && file.size > policy.maxSize) return status(400, { message: "File size exceeds the maximum allowed size" });
16
+ if (policy.allowedMimeTypes !== void 0 && !policy.allowedMimeTypes.includes(file.type)) return status(400, { message: "File type not allowed" });
17
+ const uploaded = await services.uploadFile({
18
+ file,
19
+ purpose,
20
+ visibility: policy.visibility ?? "private"
21
+ });
22
+ return status(200, {
23
+ id: uploaded.id,
24
+ name: uploaded.name,
25
+ key: uploaded.key,
26
+ size: uploaded.size,
27
+ mimeType: uploaded.mimeType,
28
+ createdAt: uploaded.createdAt
29
+ });
30
+ }, {
31
+ body: UploadRequest(Object.keys(policies)),
32
+ response: {
33
+ 200: FileResponse,
34
+ 400: ErrorResponse,
35
+ 500: ErrorResponse
36
+ }
37
+ });
38
+ }
39
+ function UploadRequest(purposes) {
40
+ return t.Object({
41
+ file: t.File(),
42
+ purpose: t.Union(purposes.map((p) => t.Literal(p)))
43
+ });
44
+ }
45
+ const ErrorResponse = t.Object({ message: t.String() });
46
+ const FileResponse = t.Object({
47
+ id: t.String(),
48
+ name: t.Nullable(t.String()),
49
+ key: t.String(),
50
+ size: t.Number(),
51
+ mimeType: t.String(),
52
+ createdAt: t.Date()
53
+ });
54
+
55
+ //#endregion
56
+ //#region src/backend/schemas.ts
57
+ function createSchemas() {
58
+ return { files: pgTable("files", {
59
+ id: text("id").primaryKey().$defaultFn(() => `file_${nanoid()}`),
60
+ purpose: text("purpose").notNull(),
61
+ name: text("name"),
62
+ key: text("key").notNull().unique(),
63
+ size: integer("size").notNull(),
64
+ mimeType: text("mime_type").notNull().default("application/octet-stream"),
65
+ refCount: integer("ref_count").notNull().default(0),
66
+ visibility: pgEnum("visibility", ["private", "public"])().notNull().default("private"),
67
+ createdAt: timestamp("created_at").notNull().defaultNow(),
68
+ updatedAt: timestamp("updated_at").notNull().defaultNow()
69
+ }, (table) => [index("files_key_idx").on(table.key), index("files_created_at_idx").on(table.createdAt)]) };
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/backend/services.ts
74
+ function createServices(options) {
75
+ const { db, schemas, s3Options, keyPrefix = "files", presignExpiresIn = 3600 } = options;
76
+ const { endpoint } = s3Options;
77
+ const s3Client = new S3Client(s3Options);
78
+ return {
79
+ async getFile(params) {
80
+ const [found] = await db.select().from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
81
+ if (!found) throw new Error("File not found");
82
+ return found;
83
+ },
84
+ async getUrl(params) {
85
+ const [found] = await db.select({
86
+ key: schemas.files.key,
87
+ visibility: schemas.files.visibility
88
+ }).from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
89
+ if (!found) throw new Error("File not found");
90
+ if (found.visibility === "public") return `${endpoint}/${found.key}`;
91
+ return s3Client.presign(found.key, { expiresIn: presignExpiresIn });
92
+ },
93
+ async uploadFile(params) {
94
+ const id = nanoid();
95
+ const ext = extname(params.file.name);
96
+ const key = [
97
+ keyPrefix,
98
+ params.visibility,
99
+ params.purpose,
100
+ `${id}${ext}`
101
+ ].join("/");
102
+ const s3file = s3Client.file(key);
103
+ await s3file.write(params.file, {
104
+ type: params.file.type,
105
+ acl: params.visibility === "public" ? "public-read" : "private"
106
+ });
107
+ try {
108
+ const [created] = await db.insert(schemas.files).values({
109
+ purpose: params.purpose,
110
+ key,
111
+ size: s3file.size,
112
+ name: s3file.name ?? null,
113
+ mimeType: s3file.type,
114
+ visibility: params.visibility
115
+ }).returning();
116
+ if (!created) throw new Error("Failed to create file record");
117
+ return created;
118
+ } catch (error) {
119
+ await s3file.delete().catch();
120
+ throw error;
121
+ }
122
+ },
123
+ async deleteFile(params) {
124
+ const [deleted] = await db.delete(schemas.files).where(eq(schemas.files.id, params.id)).returning();
125
+ if (!deleted) return;
126
+ await s3Client.delete(deleted.key);
127
+ },
128
+ async acquireFile(params) {
129
+ 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) : void 0)).returning();
130
+ if (!updated) throw new Error("File not found");
131
+ return updated;
132
+ },
133
+ async releaseFile(params) {
134
+ const [updated] = await db.update(schemas.files).set({ refCount: sql`${schemas.files.refCount} - 1` }).where(eq(schemas.files.id, params.id)).returning();
135
+ if (!updated) throw new Error("File not found");
136
+ if (updated.refCount < 1) await this.deleteFile({ id: params.id });
137
+ }
138
+ };
139
+ }
140
+
141
+ //#endregion
142
+ //#region src/backend/backend.ts
143
+ function createFilesBackend(options) {
144
+ const schemas = createSchemas();
145
+ const services = createServices({
146
+ db: options.db,
147
+ schemas,
148
+ s3Options: options.s3Options,
149
+ presignExpiresIn: options.presignExpiresIn
150
+ });
151
+ return {
152
+ schemas,
153
+ routes: createRoutes({
154
+ services,
155
+ policies: options.policies
156
+ }),
157
+ services
158
+ };
159
+ }
160
+
161
+ //#endregion
162
+ export { createFilesBackend as t };
163
+ //# sourceMappingURL=backend-BOAJlrA-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-BOAJlrA-.mjs","names":[],"sources":["../src/backend/routes.ts","../src/backend/schemas.ts","../src/backend/services.ts","../src/backend/backend.ts"],"sourcesContent":["import { Elysia, t } from \"elysia\";\r\nimport type { Services } from \"./services\";\r\n\r\nexport type Visibility = \"private\" | \"public\";\r\n\r\nexport interface PurposePolicy {\r\n maxSize?: number;\r\n allowedMimeTypes?: string[];\r\n visibility?: Visibility;\r\n}\r\n\r\nexport function createRoutes<const TPurpose extends string>(\r\n options: {\r\n services: Services;\r\n policies: Record<TPurpose, PurposePolicy>\r\n }\r\n) {\r\n \r\n const { \r\n services, \r\n policies,\r\n } = options;\r\n\r\n return new Elysia({\r\n prefix: \"/api\",\r\n }).post(\"/files/upload\", async ({ status, body }) => {\r\n const { file, purpose } = body;\r\n const policy = policies[purpose as TPurpose];\r\n if (!policy) {\r\n return status(400, {\r\n message: \"Purpose not supported\",\r\n });\r\n }\r\n if (policy.maxSize !== undefined && file.size > policy.maxSize) {\r\n return status(400, {\r\n message: \"File size exceeds the maximum allowed size\",\r\n });\r\n }\r\n if (policy.allowedMimeTypes !== undefined && !policy.allowedMimeTypes.includes(file.type)) {\r\n return status(400, {\r\n message: \"File type not allowed\",\r\n });\r\n }\r\n const uploaded = await services.uploadFile({ \r\n file, \r\n purpose, \r\n visibility: policy.visibility ?? \"private\" \r\n });\r\n return status(200, {\r\n id: uploaded.id,\r\n name: uploaded.name,\r\n key: uploaded.key,\r\n size: uploaded.size,\r\n mimeType: uploaded.mimeType,\r\n createdAt: uploaded.createdAt,\r\n });\r\n }, {\r\n body: UploadRequest(Object.keys(policies) as TPurpose[]),\r\n response: {\r\n 200: FileResponse,\r\n 400: ErrorResponse,\r\n 500: ErrorResponse,\r\n }\r\n });\r\n}\r\n\r\nfunction UploadRequest<const TPurpose extends string>(\r\n purposes: TPurpose[]\r\n) {\r\n return t.Object({\r\n file: t.File(),\r\n purpose: t.Union(\r\n purposes.map((p) => t.Literal(p)) as [\r\n ReturnType<typeof t.Literal<TPurpose>>,\r\n ...ReturnType<typeof t.Literal<TPurpose>>[],\r\n ]\r\n )\r\n });\r\n}\r\n\r\nconst ErrorResponse = t.Object({\r\n message: t.String(),\r\n});\r\n\r\nconst FileResponse = t.Object({\r\n id: t.String(),\r\n name: t.Nullable(t.String()),\r\n key: t.String(),\r\n size: t.Number(),\r\n mimeType: t.String(),\r\n createdAt: t.Date(),\r\n});","import { nanoid } from \"nanoid\";\r\nimport { index, integer, pgTable, text, timestamp, pgEnum } from \"drizzle-orm/pg-core\";\r\n\r\n\r\nexport type Schemas = ReturnType<typeof createSchemas>;\r\nexport type FileSchema = Schemas[\"files\"];\r\nexport type FileRecord = FileSchema[\"$inferSelect\"];\r\n\r\nexport function createSchemas() {\r\n\r\n const files = pgTable(\"files\", {\r\n id: text(\"id\").primaryKey().$defaultFn(() => `file_${nanoid()}`),\r\n purpose: text(\"purpose\").notNull(),\r\n name: text(\"name\"),\r\n key: text(\"key\").notNull().unique(),\r\n size: integer(\"size\").notNull(),\r\n mimeType: text(\"mime_type\").notNull().default(\"application/octet-stream\"),\r\n refCount: integer(\"ref_count\").notNull().default(0),\r\n visibility: pgEnum(\"visibility\", [\"private\", \"public\"])().notNull().default(\"private\"),\r\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\r\n updatedAt: timestamp(\"updated_at\").notNull().defaultNow(),\r\n }, (table) => [\r\n index(\"files_key_idx\").on(table.key),\r\n index(\"files_created_at_idx\").on(table.createdAt),\r\n ]);\r\n\r\n return {\r\n files,\r\n }\r\n}","import { S3Client, type S3Options } from \"bun\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { extname } from \"path\";\r\nimport { eq, sql, lt, and } from \"drizzle-orm\";\r\nimport type { Schemas, FileRecord } from \"./schemas\";\r\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\r\n\r\nexport type Services = ReturnType<typeof createServices>;\r\n\r\ntype ById = { id: string };\r\n\r\nexport function createServices(\r\n options: {\r\n db: PgDatabase<any, any, any>;\r\n schemas: Schemas;\r\n s3Options: S3Options;\r\n keyPrefix?: string;\r\n presignExpiresIn?: number;\r\n }\r\n) {\r\n const { \r\n db, \r\n schemas, \r\n s3Options,\r\n keyPrefix = \"files\",\r\n presignExpiresIn = 3600\r\n } = options;\r\n \r\n const { endpoint } = s3Options;\r\n const s3Client = new S3Client(s3Options);\r\n\r\n return {\r\n\r\n async getFile(params: ById): Promise<FileRecord> {\r\n const [found] = await db\r\n .select()\r\n .from(schemas.files)\r\n .where(eq(schemas.files.id, params.id))\r\n .limit(1);\r\n if (!found) {\r\n throw new Error(\"File not found\");\r\n }\r\n return found;\r\n },\r\n\r\n async getUrl(params: ById): Promise<string> {\r\n const [found] = await db\r\n .select({ \r\n key: schemas.files.key,\r\n visibility: schemas.files.visibility,\r\n })\r\n .from(schemas.files)\r\n .where(eq(schemas.files.id, params.id))\r\n .limit(1);\r\n if (!found) {\r\n throw new Error(\"File not found\");\r\n }\r\n if (found.visibility === \"public\") {\r\n return `${endpoint}/${found.key}`;\r\n }\r\n return s3Client.presign(found.key, { expiresIn: presignExpiresIn });\r\n },\r\n\r\n async uploadFile(params: {\r\n file: File;\r\n purpose: string;\r\n visibility: \"private\" | \"public\";\r\n }): Promise<FileRecord> {\r\n const id = nanoid();\r\n const ext = extname(params.file.name);\r\n const key = [keyPrefix, params.visibility, params.purpose, `${id}${ext}`].join(\"/\");\r\n const s3file = s3Client.file(key);\r\n await s3file.write(params.file, {\r\n type: params.file.type,\r\n acl: params.visibility === \"public\" ? \"public-read\" : \"private\",\r\n });\r\n try {\r\n const [created] = await db.insert(schemas.files)\r\n .values({\r\n purpose: params.purpose,\r\n key,\r\n size: s3file.size,\r\n name: s3file.name ?? null,\r\n mimeType: s3file.type,\r\n visibility: params.visibility,\r\n })\r\n .returning();\r\n if (!created) {\r\n throw new Error(\"Failed to create file record\");\r\n }\r\n return created;\r\n } catch (error) {\r\n await s3file.delete().catch();\r\n throw error;\r\n }\r\n },\r\n\r\n async deleteFile(params: { id: string }): Promise<void> {\r\n const [deleted] = await db\r\n .delete(schemas.files)\r\n .where(eq(schemas.files.id, params.id))\r\n .returning();\r\n if (!deleted) return;\r\n await s3Client.delete(deleted.key);\r\n },\r\n\r\n async acquireFile(params: ById & { \r\n purpose?: string \r\n }): Promise<FileRecord> {\r\n const [updated] = await db\r\n .update(schemas.files)\r\n .set({ refCount: sql`${schemas.files.refCount} + 1` })\r\n .where(\r\n and(\r\n eq(schemas.files.id, params.id),\r\n params.purpose ? eq(schemas.files.purpose, params.purpose) : undefined,\r\n )\r\n )\r\n .returning();\r\n if (!updated) {\r\n throw new Error(\"File not found\");\r\n }\r\n return updated;\r\n },\r\n\r\n async releaseFile(params: ById): Promise<void> {\r\n const [updated] = await db\r\n .update(schemas.files)\r\n .set({ refCount: sql`${schemas.files.refCount} - 1` })\r\n .where(eq(schemas.files.id, params.id))\r\n .returning();\r\n if (!updated) {\r\n throw new Error(\"File not found\");\r\n }\r\n if (updated.refCount < 1) {\r\n await this.deleteFile({ id: params.id });\r\n }\r\n },\r\n };\r\n}","import type { PgDatabase } from \"drizzle-orm/pg-core\";\r\nimport { createRoutes, type PurposePolicy } from \"./routes\";\r\nimport { createSchemas } from \"./schemas\";\r\nimport { createServices } from \"./services\";\r\nimport type { S3Options } from \"bun\";\r\n\r\nexport interface FilesBackendOptions<TPurposes extends string> {\r\n db: PgDatabase<any, any, any>;\r\n s3Options: S3Options;\r\n policies: Record<TPurposes, PurposePolicy>;\r\n presignExpiresIn?: number;\r\n}\r\n\r\nexport function createFilesBackend<const TPurpose extends string>(\r\n options: FilesBackendOptions<TPurpose>\r\n) {\r\n const schemas = createSchemas();\r\n const services = createServices({\r\n db: options.db,\r\n schemas,\r\n s3Options: options.s3Options,\r\n presignExpiresIn: options.presignExpiresIn,\r\n });\r\n const routes = createRoutes({\r\n services,\r\n policies: options.policies,\r\n });\r\n return {\r\n schemas,\r\n routes,\r\n services,\r\n } as const;\r\n}"],"mappings":"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"}
@@ -0,0 +1,482 @@
1
+ import * as elysia from "elysia";
2
+ import { Elysia } from "elysia";
3
+ import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
4
+ import { PgDatabase } from "drizzle-orm/pg-core";
5
+ import { S3Options } from "bun";
6
+
7
+ //#region src/backend/schemas.d.ts
8
+ type Schemas = ReturnType<typeof createSchemas>;
9
+ type FileSchema = Schemas["files"];
10
+ type FileRecord = FileSchema["$inferSelect"];
11
+ declare function createSchemas(): {
12
+ files: drizzle_orm_pg_core0.PgTableWithColumns<{
13
+ name: "files";
14
+ schema: undefined;
15
+ columns: {
16
+ id: drizzle_orm_pg_core0.PgColumn<{
17
+ name: "id";
18
+ tableName: "files";
19
+ dataType: "string";
20
+ columnType: "PgText";
21
+ data: string;
22
+ driverParam: string;
23
+ notNull: true;
24
+ hasDefault: true;
25
+ isPrimaryKey: true;
26
+ isAutoincrement: false;
27
+ hasRuntimeDefault: true;
28
+ enumValues: [string, ...string[]];
29
+ baseColumn: never;
30
+ identity: undefined;
31
+ generated: undefined;
32
+ }, {}, {}>;
33
+ purpose: drizzle_orm_pg_core0.PgColumn<{
34
+ name: "purpose";
35
+ tableName: "files";
36
+ dataType: "string";
37
+ columnType: "PgText";
38
+ data: string;
39
+ driverParam: string;
40
+ notNull: true;
41
+ hasDefault: false;
42
+ isPrimaryKey: false;
43
+ isAutoincrement: false;
44
+ hasRuntimeDefault: false;
45
+ enumValues: [string, ...string[]];
46
+ baseColumn: never;
47
+ identity: undefined;
48
+ generated: undefined;
49
+ }, {}, {}>;
50
+ name: drizzle_orm_pg_core0.PgColumn<{
51
+ name: "name";
52
+ tableName: "files";
53
+ dataType: "string";
54
+ columnType: "PgText";
55
+ data: string;
56
+ driverParam: string;
57
+ notNull: false;
58
+ hasDefault: false;
59
+ isPrimaryKey: false;
60
+ isAutoincrement: false;
61
+ hasRuntimeDefault: false;
62
+ enumValues: [string, ...string[]];
63
+ baseColumn: never;
64
+ identity: undefined;
65
+ generated: undefined;
66
+ }, {}, {}>;
67
+ key: drizzle_orm_pg_core0.PgColumn<{
68
+ name: "key";
69
+ tableName: "files";
70
+ dataType: "string";
71
+ columnType: "PgText";
72
+ data: string;
73
+ driverParam: string;
74
+ notNull: true;
75
+ hasDefault: false;
76
+ isPrimaryKey: false;
77
+ isAutoincrement: false;
78
+ hasRuntimeDefault: false;
79
+ enumValues: [string, ...string[]];
80
+ baseColumn: never;
81
+ identity: undefined;
82
+ generated: undefined;
83
+ }, {}, {}>;
84
+ size: drizzle_orm_pg_core0.PgColumn<{
85
+ name: "size";
86
+ tableName: "files";
87
+ dataType: "number";
88
+ columnType: "PgInteger";
89
+ data: number;
90
+ driverParam: string | number;
91
+ notNull: true;
92
+ hasDefault: false;
93
+ isPrimaryKey: false;
94
+ isAutoincrement: false;
95
+ hasRuntimeDefault: false;
96
+ enumValues: undefined;
97
+ baseColumn: never;
98
+ identity: undefined;
99
+ generated: undefined;
100
+ }, {}, {}>;
101
+ mimeType: drizzle_orm_pg_core0.PgColumn<{
102
+ name: "mime_type";
103
+ tableName: "files";
104
+ dataType: "string";
105
+ columnType: "PgText";
106
+ data: string;
107
+ driverParam: string;
108
+ notNull: true;
109
+ hasDefault: true;
110
+ isPrimaryKey: false;
111
+ isAutoincrement: false;
112
+ hasRuntimeDefault: false;
113
+ enumValues: [string, ...string[]];
114
+ baseColumn: never;
115
+ identity: undefined;
116
+ generated: undefined;
117
+ }, {}, {}>;
118
+ refCount: drizzle_orm_pg_core0.PgColumn<{
119
+ name: "ref_count";
120
+ tableName: "files";
121
+ dataType: "number";
122
+ columnType: "PgInteger";
123
+ data: number;
124
+ driverParam: string | number;
125
+ notNull: true;
126
+ hasDefault: true;
127
+ isPrimaryKey: false;
128
+ isAutoincrement: false;
129
+ hasRuntimeDefault: false;
130
+ enumValues: undefined;
131
+ baseColumn: never;
132
+ identity: undefined;
133
+ generated: undefined;
134
+ }, {}, {}>;
135
+ visibility: drizzle_orm_pg_core0.PgColumn<{
136
+ name: "visibility";
137
+ tableName: "files";
138
+ dataType: "string";
139
+ columnType: "PgEnumColumn";
140
+ data: "private" | "public";
141
+ driverParam: string;
142
+ notNull: true;
143
+ hasDefault: true;
144
+ isPrimaryKey: false;
145
+ isAutoincrement: false;
146
+ hasRuntimeDefault: false;
147
+ enumValues: ["private", "public"];
148
+ baseColumn: never;
149
+ identity: undefined;
150
+ generated: undefined;
151
+ }, {}, {}>;
152
+ createdAt: drizzle_orm_pg_core0.PgColumn<{
153
+ name: "created_at";
154
+ tableName: "files";
155
+ dataType: "date";
156
+ columnType: "PgTimestamp";
157
+ data: Date;
158
+ driverParam: string;
159
+ notNull: true;
160
+ hasDefault: true;
161
+ isPrimaryKey: false;
162
+ isAutoincrement: false;
163
+ hasRuntimeDefault: false;
164
+ enumValues: undefined;
165
+ baseColumn: never;
166
+ identity: undefined;
167
+ generated: undefined;
168
+ }, {}, {}>;
169
+ updatedAt: drizzle_orm_pg_core0.PgColumn<{
170
+ name: "updated_at";
171
+ tableName: "files";
172
+ dataType: "date";
173
+ columnType: "PgTimestamp";
174
+ data: Date;
175
+ driverParam: string;
176
+ notNull: true;
177
+ hasDefault: true;
178
+ isPrimaryKey: false;
179
+ isAutoincrement: false;
180
+ hasRuntimeDefault: false;
181
+ enumValues: undefined;
182
+ baseColumn: never;
183
+ identity: undefined;
184
+ generated: undefined;
185
+ }, {}, {}>;
186
+ };
187
+ dialect: "pg";
188
+ }>;
189
+ };
190
+ //#endregion
191
+ //#region src/backend/routes.d.ts
192
+ type Visibility = "private" | "public";
193
+ interface PurposePolicy {
194
+ maxSize?: number;
195
+ allowedMimeTypes?: string[];
196
+ visibility?: Visibility;
197
+ }
198
+ //#endregion
199
+ //#region src/backend/backend.d.ts
200
+ interface FilesBackendOptions<TPurposes extends string> {
201
+ db: PgDatabase<any, any, any>;
202
+ s3Options: S3Options;
203
+ policies: Record<TPurposes, PurposePolicy>;
204
+ presignExpiresIn?: number;
205
+ }
206
+ declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {
207
+ readonly schemas: {
208
+ files: drizzle_orm_pg_core0.PgTableWithColumns<{
209
+ name: "files";
210
+ schema: undefined;
211
+ columns: {
212
+ id: drizzle_orm_pg_core0.PgColumn<{
213
+ name: "id";
214
+ tableName: "files";
215
+ dataType: "string";
216
+ columnType: "PgText";
217
+ data: string;
218
+ driverParam: string;
219
+ notNull: true;
220
+ hasDefault: true;
221
+ isPrimaryKey: true;
222
+ isAutoincrement: false;
223
+ hasRuntimeDefault: true;
224
+ enumValues: [string, ...string[]];
225
+ baseColumn: never;
226
+ identity: undefined;
227
+ generated: undefined;
228
+ }, {}, {}>;
229
+ purpose: drizzle_orm_pg_core0.PgColumn<{
230
+ name: "purpose";
231
+ tableName: "files";
232
+ dataType: "string";
233
+ columnType: "PgText";
234
+ data: string;
235
+ driverParam: string;
236
+ notNull: true;
237
+ hasDefault: false;
238
+ isPrimaryKey: false;
239
+ isAutoincrement: false;
240
+ hasRuntimeDefault: false;
241
+ enumValues: [string, ...string[]];
242
+ baseColumn: never;
243
+ identity: undefined;
244
+ generated: undefined;
245
+ }, {}, {}>;
246
+ name: drizzle_orm_pg_core0.PgColumn<{
247
+ name: "name";
248
+ tableName: "files";
249
+ dataType: "string";
250
+ columnType: "PgText";
251
+ data: string;
252
+ driverParam: string;
253
+ notNull: false;
254
+ hasDefault: false;
255
+ isPrimaryKey: false;
256
+ isAutoincrement: false;
257
+ hasRuntimeDefault: false;
258
+ enumValues: [string, ...string[]];
259
+ baseColumn: never;
260
+ identity: undefined;
261
+ generated: undefined;
262
+ }, {}, {}>;
263
+ key: drizzle_orm_pg_core0.PgColumn<{
264
+ name: "key";
265
+ tableName: "files";
266
+ dataType: "string";
267
+ columnType: "PgText";
268
+ data: string;
269
+ driverParam: string;
270
+ notNull: true;
271
+ hasDefault: false;
272
+ isPrimaryKey: false;
273
+ isAutoincrement: false;
274
+ hasRuntimeDefault: false;
275
+ enumValues: [string, ...string[]];
276
+ baseColumn: never;
277
+ identity: undefined;
278
+ generated: undefined;
279
+ }, {}, {}>;
280
+ size: drizzle_orm_pg_core0.PgColumn<{
281
+ name: "size";
282
+ tableName: "files";
283
+ dataType: "number";
284
+ columnType: "PgInteger";
285
+ data: number;
286
+ driverParam: string | number;
287
+ notNull: true;
288
+ hasDefault: false;
289
+ isPrimaryKey: false;
290
+ isAutoincrement: false;
291
+ hasRuntimeDefault: false;
292
+ enumValues: undefined;
293
+ baseColumn: never;
294
+ identity: undefined;
295
+ generated: undefined;
296
+ }, {}, {}>;
297
+ mimeType: drizzle_orm_pg_core0.PgColumn<{
298
+ name: "mime_type";
299
+ tableName: "files";
300
+ dataType: "string";
301
+ columnType: "PgText";
302
+ data: string;
303
+ driverParam: string;
304
+ notNull: true;
305
+ hasDefault: true;
306
+ isPrimaryKey: false;
307
+ isAutoincrement: false;
308
+ hasRuntimeDefault: false;
309
+ enumValues: [string, ...string[]];
310
+ baseColumn: never;
311
+ identity: undefined;
312
+ generated: undefined;
313
+ }, {}, {}>;
314
+ refCount: drizzle_orm_pg_core0.PgColumn<{
315
+ name: "ref_count";
316
+ tableName: "files";
317
+ dataType: "number";
318
+ columnType: "PgInteger";
319
+ data: number;
320
+ driverParam: string | number;
321
+ notNull: true;
322
+ hasDefault: true;
323
+ isPrimaryKey: false;
324
+ isAutoincrement: false;
325
+ hasRuntimeDefault: false;
326
+ enumValues: undefined;
327
+ baseColumn: never;
328
+ identity: undefined;
329
+ generated: undefined;
330
+ }, {}, {}>;
331
+ visibility: drizzle_orm_pg_core0.PgColumn<{
332
+ name: "visibility";
333
+ tableName: "files";
334
+ dataType: "string";
335
+ columnType: "PgEnumColumn";
336
+ data: "private" | "public";
337
+ driverParam: string;
338
+ notNull: true;
339
+ hasDefault: true;
340
+ isPrimaryKey: false;
341
+ isAutoincrement: false;
342
+ hasRuntimeDefault: false;
343
+ enumValues: ["private", "public"];
344
+ baseColumn: never;
345
+ identity: undefined;
346
+ generated: undefined;
347
+ }, {}, {}>;
348
+ createdAt: drizzle_orm_pg_core0.PgColumn<{
349
+ name: "created_at";
350
+ tableName: "files";
351
+ dataType: "date";
352
+ columnType: "PgTimestamp";
353
+ data: Date;
354
+ driverParam: string;
355
+ notNull: true;
356
+ hasDefault: true;
357
+ isPrimaryKey: false;
358
+ isAutoincrement: false;
359
+ hasRuntimeDefault: false;
360
+ enumValues: undefined;
361
+ baseColumn: never;
362
+ identity: undefined;
363
+ generated: undefined;
364
+ }, {}, {}>;
365
+ updatedAt: drizzle_orm_pg_core0.PgColumn<{
366
+ name: "updated_at";
367
+ tableName: "files";
368
+ dataType: "date";
369
+ columnType: "PgTimestamp";
370
+ data: Date;
371
+ driverParam: string;
372
+ notNull: true;
373
+ hasDefault: true;
374
+ isPrimaryKey: false;
375
+ isAutoincrement: false;
376
+ hasRuntimeDefault: false;
377
+ enumValues: undefined;
378
+ baseColumn: never;
379
+ identity: undefined;
380
+ generated: undefined;
381
+ }, {}, {}>;
382
+ };
383
+ dialect: "pg";
384
+ }>;
385
+ };
386
+ readonly routes: elysia.default<"/api", {
387
+ decorator: {};
388
+ store: {};
389
+ derive: {};
390
+ resolve: {};
391
+ }, {
392
+ typebox: {};
393
+ error: {};
394
+ }, {
395
+ schema: {};
396
+ standaloneSchema: {};
397
+ macro: {};
398
+ macroFn: {};
399
+ parser: {};
400
+ response: {};
401
+ }, {
402
+ api: {
403
+ files: {
404
+ upload: {
405
+ post: {
406
+ body: {
407
+ purpose: TPurpose;
408
+ file: File;
409
+ };
410
+ params: {};
411
+ query: unknown;
412
+ headers: unknown;
413
+ response: {
414
+ 200: {
415
+ id: string;
416
+ name: string | null;
417
+ key: string;
418
+ size: number;
419
+ mimeType: string;
420
+ createdAt: Date;
421
+ };
422
+ 400: {
423
+ message: string;
424
+ };
425
+ 500: {
426
+ message: string;
427
+ };
428
+ 422: {
429
+ type: "validation";
430
+ on: string;
431
+ summary?: string;
432
+ message?: string;
433
+ found?: unknown;
434
+ property?: string;
435
+ expected?: string;
436
+ };
437
+ };
438
+ };
439
+ };
440
+ };
441
+ };
442
+ }, {
443
+ derive: {};
444
+ resolve: {};
445
+ schema: {};
446
+ standaloneSchema: {};
447
+ response: {};
448
+ }, {
449
+ derive: {};
450
+ resolve: {};
451
+ schema: {};
452
+ standaloneSchema: {};
453
+ response: {};
454
+ }>;
455
+ readonly services: {
456
+ getFile(params: {
457
+ id: string;
458
+ }): Promise<FileRecord>;
459
+ getUrl(params: {
460
+ id: string;
461
+ }): Promise<string>;
462
+ uploadFile(params: {
463
+ file: File;
464
+ purpose: string;
465
+ visibility: "private" | "public";
466
+ }): Promise<FileRecord>;
467
+ deleteFile(params: {
468
+ id: string;
469
+ }): Promise<void>;
470
+ acquireFile(params: {
471
+ id: string;
472
+ } & {
473
+ purpose?: string;
474
+ }): Promise<FileRecord>;
475
+ releaseFile(params: {
476
+ id: string;
477
+ }): Promise<void>;
478
+ };
479
+ };
480
+ //#endregion
481
+ export { FileRecord as a, Visibility as i, createFilesBackend as n, PurposePolicy as r, FilesBackendOptions as t };
482
+ //# sourceMappingURL=backend-DpyA_n4-.d.mts.map
@@ -0,0 +1,101 @@
1
+ import { n as createFilesBackend } from "../backend-DpyA_n4-.mjs";
2
+ import "../backend/index.mjs";
3
+ import { ReactNode } from "react";
4
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+ import * as _elysiajs_eden0 from "@elysiajs/eden";
6
+ import { Treaty } from "@elysiajs/eden";
7
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
8
+ import { InferMutationOptions } from "eden2query";
9
+
10
+ //#region src/client/client.d.ts
11
+ declare function createFilesClient<TBackend extends ReturnType<typeof createFilesBackend<any>>>(domain: string, config?: Treaty.Config): Treaty.Create<TBackend["routes"]>;
12
+ type FilesClient = ReturnType<typeof createFilesClient>;
13
+ //#endregion
14
+ //#region src/client/provider.d.ts
15
+ declare function FilesClientProvider(props: {
16
+ filesClient: FilesClient;
17
+ children: ReactNode;
18
+ }): react_jsx_runtime0.JSX.Element;
19
+ declare function useFilesClient(): {
20
+ api: {
21
+ files: {
22
+ upload: {
23
+ post: (body: {
24
+ purpose: any;
25
+ file: File | Bun.BunFile;
26
+ }, options?: {
27
+ headers?: Record<string, unknown> | undefined;
28
+ query?: Record<string, unknown> | undefined;
29
+ fetch?: RequestInit | undefined;
30
+ } | undefined) => Promise<_elysiajs_eden0.Treaty.TreatyResponse<{
31
+ 200: {
32
+ id: string;
33
+ name: string | null;
34
+ key: string;
35
+ size: number;
36
+ mimeType: string;
37
+ createdAt: Date;
38
+ };
39
+ 400: {
40
+ message: string;
41
+ };
42
+ 500: {
43
+ message: string;
44
+ };
45
+ 422: {
46
+ type: "validation";
47
+ on: string;
48
+ summary?: string;
49
+ message?: string;
50
+ found?: unknown;
51
+ property?: string;
52
+ expected?: string;
53
+ };
54
+ }>>;
55
+ };
56
+ };
57
+ };
58
+ };
59
+ //#endregion
60
+ //#region src/client/hooks.d.ts
61
+ declare function useUpload(options: InferMutationOptions<FilesClient["api"]["files"]["upload"]["post"]>): _tanstack_react_query0.UseMutationResult<{
62
+ id: string;
63
+ name: string | null;
64
+ key: string;
65
+ size: number;
66
+ mimeType: string;
67
+ createdAt: Date;
68
+ } | null, {
69
+ status: 400;
70
+ value: {
71
+ message: string;
72
+ };
73
+ } | {
74
+ status: 500;
75
+ value: {
76
+ message: string;
77
+ };
78
+ } | {
79
+ status: 422;
80
+ value: {
81
+ type: "validation";
82
+ on: string;
83
+ summary?: string;
84
+ message?: string;
85
+ found?: unknown;
86
+ property?: string;
87
+ expected?: string;
88
+ };
89
+ }, {
90
+ headers?: Record<string, unknown> | undefined;
91
+ query?: Record<string, unknown> | undefined;
92
+ fetch?: RequestInit | undefined;
93
+ } & {
94
+ body: {
95
+ purpose: any;
96
+ file: File | Bun.BunFile;
97
+ };
98
+ }, unknown>;
99
+ //#endregion
100
+ export { type FilesClient, FilesClientProvider, createFilesClient, useFilesClient, useUpload };
101
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,39 @@
1
+ import { createContext, useContext } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { treaty } from "@elysiajs/eden";
4
+ import { useMutation } from "@tanstack/react-query";
5
+ import { edenMutationOptions } from "eden2query";
6
+
7
+ //#region src/client/provider.tsx
8
+ const FilesClientContext = createContext(null);
9
+ function FilesClientProvider(props) {
10
+ return /* @__PURE__ */ jsx(FilesClientContext.Provider, {
11
+ value: props.filesClient,
12
+ children: props.children
13
+ });
14
+ }
15
+ function useFilesClient() {
16
+ const context = useContext(FilesClientContext);
17
+ if (!context) throw new Error("useFilesClient must be used within a FilesClientProvider");
18
+ return context;
19
+ }
20
+
21
+ //#endregion
22
+ //#region src/client/client.ts
23
+ function createFilesClient(domain, config) {
24
+ return treaty(domain, config);
25
+ }
26
+
27
+ //#endregion
28
+ //#region src/client/hooks.ts
29
+ function useUpload(options) {
30
+ const filesClient = useFilesClient();
31
+ return useMutation({
32
+ ...options,
33
+ ...edenMutationOptions(filesClient.api.files.upload.post)
34
+ });
35
+ }
36
+
37
+ //#endregion
38
+ export { FilesClientProvider, createFilesClient, useFilesClient, useUpload };
39
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/provider.tsx","../../src/client/client.ts","../../src/client/hooks.ts"],"sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\r\nimport type { FilesClient } from \"./client\";\r\n\r\n\r\nconst FilesClientContext = createContext<FilesClient | null>(null);\r\n\r\nexport function FilesClientProvider(props: {\r\n filesClient: FilesClient;\r\n children: ReactNode;\r\n}) {\r\n return (\r\n <FilesClientContext.Provider value={props.filesClient}>\r\n {props.children}\r\n </FilesClientContext.Provider>\r\n );\r\n}\r\n\r\nexport function useFilesClient() {\r\n const context = useContext(FilesClientContext);\r\n if (!context) {\r\n throw new Error(\"useFilesClient must be used within a FilesClientProvider\");\r\n }\r\n return context;\r\n}\r\n","import { treaty, type Treaty } from \"@elysiajs/eden\";\r\nimport type { createFilesBackend } from \"../backend\";\r\n\r\nexport function createFilesClient<\r\n TBackend extends ReturnType<typeof createFilesBackend<any>>\r\n>(\r\n domain: string,\r\n config?: Treaty.Config\r\n) {\r\n return treaty<TBackend[\"routes\"]>(domain, config);\r\n}\r\n\r\nexport type FilesClient = ReturnType<typeof createFilesClient>;","import { useMutation, type UseMutationOptions } from \"@tanstack/react-query\";\r\nimport type { FilesClient } from \"./client\";\r\nimport { edenMutationOptions, type InferMutationOptions } from \"eden2query\";\r\nimport { useFilesClient } from \"./provider\";\r\n\r\nexport function useUpload(\r\n options: InferMutationOptions<FilesClient[\"api\"][\"files\"][\"upload\"][\"post\"]>\r\n) {\r\n const filesClient = useFilesClient() ;\r\n return useMutation({\r\n ...options,\r\n ...edenMutationOptions(\r\n filesClient.api.files.upload.post,\r\n ),\r\n });\r\n}"],"mappings":";;;;;;;AAIA,MAAM,qBAAqB,cAAkC,KAAK;AAElE,SAAgB,oBAAoB,OAGjC;AACD,QACE,oBAAC,mBAAmB;EAAS,OAAO,MAAM;YACvC,MAAM;GACqB;;AAIlC,SAAgB,iBAAiB;CAC/B,MAAM,UAAU,WAAW,mBAAmB;AAC9C,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,2DAA2D;AAE7E,QAAO;;;;;ACnBT,SAAgB,kBAGd,QACA,QACA;AACA,QAAO,OAA2B,QAAQ,OAAO;;;;;ACJnD,SAAgB,UACd,SACA;CACA,MAAM,cAAc,gBAAgB;AACpC,QAAO,YAAY;EACjB,GAAG;EACH,GAAG,oBACD,YAAY,IAAI,MAAM,OAAO,KAC9B;EACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { a as FileRecord, i as Visibility, n as createFilesBackend, r as PurposePolicy, t as FilesBackendOptions } from "./backend-DpyA_n4-.mjs";
2
+ import "./backend/index.mjs";
3
+ export { FileRecord, FilesBackendOptions, PurposePolicy, Visibility, createFilesBackend };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { t as createFilesBackend } from "./backend-BOAJlrA-.mjs";
2
+ import "./backend/index.mjs";
3
+
4
+ export { createFilesBackend };
package/package.json CHANGED
@@ -1,37 +1,21 @@
1
1
  {
2
2
  "name": "@edkstack/files",
3
3
  "description": "File management utilities for EDK Stack",
4
- "version": "0.1.6",
4
+ "version": "0.1.8",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
8
8
  "README.md"
9
9
  ],
10
- "module": "./dist/index.js",
11
10
  "types": "./dist/index.d.ts",
12
11
  "exports": {
13
- ".": {
14
- "import": {
15
- "types": "./dist/index.d.ts",
16
- "default": "./dist/index.js"
17
- }
18
- },
19
- "./backend": {
20
- "import": {
21
- "types": "./dist/backend/index.d.ts",
22
- "default": "./dist/backend/index.js"
23
- }
24
- },
25
- "./client": {
26
- "import": {
27
- "types": "./dist/client/index.d.ts",
28
- "default": "./dist/client/index.js"
29
- }
30
- },
12
+ ".": "./dist/index.mjs",
13
+ "./backend": "./dist/backend/index.mjs",
14
+ "./client": "./dist/client/index.mjs",
31
15
  "./package.json": "./package.json"
32
16
  },
33
17
  "scripts": {
34
- "build": "bunup",
18
+ "build": "tsdown",
35
19
  "prepublishOnly": "bun run build"
36
20
  },
37
21
  "keywords": [
@@ -57,7 +41,7 @@
57
41
  "devDependencies": {
58
42
  "@types/bun": "latest",
59
43
  "@types/react": "^19.2.13",
60
- "bunup": "^0.16.25"
44
+ "tsdown": "^0.20.3"
61
45
  },
62
46
  "peerDependencies": {
63
47
  "@elysiajs/eden": "^1.4.6",
@@ -1,21 +0,0 @@
1
- import { PgDatabase as PgDatabase2 } from "drizzle-orm/pg-core";
2
- type Schemas = ReturnType<typeof createSchemas>;
3
- type FileSchema = Schemas["files"];
4
- type FileRecord = FileSchema["$inferSelect"];
5
- declare function createSchemas(): {};
6
- type Visibility = "private" | "public";
7
- interface PurposePolicy {
8
- maxSize?: number;
9
- allowedMimeTypes?: string[];
10
- visibility?: Visibility;
11
- }
12
- import { S3Options as S3Options2 } from "bun";
13
- interface FilesBackendOptions<TPurposes extends string> {
14
- db: PgDatabase2<any, any, any>;
15
- s3Options: S3Options2;
16
- policies: Record<TPurposes, PurposePolicy>;
17
- publicBaseUrl: string;
18
- presignExpiresIn?: number;
19
- }
20
- declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {};
21
- export { createFilesBackend, Visibility, PurposePolicy, FilesBackendOptions, FileRecord };
@@ -1,10 +0,0 @@
1
- // @bun
2
- import {
3
- createFilesBackend
4
- } from "../shared/chunk-wq7ndb52.js";
5
- export {
6
- createFilesBackend
7
- };
8
-
9
- //# debugId=9C07B894307CE45C64756E2164756E21
10
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICBdLAogICJtYXBwaW5ncyI6ICIiLAogICJkZWJ1Z0lkIjogIjlDMDdCODk0MzA3Q0U0NUM2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
@@ -1,28 +0,0 @@
1
- import { ReactNode } from "react";
2
- import { Treaty } from "@elysiajs/eden";
3
- import { PgDatabase as PgDatabase2 } from "drizzle-orm/pg-core";
4
- type Visibility = "private" | "public";
5
- interface PurposePolicy {
6
- maxSize?: number;
7
- allowedMimeTypes?: string[];
8
- visibility?: Visibility;
9
- }
10
- import { S3Options as S3Options2 } from "bun";
11
- interface FilesBackendOptions<TPurposes extends string> {
12
- db: PgDatabase2<any, any, any>;
13
- s3Options: S3Options2;
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 };
@@ -1,42 +0,0 @@
1
- // @bun
2
- // src/client/provider.tsx
3
- import { createContext, useContext } from "react";
4
- import { jsxDEV } from "react/jsx-dev-runtime";
5
- var FilesClientContext = createContext(null);
6
- function FilesClientProvider(props) {
7
- return /* @__PURE__ */ jsxDEV(FilesClientContext.Provider, {
8
- value: props.filesClient,
9
- children: props.children
10
- }, undefined, false, undefined, this);
11
- }
12
- function useFilesClient() {
13
- const context = useContext(FilesClientContext);
14
- if (!context) {
15
- throw new Error("useFilesClient must be used within a FilesClientProvider");
16
- }
17
- return context;
18
- }
19
- // src/client/client.ts
20
- import { treaty } from "@elysiajs/eden";
21
- function createFilesClient(domain, config) {
22
- return treaty(domain, config);
23
- }
24
- // src/client/hooks.ts
25
- import { useMutation } from "@tanstack/react-query";
26
- import { edenMutationOptions } from "eden2query";
27
- function useUpload(options) {
28
- const filesClient = useFilesClient();
29
- return useMutation({
30
- ...options,
31
- ...edenMutationOptions(filesClient.api.files.upload.post)
32
- });
33
- }
34
- export {
35
- useUpload,
36
- useFilesClient,
37
- createFilesClient,
38
- FilesClientProvider
39
- };
40
-
41
- //# debugId=B5D4D3E17929B8B464756E2164756E21
42
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjXFxjbGllbnRcXHByb3ZpZGVyLnRzeCIsICJzcmNcXGNsaWVudFxcY2xpZW50LnRzIiwgInNyY1xcY2xpZW50XFxob29rcy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICAgICJpbXBvcnQgeyBjcmVhdGVDb250ZXh0LCB1c2VDb250ZXh0LCB0eXBlIFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xyXG5pbXBvcnQgdHlwZSB7IEZpbGVzQ2xpZW50IH0gZnJvbSBcIi4vY2xpZW50XCI7XHJcblxyXG5cclxuY29uc3QgRmlsZXNDbGllbnRDb250ZXh0ID0gY3JlYXRlQ29udGV4dDxGaWxlc0NsaWVudCB8IG51bGw+KG51bGwpO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIEZpbGVzQ2xpZW50UHJvdmlkZXIocHJvcHM6IHtcclxuICBmaWxlc0NsaWVudDogRmlsZXNDbGllbnQ7XHJcbiAgY2hpbGRyZW46IFJlYWN0Tm9kZTtcclxufSkge1xyXG4gIHJldHVybiAoXHJcbiAgICA8RmlsZXNDbGllbnRDb250ZXh0LlByb3ZpZGVyIHZhbHVlPXtwcm9wcy5maWxlc0NsaWVudH0+XHJcbiAgICAgIHtwcm9wcy5jaGlsZHJlbn1cclxuICAgIDwvRmlsZXNDbGllbnRDb250ZXh0LlByb3ZpZGVyPlxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VGaWxlc0NsaWVudCgpIHtcclxuICBjb25zdCBjb250ZXh0ID0gdXNlQ29udGV4dChGaWxlc0NsaWVudENvbnRleHQpO1xyXG4gIGlmICghY29udGV4dCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwidXNlRmlsZXNDbGllbnQgbXVzdCBiZSB1c2VkIHdpdGhpbiBhIEZpbGVzQ2xpZW50UHJvdmlkZXJcIik7XHJcbiAgfVxyXG4gIHJldHVybiBjb250ZXh0O1xyXG59XHJcbiIsCiAgICAiaW1wb3J0IHsgdHJlYXR5LCB0eXBlIFRyZWF0eSB9IGZyb20gXCJAZWx5c2lhanMvZWRlblwiO1xyXG5pbXBvcnQgdHlwZSB7IGNyZWF0ZUZpbGVzQmFja2VuZCB9IGZyb20gXCIuLi9iYWNrZW5kXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRmlsZXNDbGllbnQ8XHJcbiAgVEJhY2tlbmQgZXh0ZW5kcyBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVGaWxlc0JhY2tlbmQ8YW55Pj5cclxuPihcclxuICBkb21haW46IHN0cmluZyxcclxuICBjb25maWc/OiBUcmVhdHkuQ29uZmlnXHJcbikge1xyXG4gIHJldHVybiB0cmVhdHk8VEJhY2tlbmRbXCJyb3V0ZXNcIl0+KGRvbWFpbiwgY29uZmlnKTtcclxufVxyXG5cclxuZXhwb3J0IHR5cGUgRmlsZXNDbGllbnQgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVGaWxlc0NsaWVudD47IiwKICAgICJpbXBvcnQgeyB1c2VNdXRhdGlvbiwgdHlwZSBVc2VNdXRhdGlvbk9wdGlvbnMgfSBmcm9tIFwiQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5XCI7XHJcbmltcG9ydCB0eXBlIHsgRmlsZXNDbGllbnQgfSBmcm9tIFwiLi9jbGllbnRcIjtcclxuaW1wb3J0IHsgZWRlbk11dGF0aW9uT3B0aW9ucywgdHlwZSBJbmZlck11dGF0aW9uT3B0aW9ucyB9IGZyb20gXCJlZGVuMnF1ZXJ5XCI7XHJcbmltcG9ydCB7IHVzZUZpbGVzQ2xpZW50IH0gZnJvbSBcIi4vcHJvdmlkZXJcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VVcGxvYWQoXHJcbiAgb3B0aW9uczogSW5mZXJNdXRhdGlvbk9wdGlvbnM8RmlsZXNDbGllbnRbXCJhcGlcIl1bXCJmaWxlc1wiXVtcInVwbG9hZFwiXVtcInBvc3RcIl0+XHJcbikge1xyXG4gIGNvbnN0IGZpbGVzQ2xpZW50ID0gdXNlRmlsZXNDbGllbnQoKSA7XHJcbiAgcmV0dXJuIHVzZU11dGF0aW9uKHtcclxuICAgIC4uLm9wdGlvbnMsXHJcbiAgICAuLi5lZGVuTXV0YXRpb25PcHRpb25zKFxyXG4gICAgICBmaWxlc0NsaWVudC5hcGkuZmlsZXMudXBsb2FkLnBvc3QsXHJcbiAgICApLFxyXG4gIH0pO1xyXG59IgogIF0sCiAgIm1hcHBpbmdzIjogIjs7QUFBQTtBQUFBO0FBSUEsSUFBTSxxQkFBcUIsY0FBa0MsSUFBSTtBQUUxRCxTQUFTLG1CQUFtQixDQUFDLE9BR2pDO0FBQUEsRUFDRCx1QkFDRSxPQUVFLG1CQUFtQixVQUZyQjtBQUFBLElBQTZCLE9BQU8sTUFBTTtBQUFBLElBQTFDLFVBQ0csTUFBTTtBQUFBLEtBRFQsaUNBRUU7QUFBQTtBQUlDLFNBQVMsY0FBYyxHQUFHO0FBQUEsRUFDL0IsTUFBTSxVQUFVLFdBQVcsa0JBQWtCO0FBQUEsRUFDN0MsSUFBSSxDQUFDLFNBQVM7QUFBQSxJQUNaLE1BQU0sSUFBSSxNQUFNLDBEQUEwRDtBQUFBLEVBQzVFO0FBQUEsRUFDQSxPQUFPO0FBQUE7O0FDdEJUO0FBR08sU0FBUyxpQkFFZixDQUNDLFFBQ0EsUUFDQTtBQUFBLEVBQ0EsT0FBTyxPQUEyQixRQUFRLE1BQU07QUFBQTs7QUNUbEQ7QUFFQTtBQUdPLFNBQVMsU0FBUyxDQUN2QixTQUNBO0FBQUEsRUFDQSxNQUFNLGNBQWMsZUFBZTtBQUFBLEVBQ25DLE9BQU8sWUFBWTtBQUFBLE9BQ2Q7QUFBQSxPQUNBLG9CQUNELFlBQVksSUFBSSxNQUFNLE9BQU8sSUFDL0I7QUFBQSxFQUNGLENBQUM7QUFBQTsiLAogICJkZWJ1Z0lkIjogIkI1RDREM0UxNzkyOUI4QjQ2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
package/dist/index.d.ts DELETED
@@ -1,21 +0,0 @@
1
- import { PgDatabase as PgDatabase2 } from "drizzle-orm/pg-core";
2
- type Schemas = ReturnType<typeof createSchemas>;
3
- type FileSchema = Schemas["files"];
4
- type FileRecord = FileSchema["$inferSelect"];
5
- declare function createSchemas(): {};
6
- type Visibility = "private" | "public";
7
- interface PurposePolicy {
8
- maxSize?: number;
9
- allowedMimeTypes?: string[];
10
- visibility?: Visibility;
11
- }
12
- import { S3Options as S3Options2 } from "bun";
13
- interface FilesBackendOptions<TPurposes extends string> {
14
- db: PgDatabase2<any, any, any>;
15
- s3Options: S3Options2;
16
- policies: Record<TPurposes, PurposePolicy>;
17
- publicBaseUrl: string;
18
- presignExpiresIn?: number;
19
- }
20
- declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {};
21
- export { createFilesBackend, Visibility, PurposePolicy, FilesBackendOptions, FileRecord };
package/dist/index.js DELETED
@@ -1,10 +0,0 @@
1
- // @bun
2
- import {
3
- createFilesBackend
4
- } from "./shared/chunk-wq7ndb52.js";
5
- export {
6
- createFilesBackend
7
- };
8
-
9
- //# debugId=A60E55F38BA0FEA664756E2164756E21
10
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICBdLAogICJtYXBwaW5ncyI6ICIiLAogICJkZWJ1Z0lkIjogIkE2MEU1NUYzOEJBMEZFQTY2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
@@ -1,203 +0,0 @@
1
- // @bun
2
- // src/backend/routes.ts
3
- import { Elysia, t } from "elysia";
4
- function createRoutes(options) {
5
- const {
6
- services,
7
- policies
8
- } = options;
9
- return new Elysia({
10
- prefix: "/api"
11
- }).post("/files/upload", async ({ status, body }) => {
12
- const { file, purpose } = body;
13
- const policy = policies[purpose];
14
- if (!policy) {
15
- return status(400, {
16
- message: "Purpose not supported"
17
- });
18
- }
19
- if (policy.maxSize !== undefined && file.size > policy.maxSize) {
20
- return status(400, {
21
- message: "File size exceeds the maximum allowed size"
22
- });
23
- }
24
- if (policy.allowedMimeTypes !== undefined && !policy.allowedMimeTypes.includes(file.type)) {
25
- return status(400, {
26
- message: "File type not allowed"
27
- });
28
- }
29
- const uploaded = await services.uploadFile({
30
- file,
31
- purpose,
32
- visibility: policy.visibility ?? "private"
33
- });
34
- return status(200, {
35
- id: uploaded.id,
36
- name: uploaded.name,
37
- key: uploaded.key,
38
- size: uploaded.size,
39
- mimeType: uploaded.mimeType,
40
- createdAt: uploaded.createdAt
41
- });
42
- }, {
43
- body: UploadRequest(Object.keys(policies)),
44
- response: {
45
- 200: FileResponse,
46
- 400: ErrorResponse,
47
- 500: ErrorResponse
48
- }
49
- });
50
- }
51
- function UploadRequest(purposes) {
52
- return t.Object({
53
- file: t.File(),
54
- purpose: t.Union(purposes.map((p) => t.Literal(p)))
55
- });
56
- }
57
- var ErrorResponse = t.Object({
58
- message: t.String()
59
- });
60
- var FileResponse = t.Object({
61
- id: t.String(),
62
- name: t.Nullable(t.String()),
63
- key: t.String(),
64
- size: t.Number(),
65
- mimeType: t.String(),
66
- createdAt: t.Date()
67
- });
68
-
69
- // src/backend/schemas.ts
70
- import { nanoid } from "nanoid";
71
- import { index, integer, pgTable, text, timestamp, pgEnum } from "drizzle-orm/pg-core";
72
- function createSchemas() {
73
- const files = pgTable("files", {
74
- id: text("id").primaryKey().$defaultFn(() => `file_${nanoid()}`),
75
- purpose: text("purpose").notNull(),
76
- name: text("name"),
77
- key: text("key").notNull().unique(),
78
- size: integer("size").notNull(),
79
- mimeType: text("mime_type").notNull().default("application/octet-stream"),
80
- refCount: integer("ref_count").notNull().default(0),
81
- visibility: pgEnum("visibility", ["private", "public"])().notNull().default("private"),
82
- createdAt: timestamp("created_at").notNull().defaultNow(),
83
- updatedAt: timestamp("updated_at").notNull().defaultNow()
84
- }, (table) => [
85
- index("files_key_idx").on(table.key),
86
- index("files_created_at_idx").on(table.createdAt)
87
- ]);
88
- return {
89
- files
90
- };
91
- }
92
-
93
- // src/backend/services.ts
94
- var {S3Client } = globalThis.Bun;
95
- import { nanoid as nanoid2 } from "nanoid";
96
- import { extname } from "path";
97
- import { eq, sql, and } from "drizzle-orm";
98
- function createServices(options) {
99
- const {
100
- db,
101
- schemas,
102
- s3Options,
103
- keyPrefix = "files",
104
- presignExpiresIn = 3600
105
- } = options;
106
- const { endpoint } = s3Options;
107
- const s3Client = new S3Client(s3Options);
108
- return {
109
- async getFile(params) {
110
- const [found] = await db.select().from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
111
- if (!found) {
112
- throw new Error("File not found");
113
- }
114
- return found;
115
- },
116
- async getUrl(params) {
117
- const [found] = await db.select({
118
- key: schemas.files.key,
119
- visibility: schemas.files.visibility
120
- }).from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
121
- if (!found) {
122
- throw new Error("File not found");
123
- }
124
- if (found.visibility === "public") {
125
- return `${endpoint}/${found.key}`;
126
- }
127
- return s3Client.presign(found.key, { expiresIn: presignExpiresIn });
128
- },
129
- async uploadFile(params) {
130
- const id = nanoid2();
131
- const ext = extname(params.file.name);
132
- const key = [keyPrefix, params.visibility, params.purpose, `${id}${ext}`].join("/");
133
- const s3file = s3Client.file(key);
134
- await s3file.write(params.file, {
135
- type: params.file.type,
136
- acl: params.visibility === "public" ? "public-read" : "private"
137
- });
138
- try {
139
- const [created] = await db.insert(schemas.files).values({
140
- purpose: params.purpose,
141
- key,
142
- size: s3file.size,
143
- name: s3file.name ?? null,
144
- mimeType: s3file.type,
145
- visibility: params.visibility
146
- }).returning();
147
- if (!created) {
148
- throw new Error("Failed to create file record");
149
- }
150
- return created;
151
- } catch (error) {
152
- await s3file.delete().catch();
153
- throw error;
154
- }
155
- },
156
- async deleteFile(params) {
157
- const [deleted] = await db.delete(schemas.files).where(eq(schemas.files.id, params.id)).returning();
158
- if (!deleted)
159
- return;
160
- await s3Client.delete(deleted.key);
161
- },
162
- async acquireFile(params) {
163
- 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();
164
- if (!updated) {
165
- throw new Error("File not found");
166
- }
167
- return updated;
168
- },
169
- async releaseFile(params) {
170
- const [updated] = await db.update(schemas.files).set({ refCount: sql`${schemas.files.refCount} - 1` }).where(eq(schemas.files.id, params.id)).returning();
171
- if (!updated) {
172
- throw new Error("File not found");
173
- }
174
- if (updated.refCount < 1) {
175
- await this.deleteFile({ id: params.id });
176
- }
177
- }
178
- };
179
- }
180
-
181
- // src/backend/backend.ts
182
- function createFilesBackend(options) {
183
- const schemas = createSchemas();
184
- const services = createServices({
185
- db: options.db,
186
- schemas,
187
- s3Options: options.s3Options,
188
- presignExpiresIn: options.presignExpiresIn
189
- });
190
- const routes = createRoutes({
191
- services,
192
- policies: options.policies
193
- });
194
- return {
195
- schemas,
196
- routes,
197
- services
198
- };
199
- }
200
- export { createFilesBackend };
201
-
202
- //# debugId=DDC8BE7935E77F6D64756E2164756E21
203
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjXFxiYWNrZW5kXFxyb3V0ZXMudHMiLCAic3JjXFxiYWNrZW5kXFxzY2hlbWFzLnRzIiwgInNyY1xcYmFja2VuZFxcc2VydmljZXMudHMiLCAic3JjXFxiYWNrZW5kXFxiYWNrZW5kLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCB7IEVseXNpYSwgdCB9IGZyb20gXCJlbHlzaWFcIjtcclxuaW1wb3J0IHR5cGUgeyBTZXJ2aWNlcyB9IGZyb20gXCIuL3NlcnZpY2VzXCI7XHJcblxyXG5leHBvcnQgdHlwZSBWaXNpYmlsaXR5ID0gXCJwcml2YXRlXCIgfCBcInB1YmxpY1wiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQdXJwb3NlUG9saWN5IHtcclxuICBtYXhTaXplPzogbnVtYmVyO1xyXG4gIGFsbG93ZWRNaW1lVHlwZXM/OiBzdHJpbmdbXTtcclxuICB2aXNpYmlsaXR5PzogVmlzaWJpbGl0eTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJvdXRlczxjb25zdCBUUHVycG9zZSBleHRlbmRzIHN0cmluZz4oXHJcbiAgb3B0aW9uczoge1xyXG4gICAgc2VydmljZXM6IFNlcnZpY2VzO1xyXG4gICAgcG9saWNpZXM6IFJlY29yZDxUUHVycG9zZSwgUHVycG9zZVBvbGljeT5cclxuICB9XHJcbikge1xyXG4gIFxyXG4gIGNvbnN0IHsgXHJcbiAgICBzZXJ2aWNlcywgXHJcbiAgICBwb2xpY2llcyxcclxuICB9ID0gb3B0aW9ucztcclxuXHJcbiAgcmV0dXJuIG5ldyBFbHlzaWEoe1xyXG4gICAgcHJlZml4OiBcIi9hcGlcIixcclxuICB9KS5wb3N0KFwiL2ZpbGVzL3VwbG9hZFwiLCBhc3luYyAoeyBzdGF0dXMsIGJvZHkgfSkgPT4ge1xyXG4gICAgY29uc3QgeyBmaWxlLCBwdXJwb3NlIH0gPSBib2R5O1xyXG4gICAgY29uc3QgcG9saWN5ID0gcG9saWNpZXNbcHVycG9zZSBhcyBUUHVycG9zZV07XHJcbiAgICBpZiAoIXBvbGljeSkge1xyXG4gICAgICByZXR1cm4gc3RhdHVzKDQwMCwge1xyXG4gICAgICAgIG1lc3NhZ2U6IFwiUHVycG9zZSBub3Qgc3VwcG9ydGVkXCIsXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgaWYgKHBvbGljeS5tYXhTaXplICE9PSB1bmRlZmluZWQgJiYgZmlsZS5zaXplID4gcG9saWN5Lm1heFNpemUpIHtcclxuICAgICAgcmV0dXJuIHN0YXR1cyg0MDAsIHtcclxuICAgICAgICBtZXNzYWdlOiBcIkZpbGUgc2l6ZSBleGNlZWRzIHRoZSBtYXhpbXVtIGFsbG93ZWQgc2l6ZVwiLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIGlmIChwb2xpY3kuYWxsb3dlZE1pbWVUeXBlcyAhPT0gdW5kZWZpbmVkICYmICFwb2xpY3kuYWxsb3dlZE1pbWVUeXBlcy5pbmNsdWRlcyhmaWxlLnR5cGUpKSB7XHJcbiAgICAgIHJldHVybiBzdGF0dXMoNDAwLCB7XHJcbiAgICAgICAgbWVzc2FnZTogXCJGaWxlIHR5cGUgbm90IGFsbG93ZWRcIixcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjb25zdCB1cGxvYWRlZCA9IGF3YWl0IHNlcnZpY2VzLnVwbG9hZEZpbGUoeyBcclxuICAgICAgZmlsZSwgXHJcbiAgICAgIHB1cnBvc2UsIFxyXG4gICAgICB2aXNpYmlsaXR5OiBwb2xpY3kudmlzaWJpbGl0eSA/PyBcInByaXZhdGVcIiBcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHN0YXR1cygyMDAsIHtcclxuICAgICAgaWQ6IHVwbG9hZGVkLmlkLFxyXG4gICAgICBuYW1lOiB1cGxvYWRlZC5uYW1lLFxyXG4gICAgICBrZXk6IHVwbG9hZGVkLmtleSxcclxuICAgICAgc2l6ZTogdXBsb2FkZWQuc2l6ZSxcclxuICAgICAgbWltZVR5cGU6IHVwbG9hZGVkLm1pbWVUeXBlLFxyXG4gICAgICBjcmVhdGVkQXQ6IHVwbG9hZGVkLmNyZWF0ZWRBdCxcclxuICAgIH0pO1xyXG4gIH0sIHtcclxuICAgIGJvZHk6IFVwbG9hZFJlcXVlc3QoT2JqZWN0LmtleXMocG9saWNpZXMpIGFzIFRQdXJwb3NlW10pLFxyXG4gICAgcmVzcG9uc2U6IHtcclxuICAgICAgMjAwOiBGaWxlUmVzcG9uc2UsXHJcbiAgICAgIDQwMDogRXJyb3JSZXNwb25zZSxcclxuICAgICAgNTAwOiBFcnJvclJlc3BvbnNlLFxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG5mdW5jdGlvbiBVcGxvYWRSZXF1ZXN0PGNvbnN0IFRQdXJwb3NlIGV4dGVuZHMgc3RyaW5nPihcclxuICBwdXJwb3NlczogVFB1cnBvc2VbXVxyXG4pIHtcclxuICByZXR1cm4gdC5PYmplY3Qoe1xyXG4gICAgZmlsZTogdC5GaWxlKCksXHJcbiAgICBwdXJwb3NlOiB0LlVuaW9uKFxyXG4gICAgICBwdXJwb3Nlcy5tYXAoKHApID0+IHQuTGl0ZXJhbChwKSkgYXMgW1xyXG4gICAgICAgIFJldHVyblR5cGU8dHlwZW9mIHQuTGl0ZXJhbDxUUHVycG9zZT4+LFxyXG4gICAgICAgIC4uLlJldHVyblR5cGU8dHlwZW9mIHQuTGl0ZXJhbDxUUHVycG9zZT4+W10sXHJcbiAgICAgIF1cclxuICAgIClcclxuICB9KTtcclxufVxyXG5cclxuY29uc3QgRXJyb3JSZXNwb25zZSA9IHQuT2JqZWN0KHtcclxuICBtZXNzYWdlOiB0LlN0cmluZygpLFxyXG59KTtcclxuXHJcbmNvbnN0IEZpbGVSZXNwb25zZSA9IHQuT2JqZWN0KHtcclxuICBpZDogdC5TdHJpbmcoKSxcclxuICBuYW1lOiB0Lk51bGxhYmxlKHQuU3RyaW5nKCkpLFxyXG4gIGtleTogdC5TdHJpbmcoKSxcclxuICBzaXplOiB0Lk51bWJlcigpLFxyXG4gIG1pbWVUeXBlOiB0LlN0cmluZygpLFxyXG4gIGNyZWF0ZWRBdDogdC5EYXRlKCksXHJcbn0pOyIsCiAgICAiaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xyXG5pbXBvcnQgeyBpbmRleCwgaW50ZWdlciwgcGdUYWJsZSwgdGV4dCwgdGltZXN0YW1wLCBwZ0VudW0gfSBmcm9tIFwiZHJpenpsZS1vcm0vcGctY29yZVwiO1xyXG5cclxuXHJcbmV4cG9ydCB0eXBlIFNjaGVtYXMgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVTY2hlbWFzPjtcclxuZXhwb3J0IHR5cGUgRmlsZVNjaGVtYSA9IFNjaGVtYXNbXCJmaWxlc1wiXTtcclxuZXhwb3J0IHR5cGUgRmlsZVJlY29yZCA9IEZpbGVTY2hlbWFbXCIkaW5mZXJTZWxlY3RcIl07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2NoZW1hcygpIHtcclxuXHJcbiAgY29uc3QgZmlsZXMgPSBwZ1RhYmxlKFwiZmlsZXNcIiwge1xyXG4gICAgaWQ6IHRleHQoXCJpZFwiKS5wcmltYXJ5S2V5KCkuJGRlZmF1bHRGbigoKSA9PiBgZmlsZV8ke25hbm9pZCgpfWApLFxyXG4gICAgcHVycG9zZTogdGV4dChcInB1cnBvc2VcIikubm90TnVsbCgpLFxyXG4gICAgbmFtZTogdGV4dChcIm5hbWVcIiksXHJcbiAgICBrZXk6IHRleHQoXCJrZXlcIikubm90TnVsbCgpLnVuaXF1ZSgpLFxyXG4gICAgc2l6ZTogaW50ZWdlcihcInNpemVcIikubm90TnVsbCgpLFxyXG4gICAgbWltZVR5cGU6IHRleHQoXCJtaW1lX3R5cGVcIikubm90TnVsbCgpLmRlZmF1bHQoXCJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1cIiksXHJcbiAgICByZWZDb3VudDogaW50ZWdlcihcInJlZl9jb3VudFwiKS5ub3ROdWxsKCkuZGVmYXVsdCgwKSxcclxuICAgIHZpc2liaWxpdHk6IHBnRW51bShcInZpc2liaWxpdHlcIiwgW1wicHJpdmF0ZVwiLCBcInB1YmxpY1wiXSkoKS5ub3ROdWxsKCkuZGVmYXVsdChcInByaXZhdGVcIiksXHJcbiAgICBjcmVhdGVkQXQ6IHRpbWVzdGFtcChcImNyZWF0ZWRfYXRcIikubm90TnVsbCgpLmRlZmF1bHROb3coKSxcclxuICAgIHVwZGF0ZWRBdDogdGltZXN0YW1wKFwidXBkYXRlZF9hdFwiKS5ub3ROdWxsKCkuZGVmYXVsdE5vdygpLFxyXG4gIH0sICh0YWJsZSkgPT4gW1xyXG4gICAgaW5kZXgoXCJmaWxlc19rZXlfaWR4XCIpLm9uKHRhYmxlLmtleSksXHJcbiAgICBpbmRleChcImZpbGVzX2NyZWF0ZWRfYXRfaWR4XCIpLm9uKHRhYmxlLmNyZWF0ZWRBdCksXHJcbiAgXSk7XHJcblxyXG4gIHJldHVybiB7XHJcbiAgICBmaWxlcyxcclxuICB9XHJcbn0iLAogICAgImltcG9ydCB7IFMzQ2xpZW50LCB0eXBlIFMzT3B0aW9ucyB9IGZyb20gXCJidW5cIjtcclxuaW1wb3J0IHsgbmFub2lkIH0gZnJvbSBcIm5hbm9pZFwiO1xyXG5pbXBvcnQgeyBleHRuYW1lIH0gZnJvbSBcInBhdGhcIjtcclxuaW1wb3J0IHsgZXEsIHNxbCwgbHQsIGFuZCB9IGZyb20gXCJkcml6emxlLW9ybVwiO1xyXG5pbXBvcnQgdHlwZSB7IFNjaGVtYXMsIEZpbGVSZWNvcmQgfSBmcm9tIFwiLi9zY2hlbWFzXCI7XHJcbmltcG9ydCB0eXBlIHsgUGdEYXRhYmFzZSB9IGZyb20gXCJkcml6emxlLW9ybS9wZy1jb3JlXCI7XHJcblxyXG5leHBvcnQgdHlwZSBTZXJ2aWNlcyA9IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZVNlcnZpY2VzPjtcclxuXHJcbnR5cGUgQnlJZCA9IHsgaWQ6IHN0cmluZyB9O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNlcnZpY2VzKFxyXG4gIG9wdGlvbnM6IHtcclxuICAgIGRiOiBQZ0RhdGFiYXNlPGFueSwgYW55LCBhbnk+O1xyXG4gICAgc2NoZW1hczogU2NoZW1hcztcclxuICAgIHMzT3B0aW9uczogUzNPcHRpb25zO1xyXG4gICAga2V5UHJlZml4Pzogc3RyaW5nO1xyXG4gICAgcHJlc2lnbkV4cGlyZXNJbj86IG51bWJlcjtcclxuICB9XHJcbikge1xyXG4gIGNvbnN0IHsgXHJcbiAgICBkYiwgXHJcbiAgICBzY2hlbWFzLCBcclxuICAgIHMzT3B0aW9ucyxcclxuICAgIGtleVByZWZpeCA9IFwiZmlsZXNcIixcclxuICAgIHByZXNpZ25FeHBpcmVzSW4gPSAzNjAwXHJcbiAgfSA9IG9wdGlvbnM7XHJcbiAgXHJcbiAgY29uc3QgeyBlbmRwb2ludCB9ID0gczNPcHRpb25zO1xyXG4gIGNvbnN0IHMzQ2xpZW50ID0gbmV3IFMzQ2xpZW50KHMzT3B0aW9ucyk7XHJcblxyXG4gIHJldHVybiB7XHJcblxyXG4gICAgYXN5bmMgZ2V0RmlsZShwYXJhbXM6IEJ5SWQpOiBQcm9taXNlPEZpbGVSZWNvcmQ+IHtcclxuICAgICAgY29uc3QgW2ZvdW5kXSA9IGF3YWl0IGRiXHJcbiAgICAgICAgLnNlbGVjdCgpXHJcbiAgICAgICAgLmZyb20oc2NoZW1hcy5maWxlcylcclxuICAgICAgICAud2hlcmUoZXEoc2NoZW1hcy5maWxlcy5pZCwgcGFyYW1zLmlkKSlcclxuICAgICAgICAubGltaXQoMSk7XHJcbiAgICAgIGlmICghZm91bmQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaWxlIG5vdCBmb3VuZFwiKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZm91bmQ7XHJcbiAgICB9LFxyXG5cclxuICAgIGFzeW5jIGdldFVybChwYXJhbXM6IEJ5SWQpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICBjb25zdCBbZm91bmRdID0gYXdhaXQgZGJcclxuICAgICAgICAuc2VsZWN0KHsgXHJcbiAgICAgICAgICBrZXk6IHNjaGVtYXMuZmlsZXMua2V5LFxyXG4gICAgICAgICAgdmlzaWJpbGl0eTogc2NoZW1hcy5maWxlcy52aXNpYmlsaXR5LFxyXG4gICAgICAgIH0pXHJcbiAgICAgICAgLmZyb20oc2NoZW1hcy5maWxlcylcclxuICAgICAgICAud2hlcmUoZXEoc2NoZW1hcy5maWxlcy5pZCwgcGFyYW1zLmlkKSlcclxuICAgICAgICAubGltaXQoMSk7XHJcbiAgICAgIGlmICghZm91bmQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaWxlIG5vdCBmb3VuZFwiKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoZm91bmQudmlzaWJpbGl0eSA9PT0gXCJwdWJsaWNcIikge1xyXG4gICAgICAgIHJldHVybiBgJHtlbmRwb2ludH0vJHtmb3VuZC5rZXl9YDtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gczNDbGllbnQucHJlc2lnbihmb3VuZC5rZXksIHsgZXhwaXJlc0luOiBwcmVzaWduRXhwaXJlc0luIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICBhc3luYyB1cGxvYWRGaWxlKHBhcmFtczoge1xyXG4gICAgICBmaWxlOiBGaWxlO1xyXG4gICAgICBwdXJwb3NlOiBzdHJpbmc7XHJcbiAgICAgIHZpc2liaWxpdHk6IFwicHJpdmF0ZVwiIHwgXCJwdWJsaWNcIjtcclxuICAgIH0pOiBQcm9taXNlPEZpbGVSZWNvcmQ+IHtcclxuICAgICAgY29uc3QgaWQgPSBuYW5vaWQoKTtcclxuICAgICAgY29uc3QgZXh0ID0gZXh0bmFtZShwYXJhbXMuZmlsZS5uYW1lKTtcclxuICAgICAgY29uc3Qga2V5ID0gW2tleVByZWZpeCwgcGFyYW1zLnZpc2liaWxpdHksIHBhcmFtcy5wdXJwb3NlLCBgJHtpZH0ke2V4dH1gXS5qb2luKFwiL1wiKTtcclxuICAgICAgY29uc3QgczNmaWxlID0gczNDbGllbnQuZmlsZShrZXkpO1xyXG4gICAgICBhd2FpdCBzM2ZpbGUud3JpdGUocGFyYW1zLmZpbGUsIHtcclxuICAgICAgICB0eXBlOiBwYXJhbXMuZmlsZS50eXBlLFxyXG4gICAgICAgIGFjbDogcGFyYW1zLnZpc2liaWxpdHkgPT09IFwicHVibGljXCIgPyBcInB1YmxpYy1yZWFkXCIgOiBcInByaXZhdGVcIixcclxuICAgICAgfSk7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgW2NyZWF0ZWRdID0gYXdhaXQgZGIuaW5zZXJ0KHNjaGVtYXMuZmlsZXMpXHJcbiAgICAgICAgICAudmFsdWVzKHtcclxuICAgICAgICAgICAgcHVycG9zZTogcGFyYW1zLnB1cnBvc2UsXHJcbiAgICAgICAgICAgIGtleSxcclxuICAgICAgICAgICAgc2l6ZTogczNmaWxlLnNpemUsXHJcbiAgICAgICAgICAgIG5hbWU6IHMzZmlsZS5uYW1lID8/IG51bGwsXHJcbiAgICAgICAgICAgIG1pbWVUeXBlOiBzM2ZpbGUudHlwZSxcclxuICAgICAgICAgICAgdmlzaWJpbGl0eTogcGFyYW1zLnZpc2liaWxpdHksXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICAgLnJldHVybmluZygpO1xyXG4gICAgICAgIGlmICghY3JlYXRlZCkge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIGNyZWF0ZSBmaWxlIHJlY29yZFwiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGNyZWF0ZWQ7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgYXdhaXQgczNmaWxlLmRlbGV0ZSgpLmNhdGNoKCk7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgYXN5bmMgZGVsZXRlRmlsZShwYXJhbXM6IHsgaWQ6IHN0cmluZyB9KTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgIGNvbnN0IFtkZWxldGVkXSA9IGF3YWl0IGRiXHJcbiAgICAgICAgLmRlbGV0ZShzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgIC53aGVyZShlcShzY2hlbWFzLmZpbGVzLmlkLCBwYXJhbXMuaWQpKVxyXG4gICAgICAgIC5yZXR1cm5pbmcoKTtcclxuICAgICAgaWYgKCFkZWxldGVkKSByZXR1cm47XHJcbiAgICAgIGF3YWl0IHMzQ2xpZW50LmRlbGV0ZShkZWxldGVkLmtleSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGFzeW5jIGFjcXVpcmVGaWxlKHBhcmFtczogQnlJZCAmIHsgXHJcbiAgICAgIHB1cnBvc2U/OiBzdHJpbmcgXHJcbiAgICB9KTogUHJvbWlzZTxGaWxlUmVjb3JkPiB7XHJcbiAgICAgIGNvbnN0IFt1cGRhdGVkXSA9IGF3YWl0IGRiXHJcbiAgICAgICAgLnVwZGF0ZShzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgIC5zZXQoeyByZWZDb3VudDogc3FsYCR7c2NoZW1hcy5maWxlcy5yZWZDb3VudH0gKyAxYCB9KVxyXG4gICAgICAgIC53aGVyZShcclxuICAgICAgICAgIGFuZChcclxuICAgICAgICAgICAgZXEoc2NoZW1hcy5maWxlcy5pZCwgcGFyYW1zLmlkKSxcclxuICAgICAgICAgICAgcGFyYW1zLnB1cnBvc2UgPyBlcShzY2hlbWFzLmZpbGVzLnB1cnBvc2UsIHBhcmFtcy5wdXJwb3NlKSA6IHVuZGVmaW5lZCxcclxuICAgICAgICAgIClcclxuICAgICAgICApXHJcbiAgICAgICAgLnJldHVybmluZygpO1xyXG4gICAgICBpZiAoIXVwZGF0ZWQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaWxlIG5vdCBmb3VuZFwiKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdXBkYXRlZDtcclxuICAgIH0sXHJcblxyXG4gICAgYXN5bmMgcmVsZWFzZUZpbGUocGFyYW1zOiBCeUlkKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgIGNvbnN0IFt1cGRhdGVkXSA9IGF3YWl0IGRiXHJcbiAgICAgICAgLnVwZGF0ZShzY2hlbWFzLmZpbGVzKVxyXG4gICAgICAgIC5zZXQoeyByZWZDb3VudDogc3FsYCR7c2NoZW1hcy5maWxlcy5yZWZDb3VudH0gLSAxYCB9KVxyXG4gICAgICAgIC53aGVyZShlcShzY2hlbWFzLmZpbGVzLmlkLCBwYXJhbXMuaWQpKVxyXG4gICAgICAgIC5yZXR1cm5pbmcoKTtcclxuICAgICAgaWYgKCF1cGRhdGVkKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmlsZSBub3QgZm91bmRcIik7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHVwZGF0ZWQucmVmQ291bnQgPCAxKSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVGaWxlKHsgaWQ6IHBhcmFtcy5pZCB9KTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuICB9O1xyXG59IiwKICAgICJpbXBvcnQgdHlwZSB7IFBnRGF0YWJhc2UgfSBmcm9tIFwiZHJpenpsZS1vcm0vcGctY29yZVwiO1xyXG5pbXBvcnQgeyBjcmVhdGVSb3V0ZXMsIHR5cGUgUHVycG9zZVBvbGljeSB9IGZyb20gXCIuL3JvdXRlc1wiO1xyXG5pbXBvcnQgeyBjcmVhdGVTY2hlbWFzIH0gZnJvbSBcIi4vc2NoZW1hc1wiO1xyXG5pbXBvcnQgeyBjcmVhdGVTZXJ2aWNlcyB9IGZyb20gXCIuL3NlcnZpY2VzXCI7XHJcbmltcG9ydCB0eXBlIHsgUzNPcHRpb25zIH0gZnJvbSBcImJ1blwiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBGaWxlc0JhY2tlbmRPcHRpb25zPFRQdXJwb3NlcyBleHRlbmRzIHN0cmluZz4ge1xyXG4gIGRiOiBQZ0RhdGFiYXNlPGFueSwgYW55LCBhbnk+O1xyXG4gIHMzT3B0aW9uczogUzNPcHRpb25zO1xyXG4gIHBvbGljaWVzOiBSZWNvcmQ8VFB1cnBvc2VzLCBQdXJwb3NlUG9saWN5PjtcclxuICBwdWJsaWNCYXNlVXJsOiBzdHJpbmc7XHJcbiAgcHJlc2lnbkV4cGlyZXNJbj86IG51bWJlcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUZpbGVzQmFja2VuZDxjb25zdCBUUHVycG9zZSBleHRlbmRzIHN0cmluZz4oXHJcbiAgb3B0aW9uczogRmlsZXNCYWNrZW5kT3B0aW9uczxUUHVycG9zZT5cclxuKSB7XHJcbiAgY29uc3Qgc2NoZW1hcyA9IGNyZWF0ZVNjaGVtYXMoKTtcclxuICBjb25zdCBzZXJ2aWNlcyA9IGNyZWF0ZVNlcnZpY2VzKHtcclxuICAgIGRiOiBvcHRpb25zLmRiLFxyXG4gICAgc2NoZW1hcyxcclxuICAgIHMzT3B0aW9uczogb3B0aW9ucy5zM09wdGlvbnMsXHJcbiAgICBwcmVzaWduRXhwaXJlc0luOiBvcHRpb25zLnByZXNpZ25FeHBpcmVzSW4sXHJcbiAgfSk7XHJcbiAgY29uc3Qgcm91dGVzID0gY3JlYXRlUm91dGVzKHtcclxuICAgIHNlcnZpY2VzLFxyXG4gICAgcG9saWNpZXM6IG9wdGlvbnMucG9saWNpZXMsXHJcbiAgfSk7XHJcbiAgcmV0dXJuIHtcclxuICAgIHNjaGVtYXMsXHJcbiAgICByb3V0ZXMsXHJcbiAgICBzZXJ2aWNlcyxcclxuICB9IGFzIGNvbnN0O1xyXG59IgogIF0sCiAgIm1hcHBpbmdzIjogIjs7QUFBQTtBQVdPLFNBQVMsWUFBMkMsQ0FDekQsU0FJQTtBQUFBLEVBRUE7QUFBQSxJQUNFO0FBQUEsSUFDQTtBQUFBLE1BQ0U7QUFBQSxFQUVKLE9BQU8sSUFBSSxPQUFPO0FBQUEsSUFDaEIsUUFBUTtBQUFBLEVBQ1YsQ0FBQyxFQUFFLEtBQUssaUJBQWlCLFNBQVMsUUFBUSxXQUFXO0FBQUEsSUFDbkQsUUFBUSxNQUFNLFlBQVk7QUFBQSxJQUMxQixNQUFNLFNBQVMsU0FBUztBQUFBLElBQ3hCLElBQUksQ0FBQyxRQUFRO0FBQUEsTUFDWCxPQUFPLE9BQU8sS0FBSztBQUFBLFFBQ2pCLFNBQVM7QUFBQSxNQUNYLENBQUM7QUFBQSxJQUNIO0FBQUEsSUFDQSxJQUFJLE9BQU8sWUFBWSxhQUFhLEtBQUssT0FBTyxPQUFPLFNBQVM7QUFBQSxNQUM5RCxPQUFPLE9BQU8sS0FBSztBQUFBLFFBQ2pCLFNBQVM7QUFBQSxNQUNYLENBQUM7QUFBQSxJQUNIO0FBQUEsSUFDQSxJQUFJLE9BQU8scUJBQXFCLGFBQWEsQ0FBQyxPQUFPLGlCQUFpQixTQUFTLEtBQUssSUFBSSxHQUFHO0FBQUEsTUFDekYsT0FBTyxPQUFPLEtBQUs7QUFBQSxRQUNqQixTQUFTO0FBQUEsTUFDWCxDQUFDO0FBQUEsSUFDSDtBQUFBLElBQ0EsTUFBTSxXQUFXLE1BQU0sU0FBUyxXQUFXO0FBQUEsTUFDekM7QUFBQSxNQUNBO0FBQUEsTUFDQSxZQUFZLE9BQU8sY0FBYztBQUFBLElBQ25DLENBQUM7QUFBQSxJQUNELE9BQU8sT0FB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QUFJLEVBQUUsVUFBVSxNQUFNLFFBQVEsTUFBTSxlQUFlLENBQUMsRUFDcEQsTUFBTSxHQUFHLFFBQVEsTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDLEVBQ3JDLFVBQVU7QUFBQSxNQUNiLElBQUksQ0FBQyxTQUFTO0FBQUEsUUFDWixNQUFNLElBQUksTUFBTSxnQkFBZ0I7QUFBQSxNQUNsQztBQUFBLE1BQ0EsSUFBSSxRQUFRLFdBQVcsR0FBRztBQUFBLFFBQ3hCLE1BQU0sS0FBSyxXQUFXLEVBQUUsSUFBSSxPQUFPLEdBQUcsQ0FBQztBQUFBLE1BQ3pDO0FBQUE7QUFBQSxFQUVKO0FBQUE7OztBQzVISyxTQUFTLGtCQUFpRCxDQUMvRCxTQUNBO0FBQUEsRUFDQSxNQUFNLFVBQVUsY0FBYztBQUFBLEVBQzlCLE1BQU0sV0FBVyxlQUFlO0FBQUEsSUFDOUIsSUFBSSxRQUFRO0FBQUEsSUFDWjtBQUFBLElBQ0EsV0FBVyxRQUFRO0FBQUEsSUFDbkIsa0JBQWtCLFFBQVE7QUFBQSxFQUM1QixDQUFDO0FBQUEsRUFDRCxNQUFNLFNBQVMsYUFBYTtBQUFBLElBQzFCO0FBQUEsSUFDQSxVQUFVLFFBQVE7QUFBQSxFQUNwQixDQUFDO0FBQUEsRUFDRCxPQUFPO0FBQUEsSUFDTDtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsRUFDRjtBQUFBOyIsCiAgImRlYnVnSWQiOiAiRERDOEJFNzkzNUU3N0Y2RDY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=