import { z } from "zod"; import { AbstractApplication, type IconDescriptor, } from "./applications/applications"; import { getSanityDomain } from "./env"; import { OrganizationId } from "./organizations"; /** * Canvas ID schema, branded for type safety. * @public */ const CanvasIdSchema = z.string().nonempty().brand("CanvasId"); /** * Canvas ID type, branded for type safety. * @public */ export type CanvasId = z.output; /** * Validates and brands a string as a CanvasId. * @public */ export function brandCanvasId(id: string): CanvasId { return CanvasIdSchema.parse(id); } const CanvasSchema = z.object({ id: CanvasIdSchema, organizationId: OrganizationId, status: z.enum(["active", "provisioning"]), }); /** * Represents a Canvas resource as returned from the API. * @public */ export type Canvas = z.output; /** * Validates and parses a raw API response into a branded * Canvas. * @public */ export function parseCanvas(data: unknown): Canvas { return CanvasSchema.parse(data); } /** * Whilst the constructor takes an organization's canvas resource the existance * therefore implies the organization has access to the canvas application which * is what workbench most importantly wants to know. * @public */ export class CanvasApplication extends AbstractApplication<"canvas"> { readonly canvas: Canvas; constructor(canvas: Canvas) { super("canvas"); this.canvas = canvas; } get id(): CanvasId { return this.canvas.id; } get href(): string { return "canvas"; } get title(): string { return "Canvas"; } get url(): URL { return new URL( `https://canvas.${getSanityDomain()}/o/${this.canvas.organizationId}`, ); } get isFederated(): boolean { return false; } get icon(): IconDescriptor { return { variant: "avatar", initials: this.initials, color: this.avatarColor, }; } }