Files
template-app/modules/branding/adapters/procedures.ts
T

57 lines
2.1 KiB
TypeScript

// The handlers of the branding procedures: each resolves its ports and calls one use case.
import { type Container, implement, validationFailed } from "@conusai-kit/core"
import { DATA_SOURCE, OBJECT_STORE } from "@conusai-kit/data"
import { brandGet, brandSet, logoClear, logoGet, logoSet } from "../contract/index.js"
import { type BrandingDeps, clearLogo, getBrand, readLogo, setBrand, setLogo } from "../core/brand.js"
export const brandingDeps = (container: Container): BrandingDeps => ({
data: container.resolve(DATA_SOURCE),
store: container.resolve(OBJECT_STORE),
})
/** Standard base64 to bytes, refusing anything else as a 422 that names the field. */
function bytesOf(body: string): Uint8Array {
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(body) || body.length % 4 !== 0) {
throw validationFailed([{ path: "body", message: "is not standard base64" }])
}
return Uint8Array.from(atob(body), (char) => char.charCodeAt(0))
}
const toBase64 = (bytes: Uint8Array): string => {
let binary = ""
for (const byte of bytes) binary += String.fromCharCode(byte)
return btoa(binary)
}
export const brandGetImpl = implement(brandGet, async ({ ctx }) =>
getBrand(brandingDeps(ctx.container).data, ctx.scope),
)
export const brandSetImpl = implement(brandSet, async ({ input, ctx }) =>
setBrand(brandingDeps(ctx.container).data, ctx.scope, {
displayName: input.displayName,
primary: input.primary,
accent: input.accent,
}),
)
export const logoSetImpl = implement(logoSet, async ({ input, ctx }) =>
setLogo(brandingDeps(ctx.container), ctx.scope, {
variant: input.variant,
contentType: input.contentType,
bytes: bytesOf(input.body),
}),
)
export const logoClearImpl = implement(logoClear, async ({ input, ctx }) =>
clearLogo(brandingDeps(ctx.container), ctx.scope, input.variant),
)
export const logoGetImpl = implement(logoGet, async ({ input, ctx }) => {
const logo = await readLogo(brandingDeps(ctx.container), ctx.scope, input.variant, input.size)
return { contentType: logo.contentType, body: toBase64(logo.bytes) }
})
export const BRANDING_PROCEDURES = [brandGetImpl, brandSetImpl, logoSetImpl, logoClearImpl, logoGetImpl]