ncblock 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +286 -0
  2. package/dist/bridge/context.d.ts +44 -0
  3. package/dist/bridge/context.d.ts.map +1 -0
  4. package/dist/bridge/context.js +42 -0
  5. package/dist/bridge/dataSources/dataSource.d.ts +732 -0
  6. package/dist/bridge/dataSources/dataSource.d.ts.map +1 -0
  7. package/dist/bridge/dataSources/dataSource.js +37 -0
  8. package/dist/bridge/dataSources/dataSourcePage.d.ts +117 -0
  9. package/dist/bridge/dataSources/dataSourcePage.d.ts.map +1 -0
  10. package/dist/bridge/dataSources/dataSourcePage.js +13 -0
  11. package/dist/bridge/dataSources/dataSourceValue.d.ts +67 -0
  12. package/dist/bridge/dataSources/dataSourceValue.d.ts.map +1 -0
  13. package/dist/bridge/dataSources/dataSourceValue.js +14 -0
  14. package/dist/bridge/dataSources/dateValue.d.ts +158 -0
  15. package/dist/bridge/dataSources/dateValue.d.ts.map +1 -0
  16. package/dist/bridge/dataSources/dateValue.js +59 -0
  17. package/dist/bridge/dataSources/propertySchema.d.ts +191 -0
  18. package/dist/bridge/dataSources/propertySchema.d.ts.map +1 -0
  19. package/dist/bridge/dataSources/propertySchema.js +148 -0
  20. package/dist/bridge/dataSources/recordPointer.d.ts +10 -0
  21. package/dist/bridge/dataSources/recordPointer.d.ts.map +1 -0
  22. package/dist/bridge/dataSources/recordPointer.js +8 -0
  23. package/dist/bridge/ids.d.ts +21 -0
  24. package/dist/bridge/ids.d.ts.map +1 -0
  25. package/dist/bridge/ids.js +3 -0
  26. package/dist/bridge/incomingType.d.ts +10 -0
  27. package/dist/bridge/incomingType.d.ts.map +1 -0
  28. package/dist/bridge/incomingType.js +17 -0
  29. package/dist/bridge/manifest.d.ts +66 -0
  30. package/dist/bridge/manifest.d.ts.map +1 -0
  31. package/dist/bridge/manifest.js +40 -0
  32. package/dist/bridge/messages/contextChanged.d.ts +20 -0
  33. package/dist/bridge/messages/contextChanged.d.ts.map +1 -0
  34. package/dist/bridge/messages/contextChanged.js +10 -0
  35. package/dist/bridge/messages/createPage.d.ts +233 -0
  36. package/dist/bridge/messages/createPage.d.ts.map +1 -0
  37. package/dist/bridge/messages/createPage.js +45 -0
  38. package/dist/bridge/messages/createPageResult.d.ts +198 -0
  39. package/dist/bridge/messages/createPageResult.d.ts.map +1 -0
  40. package/dist/bridge/messages/createPageResult.js +20 -0
  41. package/dist/bridge/messages/dataSourcesChanged.d.ts +158 -0
  42. package/dist/bridge/messages/dataSourcesChanged.d.ts.map +1 -0
  43. package/dist/bridge/messages/dataSourcesChanged.js +13 -0
  44. package/dist/bridge/messages/getPage.d.ts +203 -0
  45. package/dist/bridge/messages/getPage.d.ts.map +1 -0
  46. package/dist/bridge/messages/getPage.js +24 -0
  47. package/dist/bridge/messages/hostToSandbox.d.ts +974 -0
  48. package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -0
  49. package/dist/bridge/messages/hostToSandbox.js +24 -0
  50. package/dist/bridge/messages/init.d.ts +169 -0
  51. package/dist/bridge/messages/init.d.ts.map +1 -0
  52. package/dist/bridge/messages/init.js +17 -0
  53. package/dist/bridge/messages/invalidHostMessage.d.ts +15 -0
  54. package/dist/bridge/messages/invalidHostMessage.d.ts.map +1 -0
  55. package/dist/bridge/messages/invalidHostMessage.js +13 -0
  56. package/dist/bridge/messages/invalidSandboxMessage.d.ts +15 -0
  57. package/dist/bridge/messages/invalidSandboxMessage.d.ts.map +1 -0
  58. package/dist/bridge/messages/invalidSandboxMessage.js +13 -0
  59. package/dist/bridge/messages/queryDataSource.d.ts +13 -0
  60. package/dist/bridge/messages/queryDataSource.d.ts.map +1 -0
  61. package/dist/bridge/messages/queryDataSource.js +11 -0
  62. package/dist/bridge/messages/queryDataSourceResult.d.ts +77 -0
  63. package/dist/bridge/messages/queryDataSourceResult.d.ts.map +1 -0
  64. package/dist/bridge/messages/queryDataSourceResult.js +13 -0
  65. package/dist/bridge/messages/ready.d.ts +41 -0
  66. package/dist/bridge/messages/ready.d.ts.map +1 -0
  67. package/dist/bridge/messages/ready.js +22 -0
  68. package/dist/bridge/messages/resize.d.ts +12 -0
  69. package/dist/bridge/messages/resize.d.ts.map +1 -0
  70. package/dist/bridge/messages/resize.js +10 -0
  71. package/dist/bridge/messages/sandboxToHost.d.ts +389 -0
  72. package/dist/bridge/messages/sandboxToHost.d.ts.map +1 -0
  73. package/dist/bridge/messages/sandboxToHost.js +21 -0
  74. package/dist/bridge/messages/themeChanged.d.ts +11 -0
  75. package/dist/bridge/messages/themeChanged.d.ts.map +1 -0
  76. package/dist/bridge/messages/themeChanged.js +10 -0
  77. package/dist/bridge/messages/updatePage.d.ts +171 -0
  78. package/dist/bridge/messages/updatePage.d.ts.map +1 -0
  79. package/dist/bridge/messages/updatePage.js +14 -0
  80. package/dist/bridge/messages/updatePageResult.d.ts +197 -0
  81. package/dist/bridge/messages/updatePageResult.d.ts.map +1 -0
  82. package/dist/bridge/messages/updatePageResult.js +19 -0
  83. package/dist/bridge/pages/page.d.ts +651 -0
  84. package/dist/bridge/pages/page.d.ts.map +1 -0
  85. package/dist/bridge/pages/page.js +229 -0
  86. package/dist/bridge/pendingRequests.d.ts +14 -0
  87. package/dist/bridge/pendingRequests.d.ts.map +1 -0
  88. package/dist/bridge/pendingRequests.js +27 -0
  89. package/dist/bridge/theme.d.ts +4 -0
  90. package/dist/bridge/theme.d.ts.map +1 -0
  91. package/dist/bridge/theme.js +2 -0
  92. package/dist/host.d.ts +52 -0
  93. package/dist/host.d.ts.map +1 -0
  94. package/dist/host.js +32 -0
  95. package/dist/index.d.ts +27 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +14 -0
  98. package/dist/notion.d.ts +113 -0
  99. package/dist/notion.d.ts.map +1 -0
  100. package/dist/notion.js +773 -0
  101. package/dist/pages.d.ts +23 -0
  102. package/dist/pages.d.ts.map +1 -0
  103. package/dist/pages.js +30 -0
  104. package/dist/react.d.ts +171 -0
  105. package/dist/react.d.ts.map +1 -0
  106. package/dist/react.js +284 -0
  107. package/dist/types.d.ts +124 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +1 -0
  110. package/dist/utils.d.ts +9 -0
  111. package/dist/utils.d.ts.map +1 -0
  112. package/dist/utils.js +10 -0
  113. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,286 @@
