import type { NotionDataSource } from "./dataSources/dataSource.js" import type { NotionDataSourcePage, NotionDataSourcePageBridge, NotionDataSourcePageUpdateInput, NotionDataSourcePageUpdateResult, } from "./dataSources/dataSourcePage.js" import type { NotionDataSourceValue } from "./dataSources/dataSourceValue.js" import type { NotionPropertySchema } from "./dataSources/propertySchema.js" import type { NotionBlockId } from "./ids.js" import type { CustomBlockQueryDataSourceErrorInfo } from "./messages/queryDataSourceResult.js" import type { CustomBlockPage, NotionPageId } from "./pages/page.js" import type { NotionParent } from "./parent.js" import type { NotionTheme } from "./theme.js" import type { NotionUser } from "./users/user.js" export type CustomBlockHostState = UninitializedHostState | InitializedHostState export type UninitializedHostState = { status: "uninitialized" theme: NotionTheme } export type InitializedHostState = { status: "initialized" theme: NotionTheme blockId: NotionBlockId parent: NotionParent page: CustomBlockPage currentUser: NotionUser dataSources: NotionDataSource[] dataSourceState: Record } export type DataSourceQueryState = { /** Latest pages from the host as parsed from the bridge. `propertiesByKey` is derived lazily. */ items: NotionDataSourcePageBridge[] isLoading: boolean hasMore: boolean error?: CustomBlockQueryDataSourceErrorInfo latestRequestId?: string latestSnapshotId?: string latestLimit?: number } export function createEmptyDataSourceQueryState(): DataSourceQueryState { return { items: [], isLoading: false, hasMore: false, } } /** * Resolved page + schema views for a single data source, keyed by raw property * ID and by user-defined key. Re-derived from `propertyIdsByKey` on every read so * renames don't require a re-query. */ export type DataSourceQueryView = { items: NotionDataSourcePage[] collectionSchema?: NotionDataSource["collectionSchema"] propertySchemasById: { [propertyId: string]: NotionPropertySchema } propertySchemasByKey: { [key: string]: NotionPropertySchema | undefined } isLoading: boolean hasMore: boolean error?: CustomBlockQueryDataSourceErrorInfo } const EMPTY_QUERY_VIEW: DataSourceQueryView = { items: [], propertySchemasById: {}, propertySchemasByKey: {}, isLoading: false, hasMore: false, } /** * Per-row callback that resolves property keys against the data source and forwards the * resulting write to the bridge. Injected by callers (typically the SDK singleton in `init.ts`) * so this module stays free of bridge-instance dependencies. */ export type UpdateDataSourcePageFn = (args: { dataSource: NotionDataSource pageId: NotionPageId input: NotionDataSourcePageUpdateInput }) => Promise export function getDataSourceQueryView( hostState: CustomBlockHostState, key: string, updateDataSourcePage: UpdateDataSourcePageFn, ): DataSourceQueryView { if (hostState.status !== "initialized") { return EMPTY_QUERY_VIEW } const dataSource = hostState.dataSources.find(entry => entry.key === key) const queryState = hostState.dataSourceState[key] ?? createEmptyDataSourceQueryState() if (dataSource === undefined) { return { items: [], collectionSchema: undefined, propertySchemasById: {}, propertySchemasByKey: {}, isLoading: queryState.isLoading, hasMore: queryState.hasMore, error: queryState.error, } } const propertyIdsByKey = dataSource.propertyIdsByKey const propertySchemasById = dataSource.propertySchemasById const resolvedItems: NotionDataSourcePage[] = queryState.items.map(entry => { const propertiesByKey: { [key: string]: NotionDataSourceValue | undefined } = {} for (const [key, propertyId] of Object.entries(propertyIdsByKey)) { propertiesByKey[key] = propertyId === undefined ? undefined : entry.propertiesById[propertyId] } return { id: entry.id, propertiesById: entry.propertiesById, propertiesByKey, update: input => updateDataSourcePage({ dataSource, pageId: entry.id, input, }), } }) const propertySchemasByKey: { [key: string]: NotionPropertySchema | undefined } = {} for (const [key, propertyId] of Object.entries(propertyIdsByKey)) { propertySchemasByKey[key] = propertyId === undefined ? undefined : propertySchemasById[propertyId] } return { items: resolvedItems, collectionSchema: dataSource.collectionSchema, propertySchemasById, propertySchemasByKey, isLoading: queryState.isLoading, hasMore: queryState.hasMore, error: queryState.error, } }