@notionhq/custom-blocks 0.0.58

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 (298) hide show
  1. package/HOST.md +171 -0
  2. package/README.md +57 -0
  3. package/bin/cli/attach.js +180 -0
  4. package/bin/cli/cli.js +248 -0
  5. package/bin/cli/create.js +106 -0
  6. package/bin/cli/datasources.js +255 -0
  7. package/bin/cli/deploy.js +109 -0
  8. package/bin/cli/ids.js +13 -0
  9. package/bin/cli/ntn.js +95 -0
  10. package/bin/cli/pullData.js +76 -0
  11. package/bin/cli/pullManifest.js +158 -0
  12. package/bin/cli/target.js +95 -0
  13. package/bin/src/bridge/dataSources/propertySchema.js +148 -0
  14. package/bin/src/bridge/manifest.js +40 -0
  15. package/dist/autoResize.d.ts +4 -0
  16. package/dist/autoResize.d.ts.map +1 -0
  17. package/dist/autoResize.js +71 -0
  18. package/dist/bridge/SandboxBridge.d.ts +92 -0
  19. package/dist/bridge/SandboxBridge.d.ts.map +1 -0
  20. package/dist/bridge/SandboxBridge.js +718 -0
  21. package/dist/bridge/dataSources/dataSource.d.ts +732 -0
  22. package/dist/bridge/dataSources/dataSource.d.ts.map +1 -0
  23. package/dist/bridge/dataSources/dataSource.js +37 -0
  24. package/dist/bridge/dataSources/dataSourcePage.d.ts +118 -0
  25. package/dist/bridge/dataSources/dataSourcePage.d.ts.map +1 -0
  26. package/dist/bridge/dataSources/dataSourcePage.js +14 -0
  27. package/dist/bridge/dataSources/dataSourceValue.d.ts +67 -0
  28. package/dist/bridge/dataSources/dataSourceValue.d.ts.map +1 -0
  29. package/dist/bridge/dataSources/dataSourceValue.js +14 -0
  30. package/dist/bridge/dataSources/dateValue.d.ts +158 -0
  31. package/dist/bridge/dataSources/dateValue.d.ts.map +1 -0
  32. package/dist/bridge/dataSources/dateValue.js +59 -0
  33. package/dist/bridge/dataSources/errors.d.ts +6 -0
  34. package/dist/bridge/dataSources/errors.d.ts.map +1 -0
  35. package/dist/bridge/dataSources/errors.js +4 -0
  36. package/dist/bridge/dataSources/propertySchema.d.ts +191 -0
  37. package/dist/bridge/dataSources/propertySchema.d.ts.map +1 -0
  38. package/dist/bridge/dataSources/propertySchema.js +148 -0
  39. package/dist/bridge/dataSources/recordPointer.d.ts +10 -0
  40. package/dist/bridge/dataSources/recordPointer.d.ts.map +1 -0
  41. package/dist/bridge/dataSources/recordPointer.js +8 -0
  42. package/dist/bridge/dataSources/resolve.d.ts +22 -0
  43. package/dist/bridge/dataSources/resolve.d.ts.map +1 -0
  44. package/dist/bridge/dataSources/resolve.js +65 -0
  45. package/dist/bridge/dataSources/resolveProperty.d.ts +41 -0
  46. package/dist/bridge/dataSources/resolveProperty.d.ts.map +1 -0
  47. package/dist/bridge/dataSources/resolveProperty.js +73 -0
  48. package/dist/bridge/errors.d.ts +12 -0
  49. package/dist/bridge/errors.d.ts.map +1 -0
  50. package/dist/bridge/errors.js +6 -0
  51. package/dist/bridge/hostState.d.ts +65 -0
  52. package/dist/bridge/hostState.d.ts.map +1 -0
  53. package/dist/bridge/hostState.js +65 -0
  54. package/dist/bridge/ids.d.ts +39 -0
  55. package/dist/bridge/ids.d.ts.map +1 -0
  56. package/dist/bridge/ids.js +5 -0
  57. package/dist/bridge/incomingType.d.ts +10 -0
  58. package/dist/bridge/incomingType.d.ts.map +1 -0
  59. package/dist/bridge/incomingType.js +17 -0
  60. package/dist/bridge/loadManifest.d.ts +25 -0
  61. package/dist/bridge/loadManifest.d.ts.map +1 -0
  62. package/dist/bridge/loadManifest.js +68 -0
  63. package/dist/bridge/manifest.d.ts +66 -0
  64. package/dist/bridge/manifest.d.ts.map +1 -0
  65. package/dist/bridge/manifest.js +40 -0
  66. package/dist/bridge/messages/createPage.d.ts +225 -0
  67. package/dist/bridge/messages/createPage.d.ts.map +1 -0
  68. package/dist/bridge/messages/createPage.js +46 -0
  69. package/dist/bridge/messages/createPageResult.d.ts +211 -0
  70. package/dist/bridge/messages/createPageResult.d.ts.map +1 -0
  71. package/dist/bridge/messages/createPageResult.js +28 -0
  72. package/dist/bridge/messages/currentUserChanged.d.ts +19 -0
  73. package/dist/bridge/messages/currentUserChanged.d.ts.map +1 -0
  74. package/dist/bridge/messages/currentUserChanged.js +9 -0
  75. package/dist/bridge/messages/dataSourcesChanged.d.ts +158 -0
  76. package/dist/bridge/messages/dataSourcesChanged.d.ts.map +1 -0
  77. package/dist/bridge/messages/dataSourcesChanged.js +13 -0
  78. package/dist/bridge/messages/getPage.d.ts +216 -0
  79. package/dist/bridge/messages/getPage.d.ts.map +1 -0
  80. package/dist/bridge/messages/getPage.js +33 -0
  81. package/dist/bridge/messages/getUser.d.ts +45 -0
  82. package/dist/bridge/messages/getUser.d.ts.map +1 -0
  83. package/dist/bridge/messages/getUser.js +32 -0
  84. package/dist/bridge/messages/hostToSandbox.d.ts +1089 -0
  85. package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -0
  86. package/dist/bridge/messages/hostToSandbox.js +32 -0
  87. package/dist/bridge/messages/init.d.ts +209 -0
  88. package/dist/bridge/messages/init.d.ts.map +1 -0
  89. package/dist/bridge/messages/init.js +47 -0
  90. package/dist/bridge/messages/invalidHostMessage.d.ts +15 -0
  91. package/dist/bridge/messages/invalidHostMessage.d.ts.map +1 -0
  92. package/dist/bridge/messages/invalidHostMessage.js +13 -0
  93. package/dist/bridge/messages/invalidSandboxMessage.d.ts +15 -0
  94. package/dist/bridge/messages/invalidSandboxMessage.d.ts.map +1 -0
  95. package/dist/bridge/messages/invalidSandboxMessage.js +13 -0
  96. package/dist/bridge/messages/listUsers.d.ts +53 -0
  97. package/dist/bridge/messages/listUsers.d.ts.map +1 -0
  98. package/dist/bridge/messages/listUsers.js +33 -0
  99. package/dist/bridge/messages/pageChanged.d.ts +12 -0
  100. package/dist/bridge/messages/pageChanged.d.ts.map +1 -0
  101. package/dist/bridge/messages/pageChanged.js +9 -0
  102. package/dist/bridge/messages/parentChanged.d.ts +22 -0
  103. package/dist/bridge/messages/parentChanged.d.ts.map +1 -0
  104. package/dist/bridge/messages/parentChanged.js +9 -0
  105. package/dist/bridge/messages/queryDataSource.d.ts +20 -0
  106. package/dist/bridge/messages/queryDataSource.d.ts.map +1 -0
  107. package/dist/bridge/messages/queryDataSource.js +19 -0
  108. package/dist/bridge/messages/queryDataSourceResult.d.ts +90 -0
  109. package/dist/bridge/messages/queryDataSourceResult.d.ts.map +1 -0
  110. package/dist/bridge/messages/queryDataSourceResult.js +21 -0
  111. package/dist/bridge/messages/ready.d.ts +45 -0
  112. package/dist/bridge/messages/ready.d.ts.map +1 -0
  113. package/dist/bridge/messages/ready.js +37 -0
  114. package/dist/bridge/messages/resize.d.ts +12 -0
  115. package/dist/bridge/messages/resize.d.ts.map +1 -0
  116. package/dist/bridge/messages/resize.js +10 -0
  117. package/dist/bridge/messages/sandboxToHost.d.ts +410 -0
  118. package/dist/bridge/messages/sandboxToHost.d.ts.map +1 -0
  119. package/dist/bridge/messages/sandboxToHost.js +25 -0
  120. package/dist/bridge/messages/themeChanged.d.ts +11 -0
  121. package/dist/bridge/messages/themeChanged.d.ts.map +1 -0
  122. package/dist/bridge/messages/themeChanged.js +10 -0
  123. package/dist/bridge/messages/updatePage.d.ts +171 -0
  124. package/dist/bridge/messages/updatePage.d.ts.map +1 -0
  125. package/dist/bridge/messages/updatePage.js +15 -0
  126. package/dist/bridge/messages/updatePageResult.d.ts +210 -0
  127. package/dist/bridge/messages/updatePageResult.d.ts.map +1 -0
  128. package/dist/bridge/messages/updatePageResult.js +27 -0
  129. package/dist/bridge/pages/page.d.ts +600 -0
  130. package/dist/bridge/pages/page.d.ts.map +1 -0
  131. package/dist/bridge/pages/page.js +217 -0
  132. package/dist/bridge/parent.d.ts +25 -0
  133. package/dist/bridge/parent.d.ts.map +1 -0
  134. package/dist/bridge/parent.js +11 -0
  135. package/dist/bridge/pendingRequests.d.ts +14 -0
  136. package/dist/bridge/pendingRequests.d.ts.map +1 -0
  137. package/dist/bridge/pendingRequests.js +27 -0
  138. package/dist/bridge/sandboxClient.d.ts +63 -0
  139. package/dist/bridge/sandboxClient.d.ts.map +1 -0
  140. package/dist/bridge/sandboxClient.js +92 -0
  141. package/dist/bridge/theme.d.ts +4 -0
  142. package/dist/bridge/theme.d.ts.map +1 -0
  143. package/dist/bridge/theme.js +2 -0
  144. package/dist/bridge/users/user.d.ts +36 -0
  145. package/dist/bridge/users/user.d.ts.map +1 -0
  146. package/dist/bridge/users/user.js +19 -0
  147. package/dist/customBlock.d.ts +36 -0
  148. package/dist/customBlock.d.ts.map +1 -0
  149. package/dist/customBlock.js +65 -0
  150. package/dist/host/createCustomBlockHost.d.ts +34 -0
  151. package/dist/host/createCustomBlockHost.d.ts.map +1 -0
  152. package/dist/host/createCustomBlockHost.js +278 -0
  153. package/dist/host/lifecycle/initErrors.d.ts +10 -0
  154. package/dist/host/lifecycle/initErrors.d.ts.map +1 -0
  155. package/dist/host/lifecycle/initErrors.js +123 -0
  156. package/dist/host/lifecycle/ready.d.ts +8 -0
  157. package/dist/host/lifecycle/ready.d.ts.map +1 -0
  158. package/dist/host/lifecycle/ready.js +24 -0
  159. package/dist/host/lifecycle/types.d.ts +24 -0
  160. package/dist/host/lifecycle/types.d.ts.map +1 -0
  161. package/dist/host/lifecycle/types.js +1 -0
  162. package/dist/host/messages/invalidSandboxMessage.d.ts +7 -0
  163. package/dist/host/messages/invalidSandboxMessage.d.ts.map +1 -0
  164. package/dist/host/messages/invalidSandboxMessage.js +24 -0
  165. package/dist/host/messages/types.d.ts +60 -0
  166. package/dist/host/messages/types.d.ts.map +1 -0
  167. package/dist/host/messages/types.js +1 -0
  168. package/dist/host/queries/querySubscriptions.d.ts +20 -0
  169. package/dist/host/queries/querySubscriptions.d.ts.map +1 -0
  170. package/dist/host/queries/querySubscriptions.js +29 -0
  171. package/dist/host/queries/types.d.ts +9 -0
  172. package/dist/host/queries/types.d.ts.map +1 -0
  173. package/dist/host/queries/types.js +1 -0
  174. package/dist/host.d.ts +73 -0
  175. package/dist/host.d.ts.map +1 -0
  176. package/dist/host.js +42 -0
  177. package/dist/index.d.ts +37 -0
  178. package/dist/index.d.ts.map +1 -0
  179. package/dist/index.js +14 -0
  180. package/dist/init.d.ts +53 -0
  181. package/dist/init.d.ts.map +1 -0
  182. package/dist/init.js +87 -0
  183. package/dist/react/DebugMessageLog.d.ts +2 -0
  184. package/dist/react/DebugMessageLog.d.ts.map +1 -0
  185. package/dist/react/DebugMessageLog.js +22 -0
  186. package/dist/react/NotionCustomBlock.css +110 -0
  187. package/dist/react/NotionCustomBlock.d.ts +50 -0
  188. package/dist/react/NotionCustomBlock.d.ts.map +1 -0
  189. package/dist/react/NotionCustomBlock.js +81 -0
  190. package/dist/react/index.d.ts +14 -0
  191. package/dist/react/index.d.ts.map +1 -0
  192. package/dist/react/index.js +13 -0
  193. package/dist/react/standalonePreview.d.ts +2 -0
  194. package/dist/react/standalonePreview.d.ts.map +1 -0
  195. package/dist/react/standalonePreview.js +26 -0
  196. package/dist/react/useCustomBlockAutoResize.d.ts +30 -0
  197. package/dist/react/useCustomBlockAutoResize.d.ts.map +1 -0
  198. package/dist/react/useCustomBlockAutoResize.js +35 -0
  199. package/dist/react/useCustomBlockInit.d.ts +43 -0
  200. package/dist/react/useCustomBlockInit.d.ts.map +1 -0
  201. package/dist/react/useCustomBlockInit.js +60 -0
  202. package/dist/react/useDataSource.d.ts +13 -0
  203. package/dist/react/useDataSource.d.ts.map +1 -0
  204. package/dist/react/useDataSource.js +37 -0
  205. package/dist/react/useHostState.d.ts +2 -0
  206. package/dist/react/useHostState.d.ts.map +1 -0
  207. package/dist/react/useHostState.js +5 -0
  208. package/dist/react/useRuntimeState.d.ts +66 -0
  209. package/dist/react/useRuntimeState.d.ts.map +1 -0
  210. package/dist/react/useRuntimeState.js +73 -0
  211. package/dist/types.d.ts +154 -0
  212. package/dist/types.d.ts.map +1 -0
  213. package/dist/types.js +1 -0
  214. package/dist/utils.d.ts +9 -0
  215. package/dist/utils.d.ts.map +1 -0
  216. package/dist/utils.js +10 -0
  217. package/dist/version.d.ts +9 -0
  218. package/dist/version.d.ts.map +1 -0
  219. package/dist/version.js +7 -0
  220. package/docs/block-location.md +83 -0
  221. package/docs/data-sources.md +186 -0
  222. package/docs/lifecycle.md +172 -0
  223. package/docs/manifest.md +42 -0
  224. package/docs/pages.md +143 -0
  225. package/docs/users.md +92 -0
  226. package/package.json +69 -0
  227. package/src/autoResize.ts +84 -0
  228. package/src/bridge/SandboxBridge.ts +921 -0
  229. package/src/bridge/dataSources/dataSource.ts +63 -0
  230. package/src/bridge/dataSources/dataSourcePage.ts +71 -0
  231. package/src/bridge/dataSources/dataSourceValue.ts +19 -0
  232. package/src/bridge/dataSources/dateValue.ts +96 -0
  233. package/src/bridge/dataSources/errors.ts +14 -0
  234. package/src/bridge/dataSources/propertySchema.ts +186 -0
  235. package/src/bridge/dataSources/recordPointer.ts +13 -0
  236. package/src/bridge/dataSources/resolve.ts +99 -0
  237. package/src/bridge/dataSources/resolveProperty.ts +130 -0
  238. package/src/bridge/errors.ts +13 -0
  239. package/src/bridge/hostState.ts +154 -0
  240. package/src/bridge/ids.ts +58 -0
  241. package/src/bridge/incomingType.ts +19 -0
  242. package/src/bridge/loadManifest.ts +89 -0
  243. package/src/bridge/manifest.ts +53 -0
  244. package/src/bridge/messages/createPage.ts +67 -0
  245. package/src/bridge/messages/createPageResult.ts +52 -0
  246. package/src/bridge/messages/currentUserChanged.ts +14 -0
  247. package/src/bridge/messages/dataSourcesChanged.ts +18 -0
  248. package/src/bridge/messages/getPage.ts +52 -0
  249. package/src/bridge/messages/getUser.ts +48 -0
  250. package/src/bridge/messages/hostToSandbox.ts +37 -0
  251. package/src/bridge/messages/init.ts +81 -0
  252. package/src/bridge/messages/invalidHostMessage.ts +16 -0
  253. package/src/bridge/messages/invalidSandboxMessage.ts +18 -0
  254. package/src/bridge/messages/listUsers.ts +49 -0
  255. package/src/bridge/messages/pageChanged.ts +12 -0
  256. package/src/bridge/messages/parentChanged.ts +14 -0
  257. package/src/bridge/messages/queryDataSource.ts +24 -0
  258. package/src/bridge/messages/queryDataSourceResult.ts +38 -0
  259. package/src/bridge/messages/ready.ts +41 -0
  260. package/src/bridge/messages/resize.ts +13 -0
  261. package/src/bridge/messages/sandboxToHost.ts +30 -0
  262. package/src/bridge/messages/themeChanged.ts +15 -0
  263. package/src/bridge/messages/updatePage.ts +22 -0
  264. package/src/bridge/messages/updatePageResult.ts +49 -0
  265. package/src/bridge/pages/page.ts +281 -0
  266. package/src/bridge/parent.ts +27 -0
  267. package/src/bridge/pendingRequests.ts +28 -0
  268. package/src/bridge/sandboxClient.ts +137 -0
  269. package/src/bridge/theme.ts +5 -0
  270. package/src/bridge/users/user.ts +31 -0
  271. package/src/css.d.ts +1 -0
  272. package/src/customBlock.ts +102 -0
  273. package/src/host/createCustomBlockHost.ts +392 -0
  274. package/src/host/lifecycle/initErrors.ts +132 -0
  275. package/src/host/lifecycle/ready.ts +36 -0
  276. package/src/host/lifecycle/types.ts +28 -0
  277. package/src/host/messages/invalidSandboxMessage.ts +38 -0
  278. package/src/host/messages/types.ts +67 -0
  279. package/src/host/queries/querySubscriptions.ts +52 -0
  280. package/src/host/queries/types.ts +16 -0
  281. package/src/host.ts +167 -0
  282. package/src/index.ts +115 -0
  283. package/src/init.ts +143 -0
  284. package/src/react/DebugMessageLog.tsx +30 -0
  285. package/src/react/NotionCustomBlock.css +110 -0
  286. package/src/react/NotionCustomBlock.tsx +151 -0
  287. package/src/react/index.ts +28 -0
  288. package/src/react/standalonePreview.ts +28 -0
  289. package/src/react/useCustomBlockAutoResize.ts +46 -0
  290. package/src/react/useCustomBlockInit.ts +91 -0
  291. package/src/react/useDataSource.ts +47 -0
  292. package/src/react/useHostState.ts +9 -0
  293. package/src/react/useRuntimeState.ts +85 -0
  294. package/src/types.ts +175 -0
  295. package/src/utils.ts +13 -0
  296. package/src/version.ts +8 -0
  297. package/vite-plugin/index.d.ts +46 -0
  298. package/vite-plugin/index.js +115 -0
