import * as v from "valibot" import { type CustomBlockManifest, manifestSchema } from "./manifest.js" const MANIFEST_URL = "custom_blocks.json" // The schema accepts any string code. The type lists known codes for // autocomplete, with an open string fallback for newer senders. export const customBlockReadyErrorCodeSchema = v.string() export type CustomBlockReadyErrorCode = | "manifest_unavailable" | "manifest_invalid" | (string & {}) export const customBlockReadyErrorSchema = v.object({ code: customBlockReadyErrorCodeSchema, message: v.string(), }) export type CustomBlockReadyError = v.InferOutput< typeof customBlockReadyErrorSchema > export type ManifestLoadResult = | { manifest: CustomBlockManifest | null error?: undefined } | { manifest: null error: CustomBlockReadyError } /** * Attempts to load a `custom_blocks.json` manifest co-located with the bundle. * A missing manifest means the block has no declared data requirements. * Other failures return a structured error so the host can reject the manifest. * The SDK validates the manifest locally for author feedback; the host still * validates the ready message as the iframe trust boundary. */ export async function loadManifest(): Promise { if (typeof fetch !== "function") { const message = `No fetch API available; cannot load ${MANIFEST_URL}.` console.warn(`[notion-custom-sdk] ${message}`) return { manifest: null, error: { code: "manifest_unavailable", message }, } } let response: Response try { response = await fetch(MANIFEST_URL, { credentials: "omit" }) } catch (error) { const message = `Could not fetch ${MANIFEST_URL}.` console.warn(`[notion-custom-sdk] ${message}`, error) return { manifest: null, error: { code: "manifest_unavailable", message }, } } if (response.status === 404) { const message = `No manifest found at ${MANIFEST_URL} (status ${response.status}).` console.warn(`[notion-custom-sdk] ${message}`) return { manifest: null } } if (!response.ok) { const message = `Could not fetch ${MANIFEST_URL} (status ${response.status}).` console.warn(`[notion-custom-sdk] ${message}`) return { manifest: null, error: { code: "manifest_unavailable", message }, } } let json: unknown try { json = await response.json() } catch (error) { const message = `Manifest at ${MANIFEST_URL} was not valid JSON.` console.warn(`[notion-custom-sdk] ${message}`, error) return { manifest: null, error: { code: "manifest_invalid", message } } } const parsed = v.safeParse(manifestSchema, json) if (!parsed.success) { const message = `Manifest at ${MANIFEST_URL} did not match schema.` console.warn(`[notion-custom-sdk] ${message}`, parsed.issues) return { manifest: null, error: { code: "manifest_invalid", message } } } return { manifest: parsed.output } }