@edkstack/files 0.1.9 → 0.1.11

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