@@ -0,0 +1,42 @@
1
+ # Manifest
2
+
3
+ A custom view declares its required data sources in `custom_blocks.json` at the project root. Notion uses the manifest to know what semantic keys the block expects, what shape each property should be, and what to show when an admin is configuring the block.
4
+
5
+ ```json
6
+ {
7
+ "version": 1,
8
+ "dataSources": {
9
+ "tasks": {
10
+ "name": "Tasks",
11
+ "description": "The collection of tasks to render",
12
+ "properties": {
13
+ "title": { "name": "Title", "type": "title" },
14
+ "dueDate": { "name": "Due date", "type": "date" }
15
+ }
16
+ }
17
+ }
18
+ }
19
+ ```
20
+
21
+ `initCustomBlock()` fetches `custom_blocks.json` and forwards it with `ready`. The `notionCustomBlock()` Vite plugin from `@notionhq/custom-blocks/vite` serves it in dev and emits it into `dist/` on build. If the file is missing, the SDK sends `ready` with `status: "success"` and `manifest: null`, which means the block has no declared data requirements. If the file is unavailable for another reason or invalid, the SDK sends `ready` with `status: "error"` and an `error` payload, and hosts should reject init by echoing the sandbox-reported error code back.
22
+
23
+ ## Vite plugin
24
+
25
+ ```ts
26
+ import { defineConfig } from "vite";
27
+ import react from "@vitejs/plugin-react";
28
+ import { notionCustomBlock } from "@notionhq/custom-blocks/vite";
29
+
30
+ export default defineConfig({
31
+ plugins: [react(), notionCustomBlock()],
32
+ });
33
+ ```
34
+
35
+ In dev, the plugin serves `custom_blocks.json` from the project root so HMR + the SDK handshake see the same file. On `vite build`, it emits `custom_blocks.json` into `dist/` as a separate asset alongside the bundled HTML and JS.
36
+
37
+ ## Types
38
+
39
+ - `CustomBlockManifest` — the parsed shape of `custom_blocks.json`.
40
+ - `ManifestDataSource` — a single entry in `dataSources` (name, description, properties).
41
+ - `ManifestProperty` — a single property declaration inside a `ManifestDataSource`.
42
+ - `ManifestIcon` — the icon variant accepted on a `ManifestDataSource`.
package/docs/pages.md ADDED
@@ -0,0 +1,143 @@
1
+ # `pages` API
2
+
3
+ Helpers for creating, reading, updating, and archiving Notion pages from inside a custom block. The SDK forwards each call to Notion on your behalf.
4
+
5
+ ```ts
6
+ import { pages } from "@notionhq/custom-blocks";
7
+ ```
8
+
9
+ Every helper returns a discriminated result instead of throwing:
10
+
11
+ ```ts
12
+ const result = await pages.get(pageId);
13
+ if (result.status === "success") {
14
+ // result.page is a NotionPage
15
+ } else {
16
+ // result.error is a human-readable string
17
+ }
18
+ ```
19
+
20
+ Always check `result.status` before reading `result.page`.
21
+
22
+ ## Creating pages
23
+
24
+ `pages.create` mirrors Notion's [`POST /v1/pages`](https://developers.notion.com/reference/post-page). Pass a parent, a property map, and (optionally) an `icon`, `cover`, or `position`:
25
+
26
+ ```ts
27
+ const result = await pages.create({
28
+ parent: { type: "data_source_key", key: "tasks" },
29
+ properties: {
30
+ title: {
31
+ type: "title",
32
+ title: [{ type: "text", text: { content: "New task" } }],
33
+ },
34
+ dueDate: { type: "date", date: { start: "2026-06-01" } },
35
+ },
36
+ icon: { type: "emoji", emoji: "📝" },
37
+ position: { type: "end" },
38
+ });
39
+
40
+ if (result.status === "success") {
41
+ console.log("created", result.page.id);
42
+ }
43
+ ```
44
+
45
+ ### Choosing a parent
46
+
47
+ `parent` is a `CreatePageParent`:
48
+
49
+ ```ts
50
+ type CreatePageParent =
51
+ | { type: "page_id"; page_id: NotionPageId }
52
+ | { type: "data_source_id"; data_source_id: NotionDataSourceId }
53
+ | { type: "data_source_key"; key: string };
54
+ ```
55
+
56
+ `type: "data_source_key"` is the recommended form inside a custom view. Pass the semantic key you declared in `custom_blocks.json` (e.g. `"tasks"`) and the SDK looks up the corresponding data source for you. The other two variants exist for the rarer case where you already have a raw Notion ID in hand.
57
+
58
+ ### Property keys
59
+
60
+ `properties` is a `NotionPagePropertyInputMap`. Two niceties versus the raw API when the create parent resolves to a configured data source:
61
+
62
+ - **Keys** can be either raw Notion property IDs _or_ the data-source property keys you declared in the manifest. The SDK resolves keys → IDs before forwarding the request. Semantic keys work for `parent.type: "data_source_key"` and for `parent.type: "data_source_id"` when that ID matches a data source delivered by `init` / `dataSourcesChanged`; use raw property IDs for `page_id` parents or unmapped data sources.
63
+ - **Values** (`NotionPagePropertyInputValue`) may omit `id` — the SDK fills in the final raw ID for you.
64
+
65
+ So if your manifest declares `title` and `dueDate`, you can write them by name (as in the example above) instead of looking up the raw IDs.
66
+
67
+ ### Where the new page lands
68
+
69
+ `position` is a `NotionCreatePagePosition` and controls placement inside the parent:
70
+
71
+ - `{ type: "start" }` / `{ type: "end" }` — prepend or append (default).
72
+ - `{ type: "before", blockId }` / `{ type: "after", blockId }` — insert as a sibling of the given block (which can be nested anywhere under the parent).
73
+
74
+ ## Reading pages
75
+
76
+ `pages.get(pageId)` fetches a single page by ID:
77
+
78
+ ```ts
79
+ const result = await pages.get(pageId);
80
+ if (result.status === "error") return;
81
+
82
+ const page = result.page; // NotionPage
83
+ console.log(page.properties);
84
+ ```
85
+
86
+ `page` mirrors Notion's public API shape, with `id`, `parent`, `properties`, optional `icon` / `cover`, etc. — see `NotionPage` in the types list below.
87
+
88
+ ## Updating pages
89
+
90
+ `pages.update` writes back to a page. The optional fields (`properties`, `icon`, `cover`, `archived`) are independent — supply only what you want to change:
91
+
92
+ ```ts
93
+ const result = await pages.update({
94
+ pageId,
95
+ properties: {
96
+ "%5C%3FX%3D": {
97
+ id: "%5C%3FX%3D",
98
+ type: "checkbox",
99
+ checkbox: true,
100
+ },
101
+ },
102
+ icon: { type: "emoji", emoji: "✅" },
103
+ });
104
+ ```
105
+
106
+ The `properties` map (a `NotionPagePropertyWriteMap`) is keyed by **raw Notion property ID**, and each value must repeat that ID as its own `id` field — semantic data-source keys aren't accepted here. To update a row by configured custom-block key without writing out the raw IDs, use the `update` helper on the row returned from `useDataSource` instead; the SDK handles the key → ID resolution for you.
107
+
108
+ If you call `pages.update` with no fields to change, it short-circuits and resolves with `{ status: "error", error: { code: "invalid_page_update", message: "updatePage requires at least one of: properties, icon, cover, archived.", isRetryable: false } }` — no request is sent.
109
+
110
+ ## Deleting (archiving) pages
111
+
112
+ `pages.delete(pageId)` is a thin wrapper around `pages.update({ pageId, archived: true })`. Notion treats archive and trash the same way for pages:
113
+
114
+ ```ts
115
+ await pages.delete(pageId);
116
+ ```
117
+
118
+ To restore a page, call `pages.update({ pageId, archived: false })`.
119
+
120
+ ## Icons, covers, and file uploads
121
+
122
+ File-upload references aren't enabled for custom blocks yet. For icons, covers, and file properties, use one of:
123
+
124
+ - An emoji icon — `{ type: "emoji", emoji: "🟢" }`
125
+ - An external URL — `{ type: "external", external: { url: "https://example.com/cover.png" } }`
126
+ - An existing hosted file URL returned by Notion — `{ type: "file", file: { url: existingUrl } }`
127
+
128
+ Do **not** send `{ type: "file_upload", file_upload: { id } }`; the host will reject it.
129
+
130
+ ## Types
131
+
132
+ - `NotionPage` — the page record returned by every successful call.
133
+ - `NotionPageId` — branded string ID for a page.
134
+ - `NotionPageIcon` / `NotionPageCover` — icon and cover variants Notion supports.
135
+ - `NotionParent` — a block's parent reference (`page_id` / `block_id` / `data_source_id` / `workspace`), as returned on `NotionPage.parent` and by `useParent()`.
136
+ - `NotionPagePropertyValue` — a single property value as returned on a `NotionPage`.
137
+ - `NotionPagePropertyInputValue` — a single property value as accepted by `pages.create` / `pages.update` (may omit `id` for `create`).
138
+ - `NotionPagePropertyInputMap` — input map for `pages.create` (keys can be raw property IDs, or semantic keys when creating into a mapped data source).
139
+ - `NotionPagePropertyWriteMap` — input map for `pages.update` (raw property IDs only).
140
+ - `NotionCreatePagePosition` — `start` / `end` / `before` / `after` insertion variants.
141
+ - `CreatePageInput` / `CreatePageParent` / `CreatePageResult`.
142
+ - `GetPageResult`.
143
+ - `UpdatePageInput` / `UpdatePageResult`.
package/docs/users.md ADDED
@@ -0,0 +1,92 @@
1
+ # `users` API
2
+
3
+ Helpers for reading workspace users from inside a custom block. The SDK forwards each call to Notion on your behalf.
4
+
5
+ ```ts
6
+ import {
7
+ customBlock,
8
+ initCustomBlock,
9
+ users,
10
+ type NotionUserId,
11
+ } from "@notionhq/custom-blocks";
12
+ import { useCurrentUser } from "@notionhq/custom-blocks/react";
13
+ ```
14
+
15
+ Every helper returns a discriminated result instead of throwing:
16
+
17
+ ```ts
18
+ const result = await users.get(userId);
19
+ if (result.status === "success") {
20
+ // result.user is a NotionUser
21
+ } else {
22
+ // result.error is a human-readable string
23
+ }
24
+ ```
25
+
26
+ Always check `result.status` before reading `result.user` / `result.list`.
27
+
28
+ ## Reading the current user
29
+
30
+ `useCurrentUser()` returns the viewing user's `NotionUser` from the initial host payload, so your first render can personalize or filter without a separate `users.get` request.
31
+
32
+ ```ts
33
+ const me = useCurrentUser();
34
+ // me.id, me.name, me.person.email
35
+ ```
36
+
37
+ The hook updates when the host sends `currentUserChanged`, so renders stay in sync if the viewer's profile changes.
38
+
39
+ For non-React renderers, read the same state through `customBlock` after initialization:
40
+
41
+ ```ts
42
+ await initCustomBlock()
43
+ const me = customBlock.getCurrentUser()
44
+
45
+ const unsubscribe = customBlock.subscribe(() => {
46
+ const nextMe = customBlock.getCurrentUser()
47
+ // Update your renderer with nextMe.
48
+ })
49
+ ```
50
+
51
+ ## Listing users
52
+
53
+ `users.list(input?)` returns workspace users visible to the current custom block, mirroring Notion's [`GET /v1/users`](https://developers.notion.com/reference/get-users) shape.
54
+
55
+ ```ts
56
+ const result = await users.list({ pageSize: 50 });
57
+ if (result.status === "error") return;
58
+
59
+ for (const user of result.list.results) {
60
+ console.log(user.id, user.name, user.person.email);
61
+ }
62
+
63
+ if (result.list.has_more && result.list.next_cursor) {
64
+ const next = await users.list({ startCursor: result.list.next_cursor });
65
+ // ...
66
+ }
67
+ ```
68
+
69
+ `ListUsersInput` accepts `pageSize` and `startCursor`; both are optional. `ListUsersResult` resolves to either `{ status: "success", list }` or `{ status: "error", error }`, where `list` is a `NotionUserList` (with `results`, `next_cursor`, `has_more`).
70
+
71
+ ## Reading a single user
72
+
73
+ `users.get(userId)` fetches one `NotionUser` by `NotionUserId`:
74
+
75
+ ```ts
76
+ const result = await users.get(userId);
77
+ if (result.status === "success") {
78
+ console.log(result.user.name);
79
+ }
80
+ ```
81
+
82
+ `GetUserResult` follows the same success/error shape and returns `{ status: "success", user }` when the host resolves the user.
83
+
84
+ ## Types
85
+
86
+ - `NotionUser` — the user record returned by `users.get` and inside `NotionUserList.results`.
87
+ - `NotionUserId` — branded string ID for a user.
88
+ - `NotionUserList` — paginated list shape returned by `users.list`.
89
+ - `useCurrentUser()` — hook that returns the viewer's `NotionUser`.
90
+ - `customBlock.getCurrentUser()` — framework-neutral getter for the viewer's `NotionUser`.
91
+ - `ListUsersInput` / `ListUsersResult`.
92
+ - `GetUserResult`.
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@notionhq/custom-blocks",
3
+ "version": "0.0.58",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/makenotion/custom-blocks",
12
+ "directory": "sdk"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ },
21
+ "./react": {
22
+ "import": "./dist/react/index.js",
23
+ "types": "./dist/react/index.d.ts"
24
+ },
25
+ "./host": {
26
+ "import": "./dist/host.js",
27
+ "types": "./dist/host.d.ts"
28
+ },
29
+ "./vite": {
30
+ "import": "./vite-plugin/index.js",
31
+ "types": "./vite-plugin/index.d.ts"
32
+ }
33
+ },
34
+ "bin": {
35
+ "ncblock": "./bin/cli/cli.js"
36
+ },
37
+ "scripts": {
38
+ "test": "vitest run --environment jsdom",
39
+ "typecheck": "tsc --project tsconfig.json"
40
+ },
41
+ "files": [
42
+ "src",
43
+ "bin",
44
+ "HOST.md",
45
+ "docs",
46
+ "vite-plugin",
47
+ "dist"
48
+ ],
49
+ "peerDependencies": {
50
+ "react": "^19.2.5"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "react": {
54
+ "optional": true
55
+ }
56
+ },
57
+ "devDependencies": {
58
+ "@testing-library/react": "^16.3.2",
59
+ "@types/react": "^19.2.14",
60
+ "@types/react-dom": "^19.2.3",
61
+ "jsdom": "^29.1.0",
62
+ "react": "^19.2.5",
63
+ "react-dom": "^19.2.5",
64
+ "vitest": "^4.1.5"
65
+ },
66
+ "dependencies": {
67
+ "valibot": "^1.3.1"
68
+ }
69
+ }
@@ -0,0 +1,84 @@
1
+ import { customBlockHost } from "./bridge/sandboxClient.js"
2
+
3
+ /** Limits host resize messages to 10 per second while preserving the latest height. */
4
+ const AUTO_RESIZE_THROTTLE_MS = 100
5
+
6
+ export function autoResize(args: {
7
+ target: HTMLElement | null | undefined
8
+ }): () => void {
9
+ const { target } = args
10
+ if (target === null || target === undefined) {
11
+ return () => {}
12
+ }
13
+
14
+ // Use a leading/trailing throttle: send the first changed height immediately, then retain only
15
+ // the latest height observed and send it when the throttling period ends.
16
+ let lastHeightReportedToHost = -1
17
+ let pendingHeight: number | undefined
18
+ let throttleTimeout: ReturnType<typeof setTimeout> | undefined
19
+
20
+ /** Sends a height immediately and records it as the deduplication baseline. */
21
+ const sendHeightToHost = (height: number) => {
22
+ lastHeightReportedToHost = height
23
+ customBlockHost.postResize(height)
24
+ }
25
+
26
+ /** Sends the latest height queued during the throttling period, if one exists. */
27
+ const flushPendingHeight = () => {
28
+ if (throttleTimeout !== undefined) {
29
+ clearTimeout(throttleTimeout)
30
+ throttleTimeout = undefined
31
+ }
32
+ if (pendingHeight === undefined) {
33
+ return
34
+ }
35
+ const height = pendingHeight
36
+ pendingHeight = undefined
37
+ sendHeightToHost(height)
38
+ throttleTimeout = setTimeout(flushPendingHeight, AUTO_RESIZE_THROTTLE_MS)
39
+ }
40
+
41
+ /** Measures the target and either sends, queues, or deduplicates its height. */
42
+ const measureAndScheduleResize = () => {
43
+ const next = Math.ceil(target.getBoundingClientRect().height)
44
+ if (next === lastHeightReportedToHost) {
45
+ // The height has not changed since the last measurement. Do nothing.
46
+ pendingHeight = undefined
47
+ return
48
+ }
49
+ if (throttleTimeout !== undefined) {
50
+ // The height has changed since the last measurement, but the throttling period has not
51
+ // ended. Queue the new height for later.
52
+ pendingHeight = next
53
+ return
54
+ }
55
+
56
+ // The height has changed since the last measurement and the throttling period has ended.
57
+ // Send the new height immediately and start a new throttling period.
58
+ sendHeightToHost(next)
59
+ throttleTimeout = setTimeout(flushPendingHeight, AUTO_RESIZE_THROTTLE_MS)
60
+ }
61
+
62
+ // Measure the initial height and schedule the first throttling period.
63
+ measureAndScheduleResize()
64
+
65
+ // If the ResizeObserver API is not available, return a function that cleans up the throttling
66
+ // period started by the initial measurement.
67
+ if (typeof ResizeObserver === "undefined") {
68
+ return () => {
69
+ clearTimeout(throttleTimeout)
70
+ throttleTimeout = undefined
71
+ }
72
+ }
73
+
74
+ // Observe the target and schedule subsequent measurements and throttling periods.
75
+ const observer = new ResizeObserver(measureAndScheduleResize)
76
+ observer.observe(target)
77
+
78
+ // Clean up the observer and the throttling period.
79
+ return () => {
80
+ observer.disconnect()
81
+ clearTimeout(throttleTimeout)
82
+ throttleTimeout = undefined
83
+ }
84
+ }