wcz-layout
Version:
1 lines • 13.1 kB
Source Map (JSON)
{"version":3,"file":"file-BWcNzq55.mjs","names":[],"sources":["../src/lib/createApi.ts","../src/data/server/file.ts"],"sourcesContent":["import { createServerOnlyFn } from \"@tanstack/react-start\";\nimport axios, { AxiosError, type AxiosInstance } from \"axios\";\nimport https from \"node:https\";\nimport type { serverEnv } from \"virtual:wcz-layout\";\nimport { scopes as definedScopes } from \"virtual:wcz-layout\";\nimport { getAppToken } from \"~/lib/auth/msalServer\";\nimport { getAccessToken, getSessionUser } from \"~/lib/auth/user\";\n\nexport interface ApiOptions {\n baseURL: keyof typeof serverEnv & `${string}BASE_URL${string}`;\n scopeKey: keyof typeof definedScopes;\n}\n\nconst httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n});\n\nexport const createApi = createServerOnlyFn(\n async ({ baseURL, scopeKey }: ApiOptions): Promise<AxiosInstance> => {\n const resolvedBaseURL = process.env[baseURL];\n if (!resolvedBaseURL) throw new Error(`\"${baseURL}\" env variable is not set.`);\n\n const accessToken = (await getSessionUser())\n ? await getAccessToken(scopeKey)\n : await getAppToken(scopeKey);\n\n const api = axios.create({\n baseURL: resolvedBaseURL,\n httpsAgent,\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n api.interceptors.response.use(undefined, (error: unknown) => {\n if (error instanceof AxiosError)\n throw new Error(error.response?.data?.message ?? error.message);\n throw error;\n });\n\n return api;\n },\n);\n","import { createServerOnlyFn } from \"@tanstack/react-start\";\r\nimport type { AxiosResponse } from \"axios\";\r\nimport https from \"node:https\";\r\nimport { Readable } from \"node:stream\";\r\nimport { DefaultHttpStack, Upload } from \"tus-js-client\";\r\nimport { z } from \"zod\";\r\nimport { serverEnv } from \"~/env\";\r\nimport { uuidv7 } from \"~/exports/utils\";\r\nimport { getAppToken } from \"~/lib/auth/msalServer\";\r\nimport { getAccessToken, getSessionUser } from \"~/lib/auth/user\";\r\nimport { createApi } from \"~/lib/createApi\";\r\nimport type { FileMeta } from \"~/models/file/FileMeta\";\r\nimport { FileMetaSchema } from \"~/models/file/FileMeta\";\r\n\r\nexport const GetFileMetasSchema = z.object({\r\n appName: z.string().min(1).max(255),\r\n subId: z.uuid(),\r\n});\r\n\r\nexport const FileSchema = z.object({\r\n appName: z.string().min(1).max(255),\r\n id: z.uuid(),\r\n});\r\n\r\nexport const UpdateFileMetaSchema = FileMetaSchema.extend({\r\n fileName: z.string().min(1).max(255),\r\n});\r\n\r\nconst DeleteFileSchema = FileSchema;\r\n\r\nconst BatchDeleteFilesSchema = GetFileMetasSchema;\r\n\r\nexport interface UploadFileResult {\r\n id: string;\r\n appName: string;\r\n subId: string;\r\n fileName: string;\r\n}\r\n\r\nexport const UploadFileMetaSchema = z.object({\r\n id: z.uuid().default(uuidv7),\r\n appName: z.string().min(1).max(255),\r\n subId: z.uuid(),\r\n file: z.instanceof(File),\r\n});\r\n\r\nconst fileApi = () => createApi({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" });\r\n\r\nfunction toFileResponse(response: AxiosResponse<Readable>, disposition?: string): Response {\r\n const headers = new Headers({\r\n \"Cache-Control\": \"private, max-age=3600, immutable\",\r\n \"Content-Type\": String(response.headers[\"content-type\"] ?? \"application/octet-stream\"),\r\n });\r\n const contentLength = response.headers[\"content-length\"];\r\n if (contentLength) headers.set(\"Content-Length\", String(contentLength));\r\n if (disposition) headers.set(\"Content-Disposition\", disposition);\r\n\r\n return new Response(Readable.toWeb(response.data) as ReadableStream, { headers });\r\n}\r\n\r\nexport const getFileMetas = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof GetFileMetasSchema> }): Promise<Array<FileMeta>> => {\r\n const input = GetFileMetasSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"subId\", input.subId);\r\n\r\n const api = await fileApi();\r\n const { data: fileMetas } = await api.request<Array<FileMeta>>({\r\n url: `/v1/meta?${queryParams.toString()}`,\r\n method: \"GET\",\r\n });\r\n return fileMetas;\r\n },\r\n);\r\n\r\nexport const getFileThumbnail = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof FileSchema> }): Promise<Response> => {\r\n const input = FileSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"id\", input.id);\r\n\r\n const api = await fileApi();\r\n const response = await api.request<Readable>({\r\n url: `/v1/thumbnail?${queryParams.toString()}`,\r\n method: \"GET\",\r\n responseType: \"stream\",\r\n });\r\n\r\n return toFileResponse(response);\r\n },\r\n);\r\n\r\nexport const getFile = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof FileSchema> }): Promise<Response> => {\r\n const input = FileSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"id\", input.id);\r\n\r\n const api = await fileApi();\r\n const response = await api.request<Readable>({\r\n url: `/v1?${queryParams.toString()}`,\r\n method: \"GET\",\r\n responseType: \"stream\",\r\n });\r\n\r\n return toFileResponse(response, \"inline\");\r\n },\r\n);\r\n\r\nexport const downloadFile = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof FileSchema> }): Promise<Response> => {\r\n const input = FileSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"id\", input.id);\r\n\r\n const api = await fileApi();\r\n const response = await api.request<Readable>({\r\n url: `/v1/download?${queryParams.toString()}`,\r\n method: \"GET\",\r\n responseType: \"stream\",\r\n });\r\n\r\n return toFileResponse(response);\r\n },\r\n);\r\n\r\nexport const updateFileMeta = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof UpdateFileMetaSchema> }): Promise<void> => {\r\n const input = UpdateFileMetaSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"id\", input.id);\r\n\r\n const api = await fileApi();\r\n await api.request({ url: `/v1/meta?${queryParams.toString()}`, method: \"PUT\", data: input });\r\n },\r\n);\r\n\r\nexport const deleteFile = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof DeleteFileSchema> }): Promise<void> => {\r\n const input = DeleteFileSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"id\", input.id);\r\n\r\n const api = await fileApi();\r\n await api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\r\n },\r\n);\r\n\r\nexport const batchDeleteFiles = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof BatchDeleteFilesSchema> }): Promise<void> => {\r\n const input = BatchDeleteFilesSchema.parse(data);\r\n const queryParams = new URLSearchParams();\r\n queryParams.append(\"appName\", input.appName);\r\n queryParams.append(\"subId\", input.subId);\r\n\r\n const api = await fileApi();\r\n await api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\r\n },\r\n);\r\n\r\nconst insecureHttpsAgent = new https.Agent({ rejectUnauthorized: false });\r\n\r\nexport const uploadFile = createServerOnlyFn(\r\n async ({ data }: { data: z.input<typeof UploadFileMetaSchema> }): Promise<UploadFileResult> => {\r\n const input = UploadFileMetaSchema.parse(data);\r\n const accessToken = (await getSessionUser())\r\n ? await getAccessToken(\"file\")\r\n : await getAppToken(\"file\");\r\n const stream = Readable.fromWeb(\r\n input.file.stream() as import(\"node:stream/web\").ReadableStream,\r\n );\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const upload = new Upload(stream, {\r\n endpoint: `${serverEnv.FILE_BASE_URL}/v1/upload`,\r\n httpStack: new DefaultHttpStack({ agent: insecureHttpsAgent }),\r\n uploadSize: input.file.size,\r\n chunkSize: 1_048_576,\r\n metadata: {\r\n id: input.id,\r\n appName: input.appName,\r\n subId: input.subId,\r\n filename: input.file.name,\r\n filetype: input.file.type,\r\n },\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n onError: reject,\r\n onSuccess: () => resolve(),\r\n });\r\n upload.start();\r\n });\r\n\r\n return {\r\n id: input.id,\r\n appName: input.appName,\r\n subId: input.subId,\r\n fileName: input.file.name,\r\n };\r\n },\r\n);\r\n"],"mappings":"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"}