1
+ # ncblock
2
+
3
+ > Internal alias for the Notion Custom Block SDK. Published under this name to keep the package off general discovery surfaces.
4
+
5
+ React SDK for building [Notion custom view](https://app.dev.notion.com/p/notion/Custom-Blocks-Sandbox-Capabilities-APIs-33eb35e6e67f80e387e3e74499ba0d42) blocks.
6
+
7
+ A custom view runs as a sandboxed `<iframe>` inside a Notion block on iOS, Android, and desktop. The only channel between your view and Notion is a `postMessage` bridge — this SDK wraps it in a small set of typed React hooks.
8
+
9
+ > **Pre-release.** Breaking changes may land at any time before 1.0.
10
+
11
+ ## Quick start
12
+
13
+ ```tsx
14
+ // src/index.tsx
15
+ import { NotionCustomBlock } from "ncblock";
16
+ import ReactDOM from "react-dom/client";
17
+ import { App } from "./App";
18
+
19
+ ReactDOM.createRoot(document.getElementById("root")!).render(
20
+ <NotionCustomBlock>
21
+ <App />
22
+ </NotionCustomBlock>,
23
+ );
24
+ ```
25
+
26
+ ```tsx
27
+ // src/App.tsx
28
+ import { useCustomBlockContext, useTheme } from "ncblock";
29
+
30
+ export function App() {
31
+ const context = useCustomBlockContext();
32
+ const theme = useTheme();
33
+ return <div data-theme={theme}>Hello from {context.customBlockId}.</div>;
34
+ }
35
+ ```
36
+
37
+ `<NotionCustomBlock>` runs the SDK ↔ host handshake (sends `ready` with the manifest, awaits `init`) and only mounts `children` once it resolves. Inside the wrapper, every hook returns non-nullable values — there's no separate gating component to write. It also runs `useCustomBlockAutoResize` for you by default; pass `autoResize={false}` to opt out.
38
+
39
+ ## Concepts
40
+
41
+ ### Bridge & lifecycle
42
+
43
+ `initCustomBlock()` posts `ready` to `window.parent` and awaits the host's `init` (theme, context, and `dataSources: { bindings }` keyed by semantic data-source key, which the SDK resolves against the manifest). The promise resolves with the normalized initial state — `await` it before mounting React so hooks always see populated state.
44
+
45
+ - Default `timeoutMs` is 2000; rejects with `TimeoutError` if the host doesn't respond.
46
+ - In a top-level browser tab (no parent frame), rejects with `NotInIframeError`. `<NotionCustomBlock>` catches this, seeds placeholders, and renders `children` behind a warning banner so dev-time previews still work.
47
+ - After init, `themeChanged`, `contextChanged`, and `dataSourcesChanged` push updates and the relevant hooks re-render.
48
+ - `initCustomBlock` is idempotent; subsequent calls return the same promise.
49
+
50
+ ### Sizing
51
+
52
+ The host owns width and height. Inside the iframe, `100vh` ≠ a screen and there's no meaningful "device width" — only iframe width. Layouts must reflow from a phone column to a desktop block.
53
+
54
+ - **Self-sizing content** is the default — `<NotionCustomBlock>` measures `#root` and posts `resize` messages so the iframe tracks your content. Pass `autoResize={false}` for full-bleed views, or to drive `useCustomBlockAutoResize` yourself.
55
+ - Prefer container queries (`@container`) over viewport queries.
56
+
57
+ ### Data sources
58
+
59
+ A custom block is wired to one or more "data sources" — semantic keys (e.g. `people`, `default`) that map to Notion collections. Read through `useDataSource(key)` and key off the semantic name; never reach into `collectionPointer` / `propertyIdsByKey` directly.
60
+
61
+ Each row is a `NotionDataSourcePage` of the form `{ id, propertiesById, propertiesByKey, update }`. Read via `propertiesByKey[key]` (semantic) or `propertiesById[propertyId]` (raw). Call `update(input)` to write back through the same data-source mapping; `NotionDataSourcePageUpdateInput` and `NotionDataSourcePageUpdateResult` describe that helper. The four built-ins (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`) are always present in `propertiesById` and `collectionSchema.propertiesById`.
62
+
63
+ ### Manifest
64
+
65
+ A custom view declares its required data sources in `custom_blocks.json` at the project root:
66
+
67
+ ```json
68
+ {
69
+ "version": 1,
70
+ "dataSources": {
71
+ "tasks": {
72
+ "name": "Tasks",
73
+ "description": "The collection of tasks to render",
74
+ "properties": {
75
+ "title": { "name": "Title", "type": "title" },
76
+ "dueDate": { "name": "Due date", "type": "date" }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ `initCustomBlock()` fetches `custom_blocks.json` and forwards it with `ready`. The `notionCustomBlock()` Vite plugin from `ncblock/vite` serves it in dev and emits it into `dist/` on build. If the file is missing or invalid, the SDK sends `manifest: null`.
84
+
85
+ ### Forbidden APIs
86
+
87
+ No top-level navigation, `window.open`, or auth redirects. Cross-origin work goes through the host (and is exposed via SDK hooks).
88
+
89
+ ## Hook reference
90
+
91
+ All hooks assume `initCustomBlock()` has resolved — they throw if called before that. Inside `<NotionCustomBlock>` (or past the `isLoaded` gate of `useCustomBlockInit`), single-value hooks return non-nullable values.
92
+
93
+ ### `<NotionCustomBlock>`
94
+
95
+ ```ts
96
+ type NotionCustomBlockProps = InitCustomBlockOptions & {
97
+ children: ReactNode;
98
+ fallback?: ReactNode;
99
+ errorFallback?: ReactNode | ((error: Error) => ReactNode);
100
+ autoResize?: boolean; // defaults to true
101
+ };
102
+ ```
103
+
104
+ Top-level wrapper. Runs the handshake, gates `children`, and (by default) drives auto-resize. `fallback` replaces the loading view (default `null`); `errorFallback` replaces the inline `<p role="alert">` shown if init rejects. `timeoutMs` flows through to `initCustomBlock`. Pass `autoResize={false}` for full-bleed views or to call `useCustomBlockAutoResize` yourself.
105
+
106
+ ### `useCustomBlockInit(opts?)`
107
+
108
+ ```ts
109
+ function useCustomBlockInit(opts?: InitCustomBlockOptions): UseCustomBlockInitResult;
110
+
111
+ type UseCustomBlockInitResult =
112
+ | { isLoaded: false; error: undefined }
113
+ | { isLoaded: false; error: Error }
114
+ | { isLoaded: true; error: undefined; initial: CustomBlockInitial };
115
+ ```
116
+
117
+ React wrapper around `initCustomBlock` for templates that prefer not to use top-level `await`. Multiple components calling it share the same handshake.
118
+
119
+ ```tsx
120
+ function Root() {
121
+ const init = useCustomBlockInit();
122
+ if (init.error) return <p role="alert">Init failed: {init.error.message}</p>;
123
+ if (!init.isLoaded) return null;
124
+ return <App />;
125
+ }
126
+ ```
127
+
128
+ ### `useCustomBlockContext()`
129
+
130
+ ```ts
131
+ function useCustomBlockContext(): NotionCustomBlockContext;
132
+ ```
133
+
134
+ Returns `{ customBlockId, parent: { id, type }, page: { id, type } }`. Re-renders on `contextChanged` (e.g. the block moves containers).
135
+
136
+ ### `useTheme()`
137
+
138
+ ```ts
139
+ function useTheme(): NotionTheme; // "light" | "dark"
140
+ ```
141
+
142
+ Re-renders on every `themeChanged` message.
143
+
144
+ ### `useDataSourceDefinitions()`
145
+
146
+ ```ts
147
+ function useDataSourceDefinitions(): NotionDataSource[];
148
+ ```
149
+
150
+ Resolved data-source definitions (semantic key plus `collectionPointer`, `collectionSchema`, `propertyIdsByKey`, derived `propertySchemasById`). Most templates use `useDataSource` instead — reach for this hook only when rendering the configuration itself (debug panels, schema-driven UIs).
151
+
152
+ ### `useDataSource(key, initialLimit?)`
153
+
154
+ ```ts
155
+ function useDataSource(key: string, initialLimit?: number): UseDataSourceResult;
156
+
157
+ type UseDataSourceResult = {
158
+ items: NotionDataSourcePage[];
159
+ collectionSchema?: NotionCollectionSchema;
160
+ propertySchemasById: { [propertyId: string]: NotionPropertySchema };
161
+ propertySchemasByKey: { [key: string]: NotionPropertySchema | undefined };
162
+ isLoading: boolean;
163
+ hasMore: boolean;
164
+ fetchMore: () => void;
165
+ error?: string;
166
+ };
167
+ ```
168
+
169
+ Reads the data source mapped to `key`. `initialLimit` defaults to 20. `fetchMore()` re-requests a larger prefix (no cursors yet); page growth tracks `initialLimit`, so pass a larger value to opt into bigger batches. `propertySchemasByKey` is `undefined` for declared-but-unbound slots. The hook resets to `initialLimit` when the underlying definition changes.
170
+
171
+ ### `useCustomBlockAutoResize({ enabled? })`
172
+
173
+ ```ts
174
+ function useCustomBlockAutoResize(args?: { enabled?: boolean }): void;
175
+ ```
176
+
177
+ Measures `#root` with `Math.ceil(scrollHeight)` and posts `resize` messages, deduping unchanged values. `<NotionCustomBlock>` runs this for you — only call it directly when you want to drive `enabled` yourself (e.g. a debug toggle), and pair with `autoResize={false}` so it doesn't run twice.
178
+
179
+ ```tsx
180
+ <NotionCustomBlock autoResize={false}>
181
+ <App />
182
+ </NotionCustomBlock>;
183
+
184
+ function App() {
185
+ const [enabled, setEnabled] = useState(true);
186
+ useCustomBlockAutoResize({ enabled });
187
+ return <div>…</div>;
188
+ }
189
+ ```
190
+
191
+ ## Example: querying a data source
192
+
193
+ A typical data-driven view picks a key, calls `useDataSource`, schema-checks the rows, and surfaces a setup hint when the mapped collection is missing the expected fields. Trimmed from `templates/radar-chart`:
194
+
195
+ ```tsx
196
+ import {
197
+ type NotionDataSourcePage,
198
+ useDataSource,
199
+ } from "ncblock";
200
+
201
+ const KEY = "people";
202
+
203
+ function isComplete(item: NotionDataSourcePage): boolean {
204
+ return (
205
+ typeof item.propertiesByKey.name === "string" &&
206
+ typeof item.propertiesByKey.score === "number" &&
207
+ Number.isFinite(item.propertiesByKey.score)
208
+ );
209
+ }
210
+
211
+ export function ScoreList() {
212
+ const { items, isLoading, hasMore, fetchMore, error } = useDataSource(KEY);
213
+
214
+ if (error) return <div role="alert">Couldn't load: {error}</div>;
215
+ if (isLoading && items.length === 0) return <div>Loading…</div>;
216
+
217
+ const ready = items.filter(isComplete);
218
+ if (ready.length === 0) {
219
+ return (
220
+ <div>
221
+ Map a data source with key <code>{KEY}</code> exposing{" "}
222
+ <code>name</code> (text) and <code>score</code> (number).
223
+ </div>
224
+ );
225
+ }
226
+
227
+ return (
228
+ <div>
229
+ <ul>
230
+ {ready.map((item) => (
231
+ <li key={item.id}>
232
+ {String(item.propertiesByKey.name)} —{" "}
233
+ {Number(item.propertiesByKey.score)}
234
+ </li>
235
+ ))}
236
+ </ul>
237
+ {hasMore ? (
238
+ <button type="button" onClick={fetchMore} disabled={isLoading}>
239
+ {isLoading ? "Loading…" : "Load more"}
240
+ </button>
241
+ ) : null}
242
+ </div>
243
+ );
244
+ }
245
+ ```
246
+
247
+ ## `pages` API
248
+
249
+ ```ts
250
+ import { pages } from "ncblock";
251
+
252
+ await pages.create({ parent, properties, icon?, cover?, position? });
253
+ await pages.get(pageId);
254
+ await pages.update({ pageId, properties?, icon?, cover?, archived? });
255
+ await pages.delete(pageId); // soft-delete (archive); thin wrapper around update
256
+ ```
257
+
258
+ Mirrors the public Notion API. Each call resolves to either `{ status: "success", page }` or `{ status: "error", error }`.
259
+
260
+ For `pages.create`, `parent` accepts:
261
+
262
+ ```ts
263
+ type CreatePageParent =
264
+ | { type: "page_id"; page_id: NotionPageId }
265
+ | { type: "data_source_id"; data_source_id: NotionDataSourceId }
266
+ | { type: "data_source_key"; key: string };
267
+ ```
268
+
269
+ `type: "data_source_key"` is the recommended form inside a custom view — pass the semantic key (e.g. `"default"`) and the SDK resolves it before sending the request. Page write inputs use `NotionPagePropertyInputMap`: keys may be raw property IDs or data-source property keys, and each `NotionPagePropertyInputValue` may omit `id` because the SDK fills the final raw ID before sending a bridge message.
270
+
271
+ File upload references aren't enabled for custom blocks yet. For page icons, covers, and file properties, use `external.url` or an existing `file.url`; do not send `{ type: "file_upload", file_upload: { id } }`.
272
+
273
+ ## Types reference
274
+
275
+ Re-exported from `ncblock`. Hover docs in your editor cover the per-field detail.
276
+
277
+ - **Init / lifecycle:** `CustomBlockInitial`, `InitCustomBlockOptions`, `UseCustomBlockInitResult`, `NotionCustomBlockProps`.
278
+ - **Context & theme:** `NotionTheme`, `NotionCustomBlockContext`.
279
+ - **Data sources:** `NotionDataSource`, `NotionDataSourcePage`, `NotionDataSourcePageUpdateInput`, `NotionDataSourcePageUpdateResult`, `NotionDataSourceValue`, `NotionCollectionSchema`, `NotionPropertySchema`, `NotionPropertyOption`, `NotionPropertyColor`, `NotionStatusGroup`, `NotionDualProperty`, `UseDataSourceResult`.
280
+ - **Property types:** `NotionPropertyType` / `NOTION_PROPERTY_TYPES` (string-literal union + runtime list), `NotionBuiltinPropertyId` / `NOTION_BUILTIN_PROPERTY_IDS` (the four synthetic IDs).
281
+ - **Manifest:** `CustomBlockManifest`, `ManifestDataSource`, `ManifestProperty`, `ManifestIcon`.
282
+ - **Pages API:** `NotionPage`, `NotionPageCover`, `NotionPageIcon`, `NotionPageParent`, `NotionPagePropertyValue`, `NotionPagePropertyInputValue`, `NotionPagePropertyInputMap`, `NotionPagePropertyWriteMap`, `NotionCreatePagePosition`, `CreatePageInput`, `CreatePageParent`, `CreatePageResult`, `GetPageResult`, `UpdatePageInput`, `UpdatePageResult`.
283
+ - **IDs & pointers:** `NotionRecordPointer`, `NotionPageId`, `NotionDataSourceId`, `NotionSpaceId` (branded strings).
284
+ - **Date/reminder values:** `NotionDate`, `NotionDateRange`, `NotionDateTime`, `NotionDateTimeRange`, `NotionDateValue`, `NotionDateReminder`, `NotionDateTimeReminder`, `NotionTimeReminder`, `NotionNoReminder`.
285
+
286
+ The bridge speaks a versioned `postMessage` protocol (`CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION`, currently `1`). You shouldn't need to read protocol-level details to build a view — see `CLAUDE.md` if you're extending the SDK itself.
@@ -0,0 +1,44 @@
1
+ import * as v from "valibot";
2
+ import type { NotionPageId } from "./pages/page";
3
+ /**
4
+ * Context about the custom block and its location in the block tree.
5
+ * Delivered as part of the `init` message and then re-sent via `contextChanged`
6
+ * whenever the host detects a change (e.g. the block moves into a different
7
+ * container or its enclosing page changes).
8
+ */
9
+ export declare const notionCustomBlockContextSchema: v.ObjectSchema<{
10
+ /**
11
+ * ID of the custom block itself, the one hosting this sandboxed iframe.
12
+ */
13
+ readonly customBlockId: v.StringSchema<undefined>;
14
+ /**
15
+ * The block that directly parents this custom block.
16
+ */
17
+ readonly parent: v.ObjectSchema<{
18
+ /**
19
+ * The ID of the block that directly parents this custom block.
20
+ */
21
+ readonly id: v.StringSchema<undefined>;
22
+ /**
23
+ * The block type of the block that directly parents this custom block. This could be many
24
+ * different types, including: page, toggle, column, and callout.
25
+ */
26
+ readonly type: v.StringSchema<undefined>;
27
+ }, undefined>;
28
+ /**
29
+ * The nearest page ancestor to this custom block.
30
+ */
31
+ readonly page: v.ObjectSchema<{
32
+ /**
33
+ * The ID of the nearest page ancestor to this custom block.
34
+ */
35
+ readonly id: v.StringSchema<undefined>;
36
+ }, undefined>;
37
+ }, undefined>;
38
+ export type NotionCustomBlockContext = Omit<v.InferOutput<typeof notionCustomBlockContextSchema>, "page"> & {
39
+ page: {
40
+ id: NotionPageId;
41
+ };
42
+ };
43
+ export declare function parseNotionCustomBlockContext(value: unknown): NotionCustomBlockContext | undefined;
44
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../bridge/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B;IAC1C;;OAEG;;IAGH;;OAEG;;QAEF;;WAEG;;QAEH;;;WAGG;;;IAIJ;;OAEG;;QAEF;;WAEG;;;aAGH,CAAA;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAC1C,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,EACpD,MAAM,CACN,GAAG;IACH,IAAI,EAAE;QACL,EAAE,EAAE,YAAY,CAAA;KAChB,CAAA;CACD,CAAA;AAED,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,OAAO,GACZ,wBAAwB,GAAG,SAAS,CAKtC"}
@@ -0,0 +1,42 @@
1
+ import * as v from "valibot";
2
+ /**
3
+ * Context about the custom block and its location in the block tree.
4
+ * Delivered as part of the `init` message and then re-sent via `contextChanged`
5
+ * whenever the host detects a change (e.g. the block moves into a different
6
+ * container or its enclosing page changes).
7
+ */
8
+ export const notionCustomBlockContextSchema = v.object({
9
+ /**
10
+ * ID of the custom block itself, the one hosting this sandboxed iframe.
11
+ */
12
+ customBlockId: v.string(),
13
+ /**
14
+ * The block that directly parents this custom block.
15
+ */
16
+ parent: v.object({
17
+ /**
18
+ * The ID of the block that directly parents this custom block.
19
+ */
20
+ id: v.string(),
21
+ /**
22
+ * The block type of the block that directly parents this custom block. This could be many
23
+ * different types, including: page, toggle, column, and callout.
24
+ */
25
+ type: v.string(),
26
+ }),
27
+ /**
28
+ * The nearest page ancestor to this custom block.
29
+ */
30
+ page: v.object({
31
+ /**
32
+ * The ID of the nearest page ancestor to this custom block.
33
+ */
34
+ id: v.string(),
35
+ }),
36
+ });
37
+ export function parseNotionCustomBlockContext(value) {
38
+ const parsed = v.safeParse(notionCustomBlockContextSchema, value);
39
+ return parsed.success
40
+ ? parsed.output
41
+ : undefined;
42
+ }