{"version":3,"file":"file-DM1x40eJ.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","stream","fromWeb","dotIndex","name","lastIndexOf","fileExtension","slice","resolve","reject","upload","endpoint","FILE_BASE_URL","httpStack","agent","uploadSize","size","chunkSize","metadata","mimeType","type","Authorization","onError","onSuccess","start"],"sources":["../src/data/server/file.ts"],"sourcesContent":["import { createServerFn } from \"@tanstack/react-start\";\nimport { setResponseHeaders } from \"@tanstack/react-start/server\";\nimport https from \"node:https\";\nimport { Readable } from \"node:stream\";\nimport { DefaultHttpStack, Upload } from \"tus-js-client\";\nimport { uuidv7 } from \"uuidv7\";\nimport { z } from \"zod\";\nimport { serverEnv } from \"~/env\";\nimport { getAppToken } from \"~/lib/auth/msalServer\";\nimport { getAccessToken } from \"~/lib/auth/user\";\nimport { apiMiddleware } from \"~/middleware/apiMiddleware\";\nimport { authenticationMiddleware } from \"~/middleware/authMiddleware\";\nimport type { FileMeta } from \"~/models/file/FileMeta\";\nimport { FileMetaSchema } from \"~/models/file/FileMeta\";\n\nexport const GetFileMetasSchema = z.object({\n  appName: z.string().min(1).max(255),\n  subId: z.uuid(),\n});\n\nexport const FileSchema = z.object({\n  appName: z.string().min(1).max(255),\n  id: z.uuid(),\n});\n\nexport const UpdateFileMetaSchema = FileMetaSchema.extend({\n  fileName: z.string().min(1).max(255),\n});\n\nconst DeleteFileSchema = FileSchema;\n\nconst BatchDeleteFilesSchema = GetFileMetasSchema;\n\nexport interface UploadFileResult {\n  id: string;\n  appName: string;\n  subId: string;\n  fileName: string;\n}\n\nexport const UploadFileMetaSchema = z.object({\n  appName: z.string().min(1).max(255),\n  subId: z.uuid(),\n  file: z.instanceof(File),\n});\n\nexport const getFileMetas = createServerFn({ method: \"GET\" })\n  .validator(GetFileMetasSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"subId\", data.subId);\n\n    const { data: fileMetas } = await context.api.request<Array<FileMeta>>({\n      url: `/v1/meta?${queryParams.toString()}`,\n      method: \"GET\",\n    });\n    return fileMetas;\n  });\n\nexport const getFileThumbnail = createServerFn({ method: \"GET\" })\n  .validator(FileSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"id\", data.id);\n\n    const response = await context.api.request<Readable>({\n      url: `/v1/thumbnail?${queryParams.toString()}`,\n      method: \"GET\",\n      responseType: \"stream\",\n    });\n\n    setResponseHeaders(\n      new Headers({\n        \"Content-Type\": response.headers[\"content-type\"] as string,\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\n      }),\n    );\n    return Readable.toWeb(response.data) as ReadableStream;\n  });\n\nexport const getFile = createServerFn({ method: \"GET\" })\n  .validator(FileSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"id\", data.id);\n\n    const response = await context.api.request<Readable>({\n      url: `/v1?${queryParams.toString()}`,\n      method: \"GET\",\n      responseType: \"stream\",\n    });\n\n    setResponseHeaders(\n      new Headers({\n        \"Content-Type\": response.headers[\"content-type\"] as string,\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\n      }),\n    );\n    return Readable.toWeb(response.data) as ReadableStream;\n  });\n\nexport const downloadFile = createServerFn({ method: \"GET\" })\n  .validator(FileSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"id\", data.id);\n\n    const response = await context.api.request<Readable>({\n      url: `/v1/download?${queryParams.toString()}`,\n      method: \"GET\",\n      responseType: \"stream\",\n    });\n\n    setResponseHeaders(\n      new Headers({\n        \"Content-Type\": response.headers[\"content-type\"] as string,\n        \"Cache-Control\": \"private, max-age=3600, immutable\",\n      }),\n    );\n    return Readable.toWeb(response.data) as ReadableStream;\n  });\n\nexport const updateFileMeta = createServerFn({ method: \"POST\" })\n  .validator(UpdateFileMetaSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"id\", data.id);\n\n    await context.api.request({ url: `/v1/meta?${queryParams.toString()}`, method: \"PUT\", data });\n  });\n\nexport const deleteFile = createServerFn({ method: \"POST\" })\n  .validator(DeleteFileSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"id\", data.id);\n\n    await context.api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\n  });\n\nexport const batchDeleteFiles = createServerFn({ method: \"POST\" })\n  .validator(BatchDeleteFilesSchema)\n  .middleware([apiMiddleware({ baseURL: \"FILE_BASE_URL\", scopeKey: \"file\" })])\n  .handler(async ({ data, context }) => {\n    const queryParams = new URLSearchParams();\n    queryParams.append(\"appName\", data.appName);\n    queryParams.append(\"subId\", data.subId);\n\n    await context.api.request({ url: `/v1?${queryParams.toString()}`, method: \"DELETE\" });\n  });\n\nconst insecureHttpsAgent = new https.Agent({ rejectUnauthorized: false });\n\nexport const uploadFile = createServerFn({ method: \"POST\" })\n  // File inputs must travel as multipart FormData — a File nested in a plain\n  // payload object can't be seroval-serialized, so the request never fires.\n  .validator((data: FormData) =>\n    UploadFileMetaSchema.parse({\n      appName: data.get(\"appName\"),\n      subId: data.get(\"subId\"),\n      file: data.get(\"file\"),\n    }),\n  )\n  .middleware([authenticationMiddleware()])\n  .handler(async ({ data }): Promise<UploadFileResult> => {\n    // Prefer the signed-in user's delegated token so the file service stamps\n    // createdBy; fall back to the app identity when there's no user session.\n    let accessToken: string;\n    try {\n      accessToken = await getAccessToken(\"file\");\n    } catch {\n      accessToken = await getAppToken(\"file\");\n    }\n    // Stream instead of buffering the whole file: in-process callers (e.g. a File\n    // from fs.openAsBlob) upload arbitrarily large files without holding them in RAM.\n    const stream = Readable.fromWeb(data.file.stream() as import(\"node:stream/web\").ReadableStream);\n    const id = uuidv7();\n    const dotIndex = data.file.name.lastIndexOf(\".\");\n    const fileExtension = dotIndex >= 0 ? data.file.name.slice(dotIndex + 1) : \"\";\n\n    // Server-originated edge cases only — browser uploads go direct to the file\n    // service via uploadFileMutationOptions (client) with the user's OBO token.\n    await new Promise<void>((resolve, reject) => {\n      const upload = new Upload(stream, {\n        endpoint: `${serverEnv.FILE_BASE_URL}/v1/upload`,\n        httpStack: new DefaultHttpStack({ agent: insecureHttpsAgent }),\n        uploadSize: data.file.size,\n        chunkSize: 1_048_576,\n        metadata: {\n          id,\n          appName: data.appName,\n          subId: data.subId,\n          fileName: data.file.name,\n          fileExtension,\n          mimeType: data.file.type,\n        },\n        headers: { Authorization: `Bearer ${accessToken}` },\n        onError: reject,\n        onSuccess: () => resolve(),\n      });\n      upload.start();\n    });\n\n    return {\n      id,\n      appName: data.appName,\n      subId: data.subId,\n      fileName: data.file.name,\n    };\n  });\n"],"mappings":"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"}