@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 6.79 kB
Source Map (JSON)
{"version":3,"file":"stream-media.mjs","names":["constants","mediaShareLinkServices.authorizeShare","mediaShareLinkServices.getShareAccess","mediaShareLinkServices.streamMedia"],"sources":["../../../../../src/libs/http/controllers/share/stream-media.ts"],"sourcesContent":["import { Readable } from \"node:stream\";\nimport { minutesToMilliseconds } from \"date-fns\";\nimport { getCookie } from \"hono/cookie\";\nimport { createFactory } from \"hono/factory\";\nimport { stream } from \"hono/streaming\";\nimport { describeRoute } from \"hono-openapi\";\nimport constants from \"../../../../constants/constants.js\";\nimport { controllerSchemas } from \"../../../../schemas/share.js\";\nimport { mediaShareLinkServices } from \"../../../../services/index.js\";\nimport { LucidAPIError } from \"../../../../utils/errors/index.js\";\nimport serviceWrapper from \"../../../../utils/services/service-wrapper.js\";\nimport createAuthCookieName from \"../../../../utils/share-link/auth-cookie.js\";\nimport { copy } from \"../../../i18n/index.js\";\nimport rateLimiter from \"../../middleware/rate-limiter.js\";\nimport validate from \"../../middleware/validate.js\";\nimport openAPI from \"../../openapi/index.js\";\nimport createServiceContext from \"../../utils/create-service-context.js\";\nimport {\n\tapplyRangeHeaders,\n\tapplyStreamingHeaders,\n\tparseRangeHeader,\n} from \"../../utils/streaming.js\";\n\nconst factory = createFactory();\n\n/**\n * Stream shared media content by token for previewable media types.\n */\nconst streamMediaController = factory.createHandlers(\n\tdescribeRoute({\n\t\tdescription: \"Streams shared media content by token.\",\n\t\ttags: [\"share\"],\n\t\tsummary: \"Stream Shared Media\",\n\t\tparameters: openAPI.parameters({\n\t\t\tparams: controllerSchemas.streamShareMedia.params,\n\t\t}),\n\t}),\n\trateLimiter({\n\t\tmode: \"ip\",\n\t\tscope: constants.rateLimit.scopes.stream.scopeKey,\n\t\tlimit: constants.rateLimit.scopes.stream.limit,\n\t\twindowMs: minutesToMilliseconds(1),\n\t}),\n\tvalidate(\"param\", controllerSchemas.streamShareMedia.params),\n\tvalidate(\"query\", controllerSchemas.streamShareMedia.query.string),\n\tasync (c) => {\n\t\tconst { token } = c.req.valid(\"param\");\n\t\tconst query = c.req.valid(\"query\");\n\t\tconst context = createServiceContext(c);\n\t\tconst range = parseRangeHeader(c.req.header(\"range\"));\n\n\t\tconst cookieName = createAuthCookieName(token);\n\t\tconst sessionCookie = getCookie(c, cookieName);\n\n\t\tconst authorizeRes = await serviceWrapper(\n\t\t\tmediaShareLinkServices.authorizeShare,\n\t\t\t{ transaction: false },\n\t\t)(context, {\n\t\t\ttoken,\n\t\t\tsessionCookie,\n\t\t\tenforcePasswordSession: true,\n\t\t});\n\t\tif (authorizeRes.error) throw new LucidAPIError(authorizeRes.error);\n\n\t\tconst shareAccessRes = await serviceWrapper(\n\t\t\tmediaShareLinkServices.getShareAccess,\n\t\t\t{ transaction: false },\n\t\t)(context, { token, sessionCookie });\n\t\tif (shareAccessRes.error) throw new LucidAPIError(shareAccessRes.error);\n\n\t\tif (shareAccessRes.data.passwordRequired) {\n\t\t\tthrow new LucidAPIError({\n\t\t\t\ttype: \"authorisation\",\n\t\t\t\tstatus: 401,\n\t\t\t\tname: copy(\"server:core.share.stream.password.required.title\"),\n\t\t\t\tmessage: copy(\"server:core.share.stream.password.required.message\"),\n\t\t\t});\n\t\t}\n\n\t\t//* we only support previews on images, video and audio for the time being\n\t\tif (!shareAccessRes.data.media.previewable) {\n\t\t\tthrow new LucidAPIError({\n\t\t\t\ttype: \"basic\",\n\t\t\t\tstatus: 415,\n\t\t\t\tname: copy(\"server:core.share.stream.unsupported.media.type.name\"),\n\t\t\t\tmessage: copy(\n\t\t\t\t\t\"server:core.share.stream.unsupported.media.type.message\",\n\t\t\t\t),\n\t\t\t});\n\t\t}\n\n\t\tconst mediaKey =\n\t\t\tquery.poster === \"true\" && authorizeRes.data.posterKey\n\t\t\t\t? authorizeRes.data.posterKey\n\t\t\t\t: authorizeRes.data.mediaKey;\n\n\t\tconst response = await serviceWrapper(mediaShareLinkServices.streamMedia, {\n\t\t\ttransaction: false,\n\t\t})(context, { mediaKey, range });\n\t\tif (response.error) throw new LucidAPIError(response.error);\n\n\t\tapplyRangeHeaders(c, {\n\t\t\tisPartial: response.data.isPartialContent,\n\t\t\trange: response.data.range,\n\t\t\ttotalSize: response.data.totalSize,\n\t\t});\n\t\tapplyStreamingHeaders(c, {\n\t\t\tkey: response.data.key,\n\t\t\tcontentLength: response.data.contentLength,\n\t\t\tcontentType: response.data.contentType,\n\t\t\tetag: response.data.etag ?? undefined,\n\t\t});\n\n\t\treturn stream(c, async (stream) => {\n\t\t\tif (response.data.body instanceof ReadableStream) {\n\t\t\t\tawait stream.pipe(response.data.body);\n\t\t\t} else if (response.data.body instanceof Uint8Array) {\n\t\t\t\tawait stream.write(response.data.body);\n\t\t\t} else if (response.data.body instanceof Readable) {\n\t\t\t\tfor await (const chunk of response.data.body) {\n\t\t\t\t\tawait stream.write(chunk);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n);\n\nexport default streamMediaController;\n"],"mappings":"imCA4BA,MAAM,EALU,EAKoB,CAAC,CAAC,eACrC,EAAc,CACb,YAAa,yCACb,KAAM,CAAC,OAAO,EACd,QAAS,sBACT,WAAY,EAAQ,WAAW,CAC9B,OAAQ,EAAkB,iBAAiB,MAC5C,CAAC,CACF,CAAC,EACD,EAAY,CACX,KAAM,KACN,MAAOA,EAAU,UAAU,OAAO,OAAO,SACzC,MAAOA,EAAU,UAAU,OAAO,OAAO,MACzC,SAAU,EAAsB,CAAC,CAClC,CAAC,EACD,EAAS,QAAS,EAAkB,iBAAiB,MAAM,EAC3D,EAAS,QAAS,EAAkB,iBAAiB,MAAM,MAAM,EACjE,KAAO,IAAM,CACZ,GAAM,CAAE,SAAU,EAAE,IAAI,MAAM,OAAO,EAC/B,EAAQ,EAAE,IAAI,MAAM,OAAO,EAC3B,EAAU,EAAqB,CAAC,EAChC,EAAQ,EAAiB,EAAE,IAAI,OAAO,OAAO,CAAC,EAG9C,EAAgB,EAAU,EADb,EAAqB,CACI,CAAC,EAEvC,EAAe,MAAM,EAC1BC,EACA,CAAE,YAAa,EAAM,CACtB,CAAC,CAAC,EAAS,CACV,QACA,gBACA,uBAAwB,EACzB,CAAC,EACD,GAAI,EAAa,MAAO,MAAM,IAAI,EAAc,EAAa,KAAK,EAElE,IAAM,EAAiB,MAAM,EAC5BC,EACA,CAAE,YAAa,EAAM,CACtB,CAAC,CAAC,EAAS,CAAE,QAAO,eAAc,CAAC,EACnC,GAAI,EAAe,MAAO,MAAM,IAAI,EAAc,EAAe,KAAK,EAEtE,GAAI,EAAe,KAAK,iBACvB,MAAM,IAAI,EAAc,CACvB,KAAM,gBACN,OAAQ,IACR,KAAM,EAAK,kDAAkD,EAC7D,QAAS,EAAK,oDAAoD,CACnE,CAAC,EAIF,GAAI,CAAC,EAAe,KAAK,MAAM,YAC9B,MAAM,IAAI,EAAc,CACvB,KAAM,QACN,OAAQ,IACR,KAAM,EAAK,sDAAsD,EACjE,QAAS,EACR,yDACD,CACD,CAAC,EAGF,IAAM,EACL,EAAM,SAAW,QAAU,EAAa,KAAK,UAC1C,EAAa,KAAK,UAClB,EAAa,KAAK,SAEhB,EAAW,MAAM,EAAeC,EAAoC,CACzE,YAAa,EACd,CAAC,CAAC,CAAC,EAAS,CAAE,WAAU,OAAM,CAAC,EAC/B,GAAI,EAAS,MAAO,MAAM,IAAI,EAAc,EAAS,KAAK,EAc1D,OAZA,EAAkB,EAAG,CACpB,UAAW,EAAS,KAAK,iBACzB,MAAO,EAAS,KAAK,MACrB,UAAW,EAAS,KAAK,SAC1B,CAAC,EACD,EAAsB,EAAG,CACxB,IAAK,EAAS,KAAK,IACnB,cAAe,EAAS,KAAK,cAC7B,YAAa,EAAS,KAAK,YAC3B,KAAM,EAAS,KAAK,MAAQ,IAAA,EAC7B,CAAC,EAEM,EAAO,EAAG,KAAO,IAAW,CAClC,GAAI,EAAS,KAAK,gBAAgB,eACjC,MAAM,EAAO,KAAK,EAAS,KAAK,IAAI,OAC9B,GAAI,EAAS,KAAK,gBAAgB,WACxC,MAAM,EAAO,MAAM,EAAS,KAAK,IAAI,OAC/B,GAAI,EAAS,KAAK,gBAAgB,EACxC,UAAW,IAAM,KAAS,EAAS,KAAK,KACvC,MAAM,EAAO,MAAM,CAAK,CAG3B,CAAC,CACF,CACD"}