UNPKG

@azure-utils/storybooks

Version:

Utils to upload and manage Storybooks via Azure Functions and storage.

1 lines 6.58 kB
{"version":3,"file":"storybook-router-CnKx8NCO.mjs","names":["request: HttpRequest","context: InvocationContext","options: RouterOptions"],"sources":["../src/handlers/storybook-handler.tsx","../src/routers/storybook-router.ts"],"sourcesContent":["import type {\n HttpRequest,\n HttpResponseInit,\n InvocationContext,\n} from \"@azure/functions\";\nimport { BlobServiceClient } from \"@azure/storage-blob\";\nimport path from \"node:path\";\nimport { generateAzureStorageContainerName } from \"../utils/azure-storage-blob\";\nimport { responseError } from \"../utils/response-utils\";\nimport { CACHE_CONTROL_PUBLIC_YEAR } from \"../utils/constants\";\nimport { Readable } from \"node:stream\";\nimport { getStore } from \"../utils/store\";\nimport { urlBuilder } from \"../utils/url-builder\";\n\nexport async function serveStorybook(\n request: HttpRequest,\n context: InvocationContext\n): Promise<HttpResponseInit> {\n const { projectId = \"\", buildSHA = \"\", filepath = \"\" } = request.params;\n const blobName = path.posix.join(buildSHA, filepath);\n context.log(\"Serving SB (%s) - %s...\", projectId, blobName);\n\n const { connectionString } = getStore();\n const blockBlobClient = BlobServiceClient.fromConnectionString(\n connectionString\n )\n .getContainerClient(generateAzureStorageContainerName(projectId))\n .getBlockBlobClient(blobName);\n\n if (!(await blockBlobClient.exists())) {\n return responseError(`File '${blobName}' not found.`, context, 404);\n }\n\n if (blobName.endsWith(\"index.html\")) {\n const buffer = await blockBlobClient.downloadToBuffer(0);\n // Add a back button to the bottom of the page\n const bodyWithBackButton = buffer.toString(\"utf8\").replace(\n `</body>`,\n `\n <div><a id=\"view-all\" href=\"${urlBuilder.allBuilds(projectId)}\"\n style=\"position: fixed; bottom: 0.5rem; left: 0.5rem; z-index: 9999; padding: 0.25rem 0.5rem; background-color: black; color: white; border-radius: 0.25rem; text-decoration: none; font-size: 1rem; font-face: sans-serif; font-weight: 400;\">\n ← View all\n </a></div></body>`\n );\n\n return {\n headers: {\n \"Cache-Control\": CACHE_CONTROL_PUBLIC_YEAR,\n \"Content-Type\": \"text/html; charset=utf8\",\n \"Content-Length\": Buffer.byteLength(bodyWithBackButton).toString(),\n },\n body: bodyWithBackButton,\n status: 200,\n };\n }\n\n // For all other files, we stream the blob and return it\n const downloadResponse = await blockBlobClient.download(0);\n\n const headers = new Headers();\n headers.set(\"Cache-Control\", CACHE_CONTROL_PUBLIC_YEAR);\n headers.set(\n \"Content-Type\",\n downloadResponse.contentType || \"application/octet-stream\"\n );\n if (downloadResponse.contentLength) {\n headers.set(\"Content-Length\", downloadResponse.contentLength.toString());\n }\n if (downloadResponse.contentEncoding) {\n headers.set(\"Content-Encoding\", downloadResponse.contentEncoding);\n }\n\n return {\n body: Readable.toWeb(downloadResponse.readableStreamBody as Readable),\n headers,\n status: 200,\n };\n}\n","import { app } from \"@azure/functions\";\nimport { commonErrorResponses } from \"../utils/constants\";\nimport { openAPITags, registerOpenAPIPath } from \"../utils/openapi-utils\";\nimport type { RouterOptions } from \"../utils/types\";\nimport z from \"zod\";\nimport { joinUrl } from \"../utils/url-utils\";\nimport { serveStorybook } from \"../handlers/storybook-handler\";\nimport { BuildSHASchema, ProjectIdSchema } from \"../models/shared\";\n\nconst TAG = openAPITags.storybook.name;\n\nexport function registerStorybookRouter(options: RouterOptions) {\n const {\n authLevel,\n baseRoute,\n basePathParamsSchema,\n handlerWrapper,\n openAPIEnabled,\n serviceName,\n } = options;\n\n const storybookRoute = joinUrl(\n baseRoute,\n \"{projectId}\",\n \"{buildSHA}\",\n \"{**filepath}\"\n );\n\n app.get(`${serviceName}-serve-storybook`, {\n authLevel,\n route: storybookRoute,\n handler: handlerWrapper(serveStorybook, [\n { resource: \"build\", action: \"read\" },\n ]),\n });\n\n if (openAPIEnabled) {\n registerOpenAPIPath(storybookRoute, {\n get: {\n tags: [TAG],\n summary: \"List all projects\",\n description: \"Retrieves a list of projects.\",\n requestParams: {\n path: basePathParamsSchema.extend({\n projectId: ProjectIdSchema,\n buildSHA: BuildSHASchema,\n \"**filepath\": z.string().meta({\n description: \"The path to the storybook files.\",\n example: \"index.html\",\n }),\n }),\n },\n responses: {\n ...commonErrorResponses,\n 200: { description: \"Serve the file.\" },\n 404: { description: \"File not found.\" },\n },\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,eAAsB,eACpBA,SACAC,SAC2B;CAC3B,MAAM,EAAE,YAAY,IAAI,WAAW,IAAI,WAAW,IAAI,GAAG,QAAQ;CACjE,MAAM,WAAW,KAAK,MAAM,KAAK,UAAU,SAAS;CACpD,QAAQ,IAAI,2BAA2B,WAAW,SAAS;CAE3D,MAAM,EAAE,kBAAkB,GAAG,UAAU;CACvC,MAAM,kBAAkB,kBAAkB,qBACxC,iBACD,CACE,mBAAmB,kCAAkC,UAAU,CAAC,CAChE,mBAAmB,SAAS;AAE/B,KAAI,CAAE,MAAM,gBAAgB,QAAQ,CAClC,QAAO,cAAc,CAAC,MAAM,EAAE,SAAS,YAAY,CAAC,EAAE,SAAS,IAAI;AAGrE,KAAI,SAAS,SAAS,aAAa,EAAE;EACnC,MAAM,SAAS,MAAM,gBAAgB,iBAAiB,EAAE;EAExD,MAAM,qBAAqB,OAAO,SAAS,OAAO,CAAC,QACjD,CAAC,OAAO,CAAC,EACT,CAAC;kCAC2B,EAAE,WAAW,UAAU,UAAU,CAAC;;;uBAG7C,CAAC,CACnB;AAED,SAAO;GACL,SAAS;IACP,iBAAiB;IACjB,gBAAgB;IAChB,kBAAkB,OAAO,WAAW,mBAAmB,CAAC,UAAU;GACnE;GACD,MAAM;GACN,QAAQ;EACT;CACF;CAGD,MAAM,mBAAmB,MAAM,gBAAgB,SAAS,EAAE;CAE1D,MAAM,UAAU,IAAI;CACpB,QAAQ,IAAI,iBAAiB,0BAA0B;CACvD,QAAQ,IACN,gBACA,iBAAiB,eAAe,2BACjC;AACD,KAAI,iBAAiB,eACnB,QAAQ,IAAI,kBAAkB,iBAAiB,cAAc,UAAU,CAAC;AAE1E,KAAI,iBAAiB,iBACnB,QAAQ,IAAI,oBAAoB,iBAAiB,gBAAgB;AAGnE,QAAO;EACL,MAAM,SAAS,MAAM,iBAAiB,mBAA+B;EACrE;EACA,QAAQ;CACT;AACF;;;;ACpED,MAAM,MAAM,YAAY,UAAU;AAElC,SAAgB,wBAAwBC,SAAwB;CAC9D,MAAM,EACJ,WACA,WACA,sBACA,gBACA,gBACA,aACD,GAAG;CAEJ,MAAM,iBAAiB,QACrB,WACA,eACA,cACA,eACD;CAED,IAAI,IAAI,GAAG,YAAY,gBAAgB,CAAC,EAAE;EACxC;EACA,OAAO;EACP,SAAS,eAAe,gBAAgB,CACtC;GAAE,UAAU;GAAS,QAAQ;EAAQ,CACtC,EAAC;CACH,EAAC;AAEF,KAAI,gBACF,oBAAoB,gBAAgB,EAClC,KAAK;EACH,MAAM,CAAC,GAAI;EACX,SAAS;EACT,aAAa;EACb,eAAe,EACb,MAAM,qBAAqB,OAAO;GAChC,WAAW;GACX,UAAU;GACV,cAAc,EAAE,QAAQ,CAAC,KAAK;IAC5B,aAAa;IACb,SAAS;GACV,EAAC;EACH,EAAC,CACH;EACD,WAAW;GACT,GAAG;GACH,KAAK,EAAE,aAAa,kBAAmB;GACvC,KAAK,EAAE,aAAa,kBAAmB;EACxC;CACF,EACF,EAAC;AAEL"}