UNPKG

@azure-utils/storybooks

Version:

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

87 lines (84 loc) 3.78 kB
import { getStore, responseError, urlBuilder } from "./store-BL4RNiEp.mjs"; import { CACHE_CONTROL_PUBLIC_YEAR, commonErrorResponses } from "./constants-CsV1N9r4.mjs"; import { generateAzureStorageContainerName } from "./azure-storage-blob-Dj53y4ng.mjs"; import { BuildSHASchema, ProjectIdSchema } from "./shared-BAE3ceND.mjs"; import { openAPITags, registerOpenAPIPath } from "./openapi-utils-CAJ85ahl.mjs"; import { joinUrl } from "./url-utils-B9Pl4bQ7.mjs"; import { app } from "@azure/functions"; import z from "zod"; import { BlobServiceClient } from "@azure/storage-blob"; import path from "node:path"; import { Readable } from "node:stream"; //#region src/handlers/storybook-handler.tsx async function serveStorybook(request, context) { const { projectId = "", buildSHA = "", filepath = "" } = request.params; const blobName = path.posix.join(buildSHA, filepath); context.log("Serving SB (%s) - %s...", projectId, blobName); const { connectionString } = getStore(); const blockBlobClient = BlobServiceClient.fromConnectionString(connectionString).getContainerClient(generateAzureStorageContainerName(projectId)).getBlockBlobClient(blobName); if (!await blockBlobClient.exists()) return responseError(`File '${blobName}' not found.`, context, 404); if (blobName.endsWith("index.html")) { const buffer = await blockBlobClient.downloadToBuffer(0); const bodyWithBackButton = buffer.toString("utf8").replace(`</body>`, ` <div><a id="view-all" href="${urlBuilder.allBuilds(projectId)}" 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;"> ← View all </a></div></body>`); return { headers: { "Cache-Control": CACHE_CONTROL_PUBLIC_YEAR, "Content-Type": "text/html; charset=utf8", "Content-Length": Buffer.byteLength(bodyWithBackButton).toString() }, body: bodyWithBackButton, status: 200 }; } const downloadResponse = await blockBlobClient.download(0); const headers = new Headers(); headers.set("Cache-Control", CACHE_CONTROL_PUBLIC_YEAR); headers.set("Content-Type", downloadResponse.contentType || "application/octet-stream"); if (downloadResponse.contentLength) headers.set("Content-Length", downloadResponse.contentLength.toString()); if (downloadResponse.contentEncoding) headers.set("Content-Encoding", downloadResponse.contentEncoding); return { body: Readable.toWeb(downloadResponse.readableStreamBody), headers, status: 200 }; } //#endregion //#region src/routers/storybook-router.ts const TAG = openAPITags.storybook.name; function registerStorybookRouter(options) { const { authLevel, baseRoute, basePathParamsSchema, handlerWrapper, openAPIEnabled, serviceName } = options; const storybookRoute = joinUrl(baseRoute, "{projectId}", "{buildSHA}", "{**filepath}"); app.get(`${serviceName}-serve-storybook`, { authLevel, route: storybookRoute, handler: handlerWrapper(serveStorybook, [{ resource: "build", action: "read" }]) }); if (openAPIEnabled) registerOpenAPIPath(storybookRoute, { get: { tags: [TAG], summary: "List all projects", description: "Retrieves a list of projects.", requestParams: { path: basePathParamsSchema.extend({ projectId: ProjectIdSchema, buildSHA: BuildSHASchema, "**filepath": z.string().meta({ description: "The path to the storybook files.", example: "index.html" }) }) }, responses: { ...commonErrorResponses, 200: { description: "Serve the file." }, 404: { description: "File not found." } } } }); } //#endregion export { registerStorybookRouter }; //# sourceMappingURL=storybook-router-CnKx8NCO.mjs.map