{"version":3,"file":"file-bAh5yYg7.mjs","names":["createServerFn","setResponseHeaders","https","Readable","DefaultHttpStack","Upload","uuidv7","z","serverEnv","getAppToken","getAccessToken","apiMiddleware","authenticationMiddleware","FileMeta","FileMetaSchema","GetFileMetasSchema","object","appName","string","min","max","subId","uuid","FileSchema","id","UpdateFileMetaSchema","extend","fileName","DeleteFileSchema","BatchDeleteFilesSchema","UploadFileResult","UploadFileMetaSchema","file","instanceof","File","getFileMetas","method","validator","middleware","baseURL","scopeKey","handler","data","context","queryParams","URLSearchParams","append","fileMetas","api","request","Array","url","toString","getFileThumbnail","response","responseType","Headers","headers","toWeb","ReadableStream","getFile","downloadFile","updateFileMeta","deleteFile","batchDeleteFiles","insecureHttpsAgent","Agent","rejectUnauthorized","uploadFile","FormData","parse","get","Promise","accessToken","buffer","Buffer","from","arrayBuffer","dotIndex","name","lastIndexOf","fileExtension","slice","resolve","reject","upload","endpoint","FILE_BASE_URL","httpStack","agent","chunkSize","metadata","mimeType","type","Authorization","onError","onSuccess","start"],"sources":["../src/data/server/file.ts"],"sourcesContent":["import { createServerFn } from \"@tanstack/react-start\";\r\nimport { setResponseHeaders } from \"@tanstack/react-start/server\";\r\nimport https from \"node:https\";\r\nimport { Readable } from \"node:stream\";\r\nimport { DefaultHttpStack, Upload } from \"tus-js-client\";\r\nimport { uuidv7 } from \"uuidv7\";\r\nimport { z } from \"zod\";\r\nimport { serverEnv } from \"~/env\";\r\nimport { getAppToken } from \"~/lib/auth/msalServer\";\r\nimport { getAccessToken } from \"~/lib/auth/user\";\r\nimport { apiMiddleware } from \"~/middleware/apiMiddleware\";\r\nimport { authenticationMiddleware } from \"~/middleware/authMiddleware\";\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\nexport const getFileMetas = createServerFn({ method: \"GET\" })\r\n  .validator(GetFileMetasSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"subId\", data.subId);\r\n\r\n    const { data: fileMetas } = await context.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\nexport const getFileThumbnail = createServerFn({ method: \"GET\" })\r\n  .validator(FileSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"id\", data.id);\r\n\r\n    const response = await context.api.request<Readable>({\r\n      url: `/v1/thumbnail?${queryParams.toString()}`,\r\n      method: \"GET\",\r\n      responseType: \"stream\",\r\n    });\r\n\r\n    setResponseHeaders(\r\n      new Headers({\r\n        \"Content-Type\": response.headers[\"content-type\"] as string,\r\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\r\n      }),\r\n    );\r\n    return Readable.toWeb(response.data) as ReadableStream;\r\n  });\r\n\r\nexport const getFile = createServerFn({ method: \"GET\" })\r\n  .validator(FileSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"id\", data.id);\r\n\r\n    const response = await context.api.request<Readable>({\r\n      url: `/v1?${queryParams.toString()}`,\r\n      method: \"GET\",\r\n      responseType: \"stream\",\r\n    });\r\n\r\n    setResponseHeaders(\r\n      new Headers({\r\n        \"Content-Type\": response.headers[\"content-type\"] as string,\r\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\r\n      }),\r\n    );\r\n    return Readable.toWeb(response.data) as ReadableStream;\r\n  });\r\n\r\nexport const downloadFile = createServerFn({ method: \"GET\" })\r\n  .validator(FileSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"id\", data.id);\r\n\r\n    const response = await context.api.request<Readable>({\r\n      url: `/v1/download?${queryParams.toString()}`,\r\n      method: \"GET\",\r\n      responseType: \"stream\",\r\n    });\r\n\r\n    setResponseHeaders(\r\n      new Headers({\r\n        \"Content-Type\": response.headers[\"content-type\"] as string,\r\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\r\n      }),\r\n    );\r\n    return Readable.toWeb(response.data) as ReadableStream;\r\n  });\r\n\r\nexport const updateFileMeta = createServerFn({ method: \"POST\" })\r\n  .validator(UpdateFileMetaSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"id\", data.id);\r\n\r\n    await context.api.request({ url: `/v1/meta?${queryParams.toString()}`, method: \"PUT\", data });\r\n  });\r\n\r\nexport const deleteFile = createServerFn({ method: \"POST\" })\r\n  .validator(DeleteFileSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"id\", data.id);\r\n\r\n    await context.api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\r\n  });\r\n\r\nexport const batchDeleteFiles = createServerFn({ method: \"POST\" })\r\n  .validator(BatchDeleteFilesSchema)\r\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\r\n  .handler(async ({ data, context }) => {\r\n    const queryParams = new URLSearchParams();\r\n    queryParams.append(\"appName\", data.appName);\r\n    queryParams.append(\"subId\", data.subId);\r\n\r\n    await context.api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\r\n  });\r\n\r\nconst insecureHttpsAgent = new https.Agent({ rejectUnauthorized: false });\r\n\r\nexport const uploadFile = createServerFn({ method: \"POST\" })\r\n  // File inputs must travel as multipart FormData — a File nested in a plain\r\n  // payload object can't be seroval-serialized, so the request never fires.\r\n  .validator((data: FormData) =>\r\n    UploadFileMetaSchema.parse({\r\n      appName: data.get(\"appName\"),\r\n      subId: data.get(\"subId\"),\r\n      file: data.get(\"file\"),\r\n    }),\r\n  )\r\n  .middleware([authenticationMiddleware()])\r\n  .handler(async ({ data }): Promise<UploadFileResult> => {\r\n    // Prefer the signed-in user's delegated token so the file service stamps\r\n    // createdBy; fall back to the app identity when there's no user session.\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 buffer = Buffer.from(await data.file.arrayBuffer());\r\n    const id = uuidv7();\r\n    const dotIndex = data.file.name.lastIndexOf(\".\");\r\n    const fileExtension = dotIndex >= 0 ? data.file.name.slice(dotIndex + 1) : \"\";\r\n\r\n    // The file microservice speaks the tus protocol, so the server forwards via\r\n    // tus-js-client. Progress isn't surfaced: by the time this runs the\r\n    // browser→server upload (the leg the user waits on) is already done, so the\r\n    // client just shows an indeterminate loading state.\r\n    await new Promise<void>((resolve, reject) => {\r\n      const upload = new Upload(buffer, {\r\n        endpoint: `${serverEnv.FILE_BASE_URL}/v1/upload`,\r\n        httpStack: new DefaultHttpStack({ agent: insecureHttpsAgent }),\r\n        chunkSize: 1_048_576,\r\n        metadata: {\r\n          id,\r\n          appName: data.appName,\r\n          subId: data.subId,\r\n          fileName: data.file.name,\r\n          fileExtension,\r\n          mimeType: data.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: data.appName,\r\n      subId: data.subId,\r\n      fileName: data.file.name,\r\n    };\r\n  });\r\n"],"mappings":"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"}