import { autoResize } from "./autoResize.js" import type { NotionDataSource } from "./bridge/dataSources/dataSource.js" import type { CustomBlockHostState, InitializedHostState, } from "./bridge/hostState.js" import type { NotionBlockId } from "./bridge/ids.js" import type { CustomBlockManifest } from "./bridge/manifest.js" import type { CustomBlockPage } from "./bridge/pages/page.js" import type { NotionParent } from "./bridge/parent.js" import { customBlockHost } from "./bridge/sandboxClient.js" import type { NotionTheme } from "./bridge/theme.js" import type { NotionUser } from "./bridge/users/user.js" export type CustomBlockState = | { status: "uninitialized"; theme: NotionTheme } | { status: "initialized" theme: NotionTheme blockId: NotionBlockId parent: NotionParent page: CustomBlockPage currentUser: NotionUser dataSources: NotionDataSource[] } /** * Framework-neutral runtime state APIs for a custom block. Call `initCustomBlock` * before reading initialized values, and use `subscribe` to react to host pushes. */ export const customBlock = { subscribe(listener: () => void): () => void { return customBlockHost.subscribe(listener) }, getState(): CustomBlockState { return toPublicState(customBlockHost.getState()) }, getCurrentUser(): NotionUser { return getInitializedHostState("getCurrentUser").currentUser }, getTheme(): NotionTheme { return getInitializedHostState("getTheme").theme }, getBlockId(): NotionBlockId { return getInitializedHostState("getBlockId").blockId }, getParent(): NotionParent { return getInitializedHostState("getParent").parent }, getPage(): CustomBlockPage { return getInitializedHostState("getPage").page }, getManifest(): CustomBlockManifest | null { return customBlockHost.getManifest() }, autoResize, } let lastHostState: CustomBlockHostState | undefined let lastPublicState: CustomBlockState | undefined function toPublicState(hostState: CustomBlockHostState): CustomBlockState { if (hostState === lastHostState && lastPublicState !== undefined) { return lastPublicState } lastHostState = hostState if (hostState.status === "uninitialized") { lastPublicState = { status: "uninitialized", theme: hostState.theme, } return lastPublicState } lastPublicState = { status: "initialized", theme: hostState.theme, blockId: hostState.blockId, parent: hostState.parent, page: hostState.page, currentUser: hostState.currentUser, dataSources: hostState.dataSources, } return lastPublicState } function getInitializedHostState(methodName: string): InitializedHostState { const hostState = customBlockHost.getState() if (hostState.status !== "initialized") { throw new Error( `customBlock.${methodName} called before \`initCustomBlock\` resolved. Await it before reading runtime state.`, ) } return hostState }