@edkstack/files 0.1.10 → 0.1.12

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,18 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll as t };
@@ -1,5 +1,5 @@
1
- import { n as createFilesBackend } from "../backend-CNgPTn_D.mjs";
2
- import "../backend/index.mjs";
1
+ import { n as createFilesServer } from "../server-Cxx9ToSf.mjs";
2
+ import "../server/index.mjs";
3
3
  import { ReactNode } from "react";
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
5
  import * as _elysiajs_eden0 from "@elysiajs/eden";
@@ -8,7 +8,7 @@ import * as _tanstack_react_query0 from "@tanstack/react-query";
8
8
  import { InferMutationOptions } from "eden2query";
9
9
 
10
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"]>;
11
+ declare function createFilesClient<TServer extends ReturnType<typeof createFilesServer<any>>>(domain: string, config?: Treaty.Config): Treaty.Create<TServer["router"]>;
12
12
  type FilesClient = ReturnType<typeof createFilesClient>;
13
13
  //#endregion
14
14
  //#region src/client/provider.d.ts
@@ -1 +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): Treaty.Create<TBackend[\"routes\"]> {\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,QACmC;AACnC,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"}
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 { createFilesServer } from \"../server\";\r\n\r\nexport function createFilesClient<\r\n TServer extends ReturnType<typeof createFilesServer<any>>\r\n>(\r\n domain: string,\r\n config?: Treaty.Config\r\n): Treaty.Create<TServer[\"router\"]> {\r\n return treaty<TServer[\"router\"]>(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,QACkC;AAClC,QAAO,OAA0B,QAAQ,OAAO;;;;;ACJlD,SAAgB,UACd,SACA;CACA,MAAM,cAAc,gBAAgB;AACpC,QAAO,YAAY;EACjB,GAAG;EACH,GAAG,oBACD,YAAY,IAAI,MAAM,OAAO,KAC9B;EACF,CAAC"}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { a as FileRecord, i as Visibility, n as createFilesBackend, r as PurposePolicy, t as FilesBackendOptions } from "./backend-CNgPTn_D.mjs";
2
- import "./backend/index.mjs";
3
- export { FileRecord, FilesBackendOptions, PurposePolicy, Visibility, createFilesBackend };
1
+ import { a as schema_d_exports, i as Visibility, n as createFilesServer, r as PurposePolicy, t as FilesServerOptions } from "./server-Cxx9ToSf.mjs";
2
+ import "./server/index.mjs";
3
+ export { FilesServerOptions, PurposePolicy, Visibility, createFilesServer, schema_d_exports as schema };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createFilesBackend } from "./backend-BOAJlrA-.mjs";
2
- import "./backend/index.mjs";
1
+ import { n as schema_exports, t as createFilesServer } from "./server-D1-_uiJo.mjs";
2
+ import "./server/index.mjs";
3
3
 
