UNPKG

wcz-layout

Version:

1 lines 15.9 kB
{"version":3,"file":"file-DUtvlVZX.mjs","names":["createServerOnlyFn","getRequest","axios","AxiosError","AxiosInstance","https","serverEnv","scopes","definedScopes","getAppToken","getTokenOnBehalfOf","getAccessToken","ApiOptions","baseURL","scopeKey","httpsAgent","Agent","rejectUnauthorized","createApi","Promise","resolvedBaseURL","process","env","Error","authHeader","headers","get","accessToken","startsWith","substring","length","api","create","Authorization","interceptors","response","use","undefined","error","data","message","createServerOnlyFn","AxiosResponse","https","Readable","DefaultHttpStack","Upload","z","serverEnv","uuidv7","getAppToken","getAccessToken","createApi","FileMeta","FileMetaSchema","GetFileMetasSchema","object","appName","string","min","max","subId","uuid","FileSchema","id","UpdateFileMetaSchema","extend","fileName","DeleteFileSchema","BatchDeleteFilesSchema","UploadFileResult","UploadFileMetaSchema","file","instanceof","File","fileApi","baseURL","scopeKey","toFileResponse","response","disposition","Response","headers","Headers","String","contentLength","set","toWeb","data","ReadableStream","getFileMetas","input","Promise","Array","parse","queryParams","URLSearchParams","append","api","fileMetas","request","url","toString","method","getFileThumbnail","responseType","getFile","downloadFile","updateFileMeta","deleteFile","batchDeleteFiles","insecureHttpsAgent","Agent","rejectUnauthorized","uploadFile","accessToken","stream","fromWeb","resolve","reject","upload","endpoint","FILE_BASE_URL","httpStack","agent","uploadSize","size","chunkSize","metadata","filename","name","filetype","type","Authorization","onError","onSuccess","start"],"sources":["../src/data/server/utils/createApi.ts","../src/data/server/file.ts"],"sourcesContent":["import { createServerOnlyFn } from \"@tanstack/react-start\";\r\nimport { getRequest } from \"@tanstack/react-start/server\";\r\nimport axios, { AxiosError, type AxiosInstance } from \"axios\";\r\nimport https from \"node:https\";\r\nimport type { serverEnv } from \"virtual:wcz-layout\";\r\nimport { scopes as definedScopes } from \"virtual:wcz-layout\";\r\nimport { getAppToken, getTokenOnBehalfOf } from \"~/lib/auth/msalServer\";\r\nimport { getAccessToken } from \"~/lib/auth/user\";\r\n\r\nexport interface ApiOptions {\r\n baseURL: keyof typeof serverEnv & `${string}BASE_URL${string}`;\r\n scopeKey: keyof typeof definedScopes;\r\n}\r\n\r\nconst httpsAgent = new https.Agent({\r\n rejectUnauthorized: false,\r\n});\r\n\r\nexport const createApi = createServerOnlyFn(\r\n async ({ baseURL, scopeKey }: ApiOptions): Promise<AxiosInstance> => {\r\n const resolvedBaseURL = process.env[baseURL];\r\n if (!resolvedBaseURL) throw new Error(`\"${baseURL}\" env variable is not set.`);\r\n\r\n const authHeader = getRequest().headers.get(\"Authorization\");\r\n let accessToken: string;\r\n if (authHeader?.startsWith(\"Bearer \")) {\r\n accessToken = await getTokenOnBehalfOf(authHeader.substring(\"Bearer \".length), scopeKey);\r\n } else {\r\n try {\r\n accessToken = await getAccessToken(scopeKey);\r\n } catch {\r\n accessToken = await getAppToken(scopeKey);\r\n }\r\n }\r\n\r\n const api = axios.create({\r\n baseURL: resolvedBaseURL,\r\n httpsAgent,\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n api.interceptors.response.use(undefined, (error: unknown) => {\r\n if (error instanceof AxiosError)\r\n throw new Error(error.response?.data?.message ?? error.message);\r\n throw error;\r\n });\r\n\r\n return api;\r\n },\r\n);\r\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 } from \"~/lib/auth/user\";\r\nimport { createApi } from \"~/data/server/utils/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 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 let accessToken: string;\r\n try {\r\n accessToken = await getAccessToken(\"file\");\r\n } catch {\r\n accessToken = await getAppToken(\"file\");\r\n }\r\n const stream = Readable.fromWeb(\r\n input.file.stream() as import(\"node:stream/web\").ReadableStream,\r\n );\r\n\r\n const id = uuidv7();\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,\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,\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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"}