@burdenoff/microfe-theculturepost 2026.705.1 → 2026.705.2

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.
@@ -4,7 +4,7 @@ import { useQuery as t } from "@tanstack/react-query";
4
4
  import { getWorkspaceClient as n, gql as r, graphqlFetch as i } from "@burdenoff/fe-libs/shared/graphql";
5
5
  import { uploadBlobToFiles as a } from "@burdenoff/fe-libs/storage";
6
6
  //#region src/theculturepost/hooks/useFiles.ts
7
- var o = 31536e3, s = {
7
+ var o = 21600, s = {
8
8
  covers: "/TheCulturePost/Covers",
9
9
  artifacts: "/TheCulturePost/Artifacts",
10
10
  recordings: "/TheCulturePost/Recordings"
@@ -1 +1 @@
1
- {"version":3,"file":"useFiles.js","names":[],"sources":["../../../src/theculturepost/hooks/useFiles.ts"],"sourcesContent":["/**\n * File hooks — covers, artifacts & recordings via wspace-files-svc (NO duplication).\n * @module theculturepost/hooks\n *\n * TheCulturePost never stores blobs. Stories keep `coverFileId`, archive items\n * keep `fileId`, citations keep `sourceFileId`, oral histories keep\n * `recordingFileId` — all pointing at files owned by wspace-files-svc. Upload\n * goes through the shared `uploadBlobToFiles` storage helper (presigned 3-step\n * upload) against the workspace Apollo client the shell initialises; display\n * resolves a file id to a presigned URL via `getFileDownloadUrl`.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch, getWorkspaceClient, gql } from '@burdenoff/fe-libs/shared/graphql';\nimport { uploadBlobToFiles } from '@burdenoff/fe-libs/storage';\n\nimport { useTheCulturePost } from '../context';\n\n/** One year — covers/artifacts/recordings are long-lived references. */\nconst DOWNLOAD_URL_TTL_SECONDS = 31_536_000;\n\nexport const FILE_FOLDERS = {\n covers: '/TheCulturePost/Covers',\n artifacts: '/TheCulturePost/Artifacts',\n recordings: '/TheCulturePost/Recordings',\n} as const;\n\nconst ENSURE_FOLDER = gql`\n mutation TcpEnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) {\n id\n }\n }\n`;\n\nconst GET_FILE_DOWNLOAD_URL = gql`\n query TcpGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }\n`;\n\nexport interface UploadedFile {\n id: string;\n url: string;\n name: string;\n}\n\ninterface EnsureFolderData {\n ensureFolderByPath?: { id: string } | null;\n}\ninterface DownloadUrlData {\n getFileDownloadUrl?: string | null;\n}\n\n/**\n * Upload a file (image, audio, document…) to wspace-files-svc and return its id\n * + a presigned URL. The caller persists the id (coverFileId / fileId /\n * recordingFileId / sourceFileId) via the entity's own tcp* mutation; the URL is\n * used for an immediate preview.\n */\nexport async function uploadImageToFiles(file: File, folderPath: string): Promise<UploadedFile> {\n const client = getWorkspaceClient();\n\n const folderResult = await client.mutate<EnsureFolderData>({\n mutation: ENSURE_FOLDER,\n variables: { path: folderPath },\n });\n const folderId = folderResult.data?.ensureFolderByPath?.id;\n if (!folderId) {\n throw new Error('Could not resolve the upload folder.');\n }\n\n const uploaded = await uploadBlobToFiles({\n client,\n blob: file,\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n folderId,\n });\n\n const urlResult = await client.query<DownloadUrlData>({\n query: GET_FILE_DOWNLOAD_URL,\n variables: { id: uploaded.id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n fetchPolicy: 'no-cache',\n });\n const url = urlResult.data?.getFileDownloadUrl;\n if (!url) {\n throw new Error('The file was uploaded but no download URL was returned.');\n }\n\n return { id: uploaded.id, url, name: uploaded.name };\n}\n\n/** Resolve a wspace-files-svc file id to a presigned download URL for display. */\nexport function useFileUrl(fileId?: string | null) {\n const { apiGatewayUrl } = useTheCulturePost();\n return useQuery({\n queryKey: ['theculturepost', 'file-url', fileId ?? ''],\n enabled: Boolean(fileId),\n staleTime: 30 * 60 * 1000,\n retry: 1,\n queryFn: async () => {\n const response = await graphqlFetch<{ getFileDownloadUrl: string | null }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n workspaceToken: true,\n query: `query TcpFileUrl($id: ID!, $expiresIn: Int) { getFileDownloadUrl(id: $id, expiresIn: $expiresIn) }`,\n variables: { id: fileId, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'Could not resolve file URL');\n }\n return response.data?.getFileDownloadUrl ?? null;\n },\n });\n}\n"],"mappings":";;;;;;AAmBA,IAAM,IAA2B,SAEpB,IAAe;CAC1B,QAAQ;CACR,WAAW;CACX,YAAY;CACb,EAEK,IAAgB,CAAG;;;;;;GAQnB,IAAwB,CAAG;;;;;AAyBjC,eAAsB,EAAmB,GAAY,GAA2C;CAC9F,IAAM,IAAS,GAAoB,EAM7B,KAJe,MAAM,EAAO,OAAyB;EACzD,UAAU;EACV,WAAW,EAAE,MAAM,GAAY;EAChC,CAAC,EAC4B,MAAM,oBAAoB;AACxD,KAAI,CAAC,EACH,OAAU,MAAM,uCAAuC;CAGzD,IAAM,IAAW,MAAM,EAAkB;EACvC;EACA,MAAM;EACN,UAAU,EAAK;EACf,UAAU,EAAK,QAAQ;EACvB;EACD,CAAC,EAOI,KALY,MAAM,EAAO,MAAuB;EACpD,OAAO;EACP,WAAW;GAAE,IAAI,EAAS;GAAI,WAAW;GAA0B;EACnE,aAAa;EACd,CAAC,EACoB,MAAM;AAC5B,KAAI,CAAC,EACH,OAAU,MAAM,0DAA0D;AAG5E,QAAO;EAAE,IAAI,EAAS;EAAI;EAAK,MAAM,EAAS;EAAM;;AAItD,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,qBAAkB,GAAmB;AAC7C,QAAO,EAAS;EACd,UAAU;GAAC;GAAkB;GAAY,KAAU;GAAG;EACtD,SAAS,EAAQ;EACjB,WAAW,OAAU;EACrB,OAAO;EACP,SAAS,YAAY;GACnB,IAAM,IAAW,MAAM,EAAoD;IACzE,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,WAAW;KAAE,IAAI;KAAQ,WAAW;KAA0B;IAC/D,CAAC;AACF,OAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,6BAA6B;AAE9E,UAAO,EAAS,MAAM,sBAAsB;;EAE/C,CAAC"}
1
+ {"version":3,"file":"useFiles.js","names":[],"sources":["../../../src/theculturepost/hooks/useFiles.ts"],"sourcesContent":["/**\n * File hooks — covers, artifacts & recordings via wspace-files-svc (NO duplication).\n * @module theculturepost/hooks\n *\n * TheCulturePost never stores blobs. Stories keep `coverFileId`, archive items\n * keep `fileId`, citations keep `sourceFileId`, oral histories keep\n * `recordingFileId` — all pointing at files owned by wspace-files-svc. Upload\n * goes through the shared `uploadBlobToFiles` storage helper (presigned 3-step\n * upload) against the workspace Apollo client the shell initialises; display\n * resolves a file id to a presigned URL via `getFileDownloadUrl`.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch, getWorkspaceClient, gql } from '@burdenoff/fe-libs/shared/graphql';\nimport { uploadBlobToFiles } from '@burdenoff/fe-libs/storage';\n\nimport { useTheCulturePost } from '../context';\n\n/**\n * Presigned-URL lifetime, in seconds. S3 caps a presigned GET at 7 days\n * (604800s); anything longer makes wspace-files-svc `getFileDownloadUrl` throw\n * INTERNAL_SERVER_ERROR. React Query re-resolves these long before expiry\n * (30-min staleTime), so 6 hours is ample and stays safely under the cap.\n */\nconst DOWNLOAD_URL_TTL_SECONDS = 21_600;\n\nexport const FILE_FOLDERS = {\n covers: '/TheCulturePost/Covers',\n artifacts: '/TheCulturePost/Artifacts',\n recordings: '/TheCulturePost/Recordings',\n} as const;\n\nconst ENSURE_FOLDER = gql`\n mutation TcpEnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) {\n id\n }\n }\n`;\n\nconst GET_FILE_DOWNLOAD_URL = gql`\n query TcpGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }\n`;\n\nexport interface UploadedFile {\n id: string;\n url: string;\n name: string;\n}\n\ninterface EnsureFolderData {\n ensureFolderByPath?: { id: string } | null;\n}\ninterface DownloadUrlData {\n getFileDownloadUrl?: string | null;\n}\n\n/**\n * Upload a file (image, audio, document…) to wspace-files-svc and return its id\n * + a presigned URL. The caller persists the id (coverFileId / fileId /\n * recordingFileId / sourceFileId) via the entity's own tcp* mutation; the URL is\n * used for an immediate preview.\n */\nexport async function uploadImageToFiles(file: File, folderPath: string): Promise<UploadedFile> {\n const client = getWorkspaceClient();\n\n const folderResult = await client.mutate<EnsureFolderData>({\n mutation: ENSURE_FOLDER,\n variables: { path: folderPath },\n });\n const folderId = folderResult.data?.ensureFolderByPath?.id;\n if (!folderId) {\n throw new Error('Could not resolve the upload folder.');\n }\n\n const uploaded = await uploadBlobToFiles({\n client,\n blob: file,\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n folderId,\n });\n\n const urlResult = await client.query<DownloadUrlData>({\n query: GET_FILE_DOWNLOAD_URL,\n variables: { id: uploaded.id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n fetchPolicy: 'no-cache',\n });\n const url = urlResult.data?.getFileDownloadUrl;\n if (!url) {\n throw new Error('The file was uploaded but no download URL was returned.');\n }\n\n return { id: uploaded.id, url, name: uploaded.name };\n}\n\n/** Resolve a wspace-files-svc file id to a presigned download URL for display. */\nexport function useFileUrl(fileId?: string | null) {\n const { apiGatewayUrl } = useTheCulturePost();\n return useQuery({\n queryKey: ['theculturepost', 'file-url', fileId ?? ''],\n enabled: Boolean(fileId),\n staleTime: 30 * 60 * 1000,\n retry: 1,\n queryFn: async () => {\n const response = await graphqlFetch<{ getFileDownloadUrl: string | null }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n workspaceToken: true,\n query: `query TcpFileUrl($id: ID!, $expiresIn: Int) { getFileDownloadUrl(id: $id, expiresIn: $expiresIn) }`,\n variables: { id: fileId, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'Could not resolve file URL');\n }\n return response.data?.getFileDownloadUrl ?? null;\n },\n });\n}\n"],"mappings":";;;;;;AAwBA,IAAM,IAA2B,OAEpB,IAAe;CAC1B,QAAQ;CACR,WAAW;CACX,YAAY;CACb,EAEK,IAAgB,CAAG;;;;;;GAQnB,IAAwB,CAAG;;;;;AAyBjC,eAAsB,EAAmB,GAAY,GAA2C;CAC9F,IAAM,IAAS,GAAoB,EAM7B,KAJe,MAAM,EAAO,OAAyB;EACzD,UAAU;EACV,WAAW,EAAE,MAAM,GAAY;EAChC,CAAC,EAC4B,MAAM,oBAAoB;AACxD,KAAI,CAAC,EACH,OAAU,MAAM,uCAAuC;CAGzD,IAAM,IAAW,MAAM,EAAkB;EACvC;EACA,MAAM;EACN,UAAU,EAAK;EACf,UAAU,EAAK,QAAQ;EACvB;EACD,CAAC,EAOI,KALY,MAAM,EAAO,MAAuB;EACpD,OAAO;EACP,WAAW;GAAE,IAAI,EAAS;GAAI,WAAW;GAA0B;EACnE,aAAa;EACd,CAAC,EACoB,MAAM;AAC5B,KAAI,CAAC,EACH,OAAU,MAAM,0DAA0D;AAG5E,QAAO;EAAE,IAAI,EAAS;EAAI;EAAK,MAAM,EAAS;EAAM;;AAItD,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,qBAAkB,GAAmB;AAC7C,QAAO,EAAS;EACd,UAAU;GAAC;GAAkB;GAAY,KAAU;GAAG;EACtD,SAAS,EAAQ;EACjB,WAAW,OAAU;EACrB,OAAO;EACP,SAAS,YAAY;GACnB,IAAM,IAAW,MAAM,EAAoD;IACzE,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,WAAW;KAAE,IAAI;KAAQ,WAAW;KAA0B;IAC/D,CAAC;AACF,OAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,6BAA6B;AAE9E,UAAO,EAAS,MAAM,sBAAsB;;EAE/C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-theculturepost",
3
- "version": "2026.705.1",
3
+ "version": "2026.705.2",
4
4
  "description": "Burdenoff TheCulturePost Microfrontend",
5
5
  "type": "module",
6
6
  "files": [