4
- export { createFilesBackend };
4
+ export { createFilesServer, schema_exports as schema };
@@ -0,0 +1,2 @@
1
+ import { a as schema_d_exports, i as Visibility, n as createFilesServer, r as PurposePolicy, t as FilesServerOptions } from "../server-Cxx9ToSf.mjs";
2
+ export { FilesServerOptions, type PurposePolicy, type Visibility, createFilesServer, schema_d_exports as schema };
@@ -0,0 +1,3 @@
1
+ import { n as schema_exports, t as createFilesServer } from "../server-D1-_uiJo.mjs";
2
+
3
+ export { createFilesServer, schema_exports as schema };
@@ -0,0 +1,308 @@
1
+ import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
2
+ import { PgDatabase } from "drizzle-orm/pg-core";
3
+ import { Elysia } from "elysia";
4
+ import { S3Options } from "bun";
5
+
6
+ //#region src/server/schema.d.ts
7
+ declare namespace schema_d_exports {
8
+ export { files };
9
+ }
10
+ declare const files: drizzle_orm_pg_core0.PgTableWithColumns<{
11
+ name: "files";
12
+ schema: undefined;
13
+ columns: {
14
+ id: drizzle_orm_pg_core0.PgColumn<{
15
+ name: "id";
16
+ tableName: "files";
17
+ dataType: "string";
18
+ columnType: "PgText";
19
+ data: string;
20
+ driverParam: string;
21
+ notNull: true;
22
+ hasDefault: true;
23
+ isPrimaryKey: true;
24
+ isAutoincrement: false;
25
+ hasRuntimeDefault: true;
26
+ enumValues: [string, ...string[]];
27
+ baseColumn: never;
28
+ identity: undefined;
29
+ generated: undefined;
30
+ }, {}, {}>;
31
+ purpose: drizzle_orm_pg_core0.PgColumn<{
32
+ name: "purpose";
33
+ tableName: "files";
34
+ dataType: "string";
35
+ columnType: "PgText";
36
+ data: string;
37
+ driverParam: string;
38
+ notNull: true;
39
+ hasDefault: false;
40
+ isPrimaryKey: false;
41
+ isAutoincrement: false;
42
+ hasRuntimeDefault: false;
43
+ enumValues: [string, ...string[]];
44
+ baseColumn: never;
45
+ identity: undefined;
46
+ generated: undefined;
47
+ }, {}, {}>;
48
+ name: drizzle_orm_pg_core0.PgColumn<{
49
+ name: "name";
50
+ tableName: "files";
51
+ dataType: "string";
52
+ columnType: "PgText";
53
+ data: string;
54
+ driverParam: string;
55
+ notNull: false;
56
+ hasDefault: false;
57
+ isPrimaryKey: false;
58
+ isAutoincrement: false;
59
+ hasRuntimeDefault: false;
60
+ enumValues: [string, ...string[]];
61
+ baseColumn: never;
62
+ identity: undefined;
63
+ generated: undefined;
64
+ }, {}, {}>;
65
+ key: drizzle_orm_pg_core0.PgColumn<{
66
+ name: "key";
67
+ tableName: "files";
68
+ dataType: "string";
69
+ columnType: "PgText";
70
+ data: string;
71
+ driverParam: string;
72
+ notNull: true;
73
+ hasDefault: false;
74
+ isPrimaryKey: false;
75
+ isAutoincrement: false;
76
+ hasRuntimeDefault: false;
77
+ enumValues: [string, ...string[]];
78
+ baseColumn: never;
79
+ identity: undefined;
80
+ generated: undefined;
81
+ }, {}, {}>;
82
+ size: drizzle_orm_pg_core0.PgColumn<{
83
+ name: "size";
84
+ tableName: "files";
85
+ dataType: "number";
86
+ columnType: "PgInteger";
87
+ data: number;
88
+ driverParam: string | number;
89
+ notNull: true;
90
+ hasDefault: false;
91
+ isPrimaryKey: false;
92
+ isAutoincrement: false;
93
+ hasRuntimeDefault: false;
94
+ enumValues: undefined;
95
+ baseColumn: never;
96
+ identity: undefined;
97
+ generated: undefined;
98
+ }, {}, {}>;
99
+ mimeType: drizzle_orm_pg_core0.PgColumn<{
100
+ name: "mime_type";
101
+ tableName: "files";
102
+ dataType: "string";
103
+ columnType: "PgText";
104
+ data: string;
105
+ driverParam: string;
106
+ notNull: true;
107
+ hasDefault: true;
108
+ isPrimaryKey: false;
109
+ isAutoincrement: false;
110
+ hasRuntimeDefault: false;
111
+ enumValues: [string, ...string[]];
112
+ baseColumn: never;
113
+ identity: undefined;
114
+ generated: undefined;
115
+ }, {}, {}>;
116
+ refCount: drizzle_orm_pg_core0.PgColumn<{
117
+ name: "ref_count";
118
+ tableName: "files";
119
+ dataType: "number";
120
+ columnType: "PgInteger";
121
+ data: number;
122
+ driverParam: string | number;
123
+ notNull: true;
124
+ hasDefault: true;
125
+ isPrimaryKey: false;
126
+ isAutoincrement: false;
127
+ hasRuntimeDefault: false;
128
+ enumValues: undefined;
129
+ baseColumn: never;
130
+ identity: undefined;
131
+ generated: undefined;
132
+ }, {}, {}>;
133
+ visibility: drizzle_orm_pg_core0.PgColumn<{
134
+ name: "visibility";
135
+ tableName: "files";
136
+ dataType: "string";
137
+ columnType: "PgEnumColumn";
138
+ data: "private" | "public";
139
+ driverParam: string;
140
+ notNull: true;
141
+ hasDefault: true;
142
+ isPrimaryKey: false;
143
+ isAutoincrement: false;
144
+ hasRuntimeDefault: false;
145
+ enumValues: ["private", "public"];
146
+ baseColumn: never;
147
+ identity: undefined;
148
+ generated: undefined;
149
+ }, {}, {}>;
150
+ createdAt: drizzle_orm_pg_core0.PgColumn<{
151
+ name: "created_at";
152
+ tableName: "files";
153
+ dataType: "date";
154
+ columnType: "PgTimestamp";
155
+ data: Date;
156
+ driverParam: string;
157
+ notNull: true;
158
+ hasDefault: true;
159
+ isPrimaryKey: false;
160
+ isAutoincrement: false;
161
+ hasRuntimeDefault: false;
162
+ enumValues: undefined;
163
+ baseColumn: never;
164
+ identity: undefined;
165
+ generated: undefined;
166
+ }, {}, {}>;
167
+ updatedAt: drizzle_orm_pg_core0.PgColumn<{
168
+ name: "updated_at";
169
+ tableName: "files";
170
+ dataType: "date";
171
+ columnType: "PgTimestamp";
172
+ data: Date;
173
+ driverParam: string;
174
+ notNull: true;
175
+ hasDefault: true;
176
+ isPrimaryKey: false;
177
+ isAutoincrement: false;
178
+ hasRuntimeDefault: false;
179
+ enumValues: undefined;
180
+ baseColumn: never;
181
+ identity: undefined;
182
+ generated: undefined;
183
+ }, {}, {}>;
184
+ };
185
+ dialect: "pg";
186
+ }>;
187
+ //#endregion
188
+ //#region src/server/service.d.ts
189
+ type Service = ReturnType<typeof createService>;
190
+ type ById = {
191
+ id: string;
192
+ };
193
+ declare function createService(options: {
194
+ db: PgDatabase<any, any, any>;
195
+ s3: S3Options;
196
+ keyPrefix?: string;
197
+ presignExpiresIn?: number;
198
+ }): {
199
+ getFile(params: ById): Promise<typeof files.$inferSelect>;
200
+ getUrl(params: ById): Promise<string>;
201
+ uploadFile(params: {
202
+ file: File;
203
+ purpose: string;
204
+ visibility: "private" | "public";
205
+ }): Promise<typeof files.$inferSelect>;
206
+ deleteFile(params: {
207
+ id: string;
208
+ }): Promise<void>;
209
+ acquireFile(params: ById & {
210
+ purpose?: string;
211
+ }): Promise<typeof files.$inferSelect>;
212
+ releaseFile(params: ById): Promise<void>;
213
+ };
214
+ //#endregion
215
+ //#region src/server/router.d.ts
216
+ type Visibility = "private" | "public";
217
+ interface PurposePolicy {
218
+ maxSize?: number;
219
+ allowedMimeTypes?: string[];
220
+ visibility?: Visibility;
221
+ }
222
+ declare function createRouter<const TPurpose extends string>(options: {
223
+ service: Service;
224
+ policies: Record<TPurpose, PurposePolicy>;
225
+ }): Elysia<"/api", {
226
+ decorator: {};
227
+ store: {};
228
+ derive: {};
229
+ resolve: {};
230
+ }, {
231
+ typebox: {};
232
+ error: {};
233
+ }, {
234
+ schema: {};
235
+ standaloneSchema: {};
236
+ macro: {};
237
+ macroFn: {};
238
+ parser: {};
239
+ response: {};
240
+ }, {
241
+ api: {
242
+ files: {
243
+ upload: {
244
+ post: {
245
+ body: {
246
+ purpose: TPurpose;
247
+ file: File;
248
+ };
249
+ params: {};
250
+ query: unknown;
251
+ headers: unknown;
252
+ response: {
253
+ 200: {
254
+ id: string;
255
+ name: string | null;
256
+ key: string;
257
+ size: number;
258
+ mimeType: string;
259
+ createdAt: Date;
260
+ };
261
+ 400: {
262
+ message: string;
263
+ };
264
+ 500: {
265
+ message: string;
266
+ };
267
+ 422: {
268
+ type: "validation";
269
+ on: string;
270
+ summary?: string;
271
+ message?: string;
272
+ found?: unknown;
273
+ property?: string;
274
+ expected?: string;
275
+ };
276
+ };
277
+ };
278
+ };
279
+ };
280
+ };
281
+ }, {
282
+ derive: {};
283
+ resolve: {};
284
+ schema: {};
285
+ standaloneSchema: {};
286
+ response: {};
287
+ }, {
288
+ derive: {};
289
+ resolve: {};
290
+ schema: {};
291
+ standaloneSchema: {};
292
+ response: {};
293
+ }>;
294
+ //#endregion
295
+ //#region src/server/server.d.ts
296
+ interface FilesServerOptions<TPurposes extends string> {
297
+ db: PgDatabase<any, any, any>;
298
+ s3: S3Options;
299
+ policies: Record<TPurposes, PurposePolicy>;
300
+ presignExpiresIn?: number;
301
+ }
302
+ declare function createFilesServer<const TPurpose extends string>(options: FilesServerOptions<TPurpose>): {
303
+ readonly router: ReturnType<typeof createRouter<TPurpose>>;
304
+ readonly service: Service;
305
+ };
306
+ //#endregion
307
+ export { schema_d_exports as a, Visibility as i, createFilesServer as n, PurposePolicy as r, FilesServerOptions as t };
308
+ //# sourceMappingURL=server-Cxx9ToSf.d.mts.map
@@ -1,20 +1,37 @@
1
- import { Elysia, t } from "elysia";
1
+ import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
2
2
  import { nanoid } from "nanoid";
3
3
  import { index, integer, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
4
+ import { Elysia, t } from "elysia";
4
5
  import { S3Client } from "bun";
5
6
  import { extname } from "path";
6
7
  import { and, eq, sql } from "drizzle-orm";
7
8
 
8
- //#region src/backend/routes.ts
9
- function createRoutes(options) {
10
- const { services, policies } = options;
9
+ //#region src/server/schema.ts
10
+ var schema_exports = /* @__PURE__ */ __exportAll({ files: () => files });
11
+ const files = pgTable("files", {
12
+ id: text("id").primaryKey().$defaultFn(() => `file_${nanoid()}`),
13
+ purpose: text("purpose").notNull(),
14
+ name: text("name"),
15
+ key: text("key").notNull().unique(),
16
+ size: integer("size").notNull(),
17
+ mimeType: text("mime_type").notNull().default("application/octet-stream"),
18
+ refCount: integer("ref_count").notNull().default(0),
19
+ visibility: pgEnum("visibility", ["private", "public"])().notNull().default("private"),
20
+ createdAt: timestamp("created_at").notNull().defaultNow(),
21
+ updatedAt: timestamp("updated_at").notNull().defaultNow()
22
+ }, (table) => [index("files_key_idx").on(table.key), index("files_created_at_idx").on(table.createdAt)]);
23
+
24
+ //#endregion
25
+ //#region src/server/router.ts
26
+ function createRouter(options) {
27
+ const { service, policies } = options;
11
28
  return new Elysia({ prefix: "/api" }).post("/files/upload", async ({ status, body }) => {
12
29
  const { file, purpose } = body;
13
30
  const policy = policies[purpose];
14
31
  if (!policy) return status(400, { message: "Purpose not supported" });
15
32
  if (policy.maxSize !== void 0 && file.size > policy.maxSize) return status(400, { message: "File size exceeds the maximum allowed size" });
16
33
  if (policy.allowedMimeTypes !== void 0 && !policy.allowedMimeTypes.includes(file.type)) return status(400, { message: "File type not allowed" });
17
- const uploaded = await services.uploadFile({
34
+ const uploaded = await service.uploadFile({
18
35
  file,
19
36
  purpose,
20
37
  visibility: policy.visibility ?? "private"
@@ -53,39 +70,22 @@ const FileResponse = t.Object({
53
70
  });
54
71
 
55
72
  //#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;
73
+ //#region src/server/service.ts
74
+ function createService(options) {
75
+ const { db, s3: s3Options, keyPrefix = "files", presignExpiresIn = 3600 } = options;
76
76
  const { endpoint } = s3Options;
77
77
  const s3Client = new S3Client(s3Options);
78
78
  return {
79
79
  async getFile(params) {
80
- const [found] = await db.select().from(schemas.files).where(eq(schemas.files.id, params.id)).limit(1);
80
+ const [found] = await db.select().from(files).where(eq(files.id, params.id)).limit(1);
81
81
  if (!found) throw new Error("File not found");
82
82
  return found;
83
83
  },
84
84
  async getUrl(params) {
85
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);
86
+ key: files.key,
87
+ visibility: files.visibility
88
+ }).from(files).where(eq(files.id, params.id)).limit(1);
89
89
  if (!found) throw new Error("File not found");
90
90
  if (found.visibility === "public") return `${endpoint}/${found.key}`;
91
91
  return s3Client.presign(found.key, { expiresIn: presignExpiresIn });
@@ -105,7 +105,7 @@ function createServices(options) {
105
105
  acl: params.visibility === "public" ? "public-read" : "private"
106
106
  });
107
107
  try {
108
- const [created] = await db.insert(schemas.files).values({
108
+ const [created] = await db.insert(files).values({
109
109
  purpose: params.purpose,
110
110
  key,
111
111
  size: s3file.size,
@@ -121,17 +121,17 @@ function createServices(options) {
121
121
  }
122
122
  },
123
123
  async deleteFile(params) {
124
- const [deleted] = await db.delete(schemas.files).where(eq(schemas.files.id, params.id)).returning();
124
+ const [deleted] = await db.delete(files).where(eq(files.id, params.id)).returning();
125
125
  if (!deleted) return;
126
126
  await s3Client.delete(deleted.key);
127
127
  },
128
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();
129
+ const [updated] = await db.update(files).set({ refCount: sql`${files.refCount} + 1` }).where(and(eq(files.id, params.id), params.purpose ? eq(files.purpose, params.purpose) : void 0)).returning();
130
130
  if (!updated) throw new Error("File not found");
131
131
  return updated;
132
132
  },
133
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();
134
+ const [updated] = await db.update(files).set({ refCount: sql`${files.refCount} - 1` }).where(eq(files.id, params.id)).returning();
135
135
  if (!updated) throw new Error("File not found");
136
136
  if (updated.refCount < 1) await this.deleteFile({ id: params.id });
137
137
  }
@@ -139,25 +139,22 @@ function createServices(options) {
139
139
  }
140
140
 
141
141
  //#endregion
142
- //#region src/backend/backend.ts
143
- function createFilesBackend(options) {
144
- const schemas = createSchemas();
145
- const services = createServices({
142
+ //#region src/server/server.ts
143
+ function createFilesServer(options) {
144
+ const service = createService({
146
145
  db: options.db,
147
- schemas,
148
- s3Options: options.s3Options,
146
+ s3: options.s3,
149
147
  presignExpiresIn: options.presignExpiresIn
150
148
  });
151
149
  return {
152
- schemas,
153
- routes: createRoutes({
154
- services,
150
+ router: createRouter({
151
+ service,
155
152
  policies: options.policies
156
153
  }),
157
- services
154
+ service
158
155
  };
159
156
  }
160
157
 
161
158
  //#endregion
162
- export { createFilesBackend as t };
163
- //# sourceMappingURL=backend-BOAJlrA-.mjs.map
159
+ export { schema_exports as n, createFilesServer as t };
160
+ //# sourceMappingURL=server-D1-_uiJo.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-D1-_uiJo.mjs","names":[],"sources":["../src/server/schema.ts","../src/server/router.ts","../src/server/service.ts","../src/server/server.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\r\nimport { index, integer, pgTable, text, timestamp, pgEnum } from \"drizzle-orm/pg-core\";\r\n\r\nexport 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]);","import { Elysia, t } from \"elysia\";\r\nimport type { Service } from \"./service\";\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 createRouter<const TPurpose extends string>(\r\n options: {\r\n service: Service;\r\n policies: Record<TPurpose, PurposePolicy>\r\n }\r\n) {\r\n \r\n const { \r\n service, \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 service.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 { S3Client, type S3Options } from \"bun\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { extname } from \"path\";\r\nimport { eq, sql, and } from \"drizzle-orm\";\r\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\r\nimport { files } from \"./schema\";\r\n\r\nexport type Service = ReturnType<typeof createService>;\r\n\r\ntype ById = { id: string };\r\n\r\nexport function createService(options: {\r\n db: PgDatabase<any, any, any>;\r\n s3: S3Options;\r\n keyPrefix?: string;\r\n presignExpiresIn?: number;\r\n}) {\r\n const { \r\n db, \r\n s3: 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<typeof files.$inferSelect> {\r\n const [found] = await db\r\n .select()\r\n .from(files)\r\n .where(eq(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: files.key,\r\n visibility: files.visibility,\r\n })\r\n .from(files)\r\n .where(eq(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<typeof files.$inferSelect> {\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(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(files)\r\n .where(eq(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<typeof files.$inferSelect> {\r\n const [updated] = await db\r\n .update(files)\r\n .set({ refCount: sql`${files.refCount} + 1` })\r\n .where(\r\n and(\r\n eq(files.id, params.id),\r\n params.purpose ? eq(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(files)\r\n .set({ refCount: sql`${files.refCount} - 1` })\r\n .where(eq(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 { createRouter, type PurposePolicy } from \"./router\";\r\nimport { createService, type Service } from \"./service\";\r\nimport type { S3Options } from \"bun\";\r\n\r\nexport interface FilesServerOptions<TPurposes extends string> {\r\n db: PgDatabase<any, any, any>;\r\n s3: S3Options;\r\n policies: Record<TPurposes, PurposePolicy>;\r\n presignExpiresIn?: number;\r\n}\r\n\r\nexport function createFilesServer<const TPurpose extends string>(\r\n options: FilesServerOptions<TPurpose>\r\n): {\r\n readonly router: ReturnType<typeof createRouter<TPurpose>>;\r\n readonly service: Service;\r\n} {\r\n const service = createService({\r\n db: options.db,\r\n s3: options.s3,\r\n presignExpiresIn: options.presignExpiresIn,\r\n });\r\n const router = createRouter({\r\n service,\r\n policies: options.policies,\r\n });\r\n return {\r\n router,\r\n service,\r\n };\r\n}"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@edkstack/files",
3
3
  "description": "File management utilities for EDK Stack",
4
- "version": "0.1.10",
4
+ "version": "0.1.12",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -10,8 +10,8 @@
10
10
  "types": "./dist/index.d.mts",
11
11
  "exports": {
12
12
  ".": "./dist/index.mjs",
13
- "./backend": "./dist/backend/index.mjs",
14
13
  "./client": "./dist/client/index.mjs",
14
+ "./server": "./dist/server/index.mjs",
15
15
  "./package.json": "./package.json"
16
16
  },
17
17
  "scripts": {
@@ -1,2 +0,0 @@
1
- import { a as FileRecord, i as Visibility, n as createFilesBackend, r as PurposePolicy, t as FilesBackendOptions } from "../backend-CNgPTn_D.mjs";
2
- export { type FileRecord, type FilesBackendOptions, type PurposePolicy, type Visibility, createFilesBackend };
@@ -1,3 +0,0 @@
1
- import { t as createFilesBackend } from "../backend-BOAJlrA-.mjs";
2
-
3
- export { createFilesBackend };
@@ -1 +0,0 @@
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, type Schemas } from \"./schemas\";\r\nimport { createServices, type Services } 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 readonly schemas: Schemas;\r\n readonly routes: ReturnType<typeof createRoutes<TPurpose>>;\r\n readonly services: Services;\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 };\r\n}"],"mappings":"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"}
@@ -1,312 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
3
- import { PgDatabase } from "drizzle-orm/pg-core";
4
- import { S3Options } from "bun";
5
-
6
- //#region src/backend/schemas.d.ts
7
- type Schemas = ReturnType<typeof createSchemas>;
8
- type FileSchema = Schemas["files"];
9
- type FileRecord = FileSchema["$inferSelect"];
10
- declare function createSchemas(): {
11
- files: drizzle_orm_pg_core0.PgTableWithColumns<{
12
- name: "files";
13
- schema: undefined;
14
- columns: {
15
- id: drizzle_orm_pg_core0.PgColumn<{
16
- name: "id";
17
- tableName: "files";
18
- dataType: "string";
19
- columnType: "PgText";
20
- data: string;
21
- driverParam: string;
22
- notNull: true;
23
- hasDefault: true;
24
- isPrimaryKey: true;
25
- isAutoincrement: false;
26
- hasRuntimeDefault: true;
27
- enumValues: [string, ...string[]];
28
- baseColumn: never;
29
- identity: undefined;
30
- generated: undefined;
31
- }, {}, {}>;
32
- purpose: drizzle_orm_pg_core0.PgColumn<{
33
- name: "purpose";
34
- tableName: "files";
35
- dataType: "string";
36
- columnType: "PgText";
37
- data: string;
38
- driverParam: string;
39
- notNull: true;
40
- hasDefault: false;
41
- isPrimaryKey: false;
42
- isAutoincrement: false;
43
- hasRuntimeDefault: false;
44
- enumValues: [string, ...string[]];
45
- baseColumn: never;
46
- identity: undefined;
47
- generated: undefined;
48
- }, {}, {}>;
49
- name: drizzle_orm_pg_core0.PgColumn<{
50
- name: "name";
51
- tableName: "files";
52
- dataType: "string";
53
- columnType: "PgText";
54
- data: string;
55
- driverParam: string;
56
- notNull: false;
57
- hasDefault: false;
58
- isPrimaryKey: false;
59
- isAutoincrement: false;
60
- hasRuntimeDefault: false;
61
- enumValues: [string, ...string[]];
62
- baseColumn: never;
63
- identity: undefined;
64
- generated: undefined;
65
- }, {}, {}>;
66
- key: drizzle_orm_pg_core0.PgColumn<{
67
- name: "key";
68
- tableName: "files";
69
- dataType: "string";
70
- columnType: "PgText";
71
- data: string;
72
- driverParam: string;
73
- notNull: true;
74
- hasDefault: false;
75
- isPrimaryKey: false;
76
- isAutoincrement: false;
77
- hasRuntimeDefault: false;
78
- enumValues: [string, ...string[]];
79
- baseColumn: never;
80
- identity: undefined;
81
- generated: undefined;
82
- }, {}, {}>;
83
- size: drizzle_orm_pg_core0.PgColumn<{
84
- name: "size";
85
- tableName: "files";
86
- dataType: "number";
87
- columnType: "PgInteger";
88
- data: number;
89
- driverParam: string | number;
90
- notNull: true;
91
- hasDefault: false;
92
- isPrimaryKey: false;
93
- isAutoincrement: false;
94
- hasRuntimeDefault: false;
95
- enumValues: undefined;
96
- baseColumn: never;
97
- identity: undefined;
98
- generated: undefined;
99
- }, {}, {}>;
100
- mimeType: drizzle_orm_pg_core0.PgColumn<{
101
- name: "mime_type";
102
- tableName: "files";
103
- dataType: "string";
104
- columnType: "PgText";
105
- data: string;
106
- driverParam: string;
107
- notNull: true;
108
- hasDefault: true;
109
- isPrimaryKey: false;
110
- isAutoincrement: false;
111
- hasRuntimeDefault: false;
112
- enumValues: [string, ...string[]];
113
- baseColumn: never;
114
- identity: undefined;
115
- generated: undefined;
116
- }, {}, {}>;
117
- refCount: drizzle_orm_pg_core0.PgColumn<{
118
- name: "ref_count";
119
- tableName: "files";
120
- dataType: "number";
121
- columnType: "PgInteger";
122
- data: number;
123
- driverParam: string | number;
124
- notNull: true;
125
- hasDefault: true;
126
- isPrimaryKey: false;
127
- isAutoincrement: false;
128
- hasRuntimeDefault: false;
129
- enumValues: undefined;
130
- baseColumn: never;
131
- identity: undefined;
132
- generated: undefined;
133
- }, {}, {}>;
134
- visibility: drizzle_orm_pg_core0.PgColumn<{
135
- name: "visibility";
136
- tableName: "files";
137
- dataType: "string";
138
- columnType: "PgEnumColumn";
139
- data: "private" | "public";
140
- driverParam: string;
141
- notNull: true;
142
- hasDefault: true;
143
- isPrimaryKey: false;
144
- isAutoincrement: false;
145
- hasRuntimeDefault: false;
146
- enumValues: ["private", "public"];
147
- baseColumn: never;
148
- identity: undefined;
149
- generated: undefined;
150
- }, {}, {}>;
151
- createdAt: drizzle_orm_pg_core0.PgColumn<{
152
- name: "created_at";
153
- tableName: "files";
154
- dataType: "date";
155
- columnType: "PgTimestamp";
156
- data: Date;
157
- driverParam: string;
158
- notNull: true;
159
- hasDefault: true;
160
- isPrimaryKey: false;
161
- isAutoincrement: false;
162
- hasRuntimeDefault: false;
163
- enumValues: undefined;
164
- baseColumn: never;
165
- identity: undefined;
166
- generated: undefined;
167
- }, {}, {}>;
168
- updatedAt: drizzle_orm_pg_core0.PgColumn<{
169
- name: "updated_at";
170
- tableName: "files";
171
- dataType: "date";
172
- columnType: "PgTimestamp";
173
- data: Date;
174
- driverParam: string;
175
- notNull: true;
176
- hasDefault: true;
177
- isPrimaryKey: false;
178
- isAutoincrement: false;
179
- hasRuntimeDefault: false;
180
- enumValues: undefined;
181
- baseColumn: never;
182
- identity: undefined;
183
- generated: undefined;
184
- }, {}, {}>;
185
- };
186
- dialect: "pg";
187
- }>;
188
- };
189
- //#endregion
190
- //#region src/backend/services.d.ts
191
- type Services = ReturnType<typeof createServices>;
192
- type ById = {
193
- id: string;
194
- };
195
- declare function createServices(options: {
196
- db: PgDatabase<any, any, any>;
197
- schemas: Schemas;
198
- s3Options: S3Options;
199
- keyPrefix?: string;
200
- presignExpiresIn?: number;
201
- }): {
202
- getFile(params: ById): Promise<FileRecord>;
203
- getUrl(params: ById): Promise<string>;
204
- uploadFile(params: {
205
- file: File;
206
- purpose: string;
207
- visibility: "private" | "public";
208
- }): Promise<FileRecord>;
209
- deleteFile(params: {
210
- id: string;
211
- }): Promise<void>;
212
- acquireFile(params: ById & {
213
- purpose?: string;
214
- }): Promise<FileRecord>;
215
- releaseFile(params: ById): Promise<void>;
216
- };
217
- //#endregion
218
- //#region src/backend/routes.d.ts
219
- type Visibility = "private" | "public";
220
- interface PurposePolicy {
221
- maxSize?: number;
222
- allowedMimeTypes?: string[];
223
- visibility?: Visibility;
224
- }
225
- declare function createRoutes<const TPurpose extends string>(options: {
226
- services: Services;
227
- policies: Record<TPurpose, PurposePolicy>;
228
- }): Elysia<"/api", {
229
- decorator: {};
230
- store: {};
231
- derive: {};
232
- resolve: {};
233
- }, {
234
- typebox: {};
235
- error: {};
236
- }, {
237
- schema: {};
238
- standaloneSchema: {};
239
- macro: {};
240
- macroFn: {};
241
- parser: {};
242
- response: {};
243
- }, {
244
- api: {
245
- files: {
246
- upload: {
247
- post: {
248
- body: {
249
- purpose: TPurpose;
250
- file: File;
251
- };
252
- params: {};
253
- query: unknown;
254
- headers: unknown;
255
- response: {
256
- 200: {
257
- id: string;
258
- name: string | null;
259
- key: string;
260
- size: number;
261
- mimeType: string;
262
- createdAt: Date;
263
- };
264
- 400: {
265
- message: string;
266
- };
267
- 500: {
268
- message: string;
269
- };
270
- 422: {
271
- type: "validation";
272
- on: string;
273
- summary?: string;
274
- message?: string;
275
- found?: unknown;
276
- property?: string;
277
- expected?: string;
278
- };
279
- };
280
- };
281
- };
282
- };
283
- };
284
- }, {
285
- derive: {};
286
- resolve: {};
287
- schema: {};
288
- standaloneSchema: {};
289
- response: {};
290
- }, {
291
- derive: {};
292
- resolve: {};
293
- schema: {};
294
- standaloneSchema: {};
295
- response: {};
296
- }>;
297
- //#endregion
298
- //#region src/backend/backend.d.ts
299
- interface FilesBackendOptions<TPurposes extends string> {
300
- db: PgDatabase<any, any, any>;
301
- s3Options: S3Options;
302
- policies: Record<TPurposes, PurposePolicy>;
303
- presignExpiresIn?: number;
304
- }
305
- declare function createFilesBackend<const TPurpose extends string>(options: FilesBackendOptions<TPurpose>): {
306
- readonly schemas: Schemas;
307
- readonly routes: ReturnType<typeof createRoutes<TPurpose>>;
308
- readonly services: Services;
309
- };
310
- //#endregion
311
- export { FileRecord as a, Visibility as i, createFilesBackend as n, PurposePolicy as r, FilesBackendOptions as t };
312
- //# sourceMappingURL=backend-CNgPTn_D.d.mts.map