@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,63 @@
1
+ import * as v from "valibot"
2
+ import { notionDataSourceIdSchema, notionSpaceIdSchema } from "../ids.js"
3
+ import { notionPropertySchemaSchema } from "./propertySchema.js"
4
+
5
+ const collectionPointerValidator = v.object({
6
+ id: notionDataSourceIdSchema,
7
+ table: v.string(),
8
+ spaceId: v.optional(notionSpaceIdSchema),
9
+ })
10
+
11
+ export type NotionCollectionPointer = v.InferOutput<
12
+ typeof collectionPointerValidator
13
+ >
14
+
15
+ export const notionCollectionSchemaValidator = v.object({
16
+ id: v.optional(notionDataSourceIdSchema),
17
+ propertiesById: v.record(v.string(), notionPropertySchemaSchema),
18
+ })
19
+
20
+ export type NotionCollectionSchema = v.InferOutput<
21
+ typeof notionCollectionSchemaValidator
22
+ >
23
+
24
+ /**
25
+ * Bridge shape for a single data source: a semantic key bound (optionally) to a collection,
26
+ * its property name → ID mapping, and its column schemas.
27
+ */
28
+ export const notionDataSourceSchema = v.object({
29
+ key: v.string(),
30
+ collectionPointer: v.optional(collectionPointerValidator),
31
+ collectionSchema: v.optional(notionCollectionSchemaValidator),
32
+ /**
33
+ * Keyed mapping of user-defined keys to a raw property ID. A key mapped to `undefined`
34
+ * is a declared-but-unbound slot.
35
+ */
36
+ propertyIdsByKey: v.record(v.string(), v.optional(v.string())),
37
+ /**
38
+ * Keyed mapping of raw property IDs to their schema. Always includes the four built-ins
39
+ * (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`).
40
+ */
41
+ propertySchemasById: v.record(v.string(), notionPropertySchemaSchema),
42
+ })
43
+
44
+ export type NotionDataSource = v.InferOutput<typeof notionDataSourceSchema>
45
+
46
+ export const notionDataSourceBindingSchema = v.object({
47
+ collectionPointer: v.optional(collectionPointerValidator),
48
+ collectionSchema: v.optional(notionCollectionSchemaValidator),
49
+ propertyIdsByKey: v.optional(v.record(v.string(), v.optional(v.string()))),
50
+ })
51
+
52
+ export type NotionDataSourceBinding = v.InferOutput<
53
+ typeof notionDataSourceBindingSchema
54
+ >
55
+
56
+ export const notionDataSourceBindingsSchema = v.record(
57
+ v.string(),
58
+ notionDataSourceBindingSchema,
59
+ )
60
+
61
+ export type NotionDataSourceBindings = v.InferOutput<
62
+ typeof notionDataSourceBindingsSchema
63
+ >
@@ -0,0 +1,71 @@
1
+ import * as v from "valibot"
2
+ import { notionPageIdSchema } from "../ids.js"
3
+ import type { CustomBlockUpdatePageErrorInfo } from "../messages/updatePageResult.js"
4
+ import type {
5
+ NotionPage,
6
+ NotionPageCover,
7
+ NotionPageIcon,
8
+ NotionPageId,
9
+ NotionPagePropertyInputMap,
10
+ } from "../pages/page.js"
11
+ import {
12
+ type NotionDataSourceValue,
13
+ notionDataSourceValueSchema,
14
+ } from "./dataSourceValue.js"
15
+
16
+ /**
17
+ * Bridge shape for a data source page, as parsed from inbound host messages. The host keys
18
+ * properties by raw property ID. The four built-ins (`created_time`, `last_edited_time`,
19
+ * `created_by`, `last_edited_by`) are normally present, possibly with `undefined` values.
20
+ *
21
+ * Internal to the SDK. The consumer-facing shape is {@link NotionDataSourcePage}.
22
+ */
23
+ export const notionDataSourcePageBridgeSchema = v.object({
24
+ id: notionPageIdSchema,
25
+ propertiesById: v.record(v.string(), v.optional(notionDataSourceValueSchema)),
26
+ })
27
+
28
+ /** Internal SDK type for a parsed bridge page. */
29
+ export type NotionDataSourcePageBridge = v.InferOutput<
30
+ typeof notionDataSourcePageBridgeSchema
31
+ >
32
+
33
+ export type NotionDataSourcePageUpdateInput = {
34
+ properties?: NotionPagePropertyInputMap
35
+ icon?: NotionPageIcon
36
+ cover?: NotionPageCover
37
+ archived?: boolean
38
+ }
39
+
40
+ export type NotionDataSourcePageUpdateResult =
41
+ | {
42
+ status: "success"
43
+ page: NotionPage
44
+ }
45
+ | { status: "error"; error: CustomBlockUpdatePageErrorInfo }
46
+
47
+ /**
48
+ * Consumer-facing page shape returned from {@link useDataSource}. Derived from the bridge payload
49
+ * plus the data source's `propertyIdsByKey`.
50
+ */
51
+ export type NotionDataSourcePage = {
52
+ id: NotionPageId
53
+ /**
54
+ * Keyed mapping of raw property IDs to their value. Includes all properties on the data source,
55
+ * including the four built-ins (`created_time`, `last_edited_time`, `created_by`,
56
+ * `last_edited_by`).
57
+ */
58
+ propertiesById: { [propertyId: string]: NotionDataSourceValue | undefined }
59
+ /**
60
+ * Keyed mapping of user-defined keys to their value. Only includes properties that are mapped
61
+ * to a raw property ID in the data source's `propertyIdsByKey`.
62
+ */
63
+ propertiesByKey: { [key: string]: NotionDataSourceValue | undefined }
64
+ /**
65
+ * Updates this page using the data source's property-key bindings. The SDK resolves property
66
+ * keys to raw property IDs before sending the bridge message to the host.
67
+ */
68
+ update: (
69
+ input: NotionDataSourcePageUpdateInput,
70
+ ) => Promise<NotionDataSourcePageUpdateResult>
71
+ }
@@ -0,0 +1,19 @@
1
+ import * as v from "valibot"
2
+ import { notionDateValueSchema } from "./dateValue.js"
3
+ import { notionRecordPointerSchema } from "./recordPointer.js"
4
+
5
+ /**
6
+ * Possible types for a data source value.
7
+ */
8
+ export const notionDataSourceValueSchema = v.union([
9
+ v.string(),
10
+ v.number(),
11
+ v.boolean(),
12
+ notionDateValueSchema,
13
+ v.array(v.string()),
14
+ v.array(notionRecordPointerSchema),
15
+ ])
16
+
17
+ export type NotionDataSourceValue = v.InferOutput<
18
+ typeof notionDataSourceValueSchema
19
+ >
@@ -0,0 +1,96 @@
1
+ import * as v from "valibot"
2
+
3
+ export const notionDateReminderSchema = v.object({
4
+ unit: v.picklist(["year", "month", "week", "day"]),
5
+ value: v.number(),
6
+ time: v.string(),
7
+ defaultTimeZone: v.optional(v.string()),
8
+ })
9
+
10
+ export type NotionDateReminder = v.InferOutput<typeof notionDateReminderSchema>
11
+
12
+ export const notionTimeReminderSchema = v.object({
13
+ unit: v.picklist(["hour", "minute"]),
14
+ value: v.number(),
15
+ })
16
+
17
+ export type NotionTimeReminder = v.InferOutput<typeof notionTimeReminderSchema>
18
+
19
+ export const notionNoReminderSchema = v.object({
20
+ unit: v.literal("none"),
21
+ })
22
+
23
+ export type NotionNoReminder = v.InferOutput<typeof notionNoReminderSchema>
24
+
25
+ /**
26
+ * Possible types for a Notion `datetime` reminder.
27
+ */
28
+ export const notionDateTimeReminderSchema = v.union([
29
+ notionDateReminderSchema,
30
+ notionTimeReminderSchema,
31
+ ])
32
+
33
+ export type NotionDateTimeReminder = v.InferOutput<
34
+ typeof notionDateTimeReminderSchema
35
+ >
36
+
37
+ const dateOrNoReminder = v.optional(
38
+ v.union([notionDateReminderSchema, notionNoReminderSchema]),
39
+ )
40
+
41
+ const dateTimeOrNoReminder = v.optional(
42
+ v.union([notionDateTimeReminderSchema, notionNoReminderSchema]),
43
+ )
44
+
45
+ export const notionDateSchema = v.object({
46
+ type: v.literal("date"),
47
+ start_date: v.string(),
48
+ reminder: dateOrNoReminder,
49
+ })
50
+ export type NotionDate = v.InferOutput<typeof notionDateSchema>
51
+
52
+ export const notionDateRangeSchema = v.object({
53
+ type: v.literal("daterange"),
54
+ start_date: v.string(),
55
+ end_date: v.string(),
56
+ reminder: dateOrNoReminder,
57
+ })
58
+ export type NotionDateRange = v.InferOutput<typeof notionDateRangeSchema>
59
+
60
+ export const notionDateTimeSchema = v.object({
61
+ type: v.literal("datetime"),
62
+ start_date: v.string(),
63
+ start_time: v.string(),
64
+ time_zone: v.optional(v.string()),
65
+ reminder: dateTimeOrNoReminder,
66
+ })
67
+
68
+ export type NotionDateTime = v.InferOutput<typeof notionDateTimeSchema>
69
+
70
+ export const notionDateTimeRangeSchema = v.object({
71
+ type: v.literal("datetimerange"),
72
+ start_date: v.string(),
73
+ start_time: v.string(),
74
+ end_date: v.string(),
75
+ end_time: v.string(),
76
+ time_zone: v.optional(v.string()),
77
+ reminder: dateTimeOrNoReminder,
78
+ })
79
+
80
+ export type NotionDateTimeRange = v.InferOutput<
81
+ typeof notionDateTimeRangeSchema
82
+ >
83
+
84
+ /**
85
+ * Possible types for a Notion `date` value.
86
+ */
87
+ export const notionDateValueSchema = v.variant("type", [
88
+ notionDateSchema,
89
+ notionDateRangeSchema,
90
+ notionDateTimeSchema,
91
+ notionDateTimeRangeSchema,
92
+ ])
93
+
94
+ export type NotionDateValue = Readonly<
95
+ v.InferOutput<typeof notionDateValueSchema>
96
+ >
@@ -0,0 +1,14 @@
1
+ import * as v from "valibot"
2
+ import type { CustomBlockErrorInfo } from "../errors"
3
+
4
+ // The schema accepts any string code. The type lists known codes for
5
+ // autocomplete, with an open string fallback for newer senders.
6
+ export const customBlockDataSourceResolutionErrorCodeSchema = v.string()
7
+
8
+ export type CustomBlockDataSourceResolutionErrorCode =
9
+ | "unknown_data_source_key"
10
+ | "unmapped_data_source"
11
+ | (string & {})
12
+
13
+ export type CustomBlockDataSourceResolutionErrorInfo =
14
+ CustomBlockErrorInfo<CustomBlockDataSourceResolutionErrorCode>
@@ -0,0 +1,186 @@
1
+ import * as v from "valibot"
2
+
3
+ /**
4
+ * Hex-token identifiers for Notion's named colors. Mirrors the public API's
5
+ * `select.options[].color` enum
6
+ * (https://developers.notion.com/reference/property-object#select).
7
+ */
8
+ export const notionPropertyColorSchema = v.picklist([
9
+ "default",
10
+ "gray",
11
+ "brown",
12
+ "orange",
13
+ "yellow",
14
+ "green",
15
+ "blue",
16
+ "purple",
17
+ "pink",
18
+ "red",
19
+ "gray_background",
20
+ "brown_background",
21
+ "orange_background",
22
+ "yellow_background",
23
+ "green_background",
24
+ "blue_background",
25
+ "purple_background",
26
+ "pink_background",
27
+ "red_background",
28
+ "default_background",
29
+ ])
30
+
31
+ export type NotionPropertyColor = v.InferOutput<
32
+ typeof notionPropertyColorSchema
33
+ >
34
+
35
+ export const notionPropertyOptionSchema = v.object({
36
+ id: v.string(),
37
+ name: v.string(),
38
+ color: v.optional(notionPropertyColorSchema),
39
+ description: v.optional(v.string()),
40
+ })
41
+
42
+ export type NotionPropertyOption = v.InferOutput<
43
+ typeof notionPropertyOptionSchema
44
+ >
45
+
46
+ export const notionStatusGroupSchema = v.object({
47
+ id: v.string(),
48
+ name: v.string(),
49
+ color: v.optional(notionPropertyColorSchema),
50
+ option_ids: v.array(v.string()),
51
+ })
52
+
53
+ export type NotionStatusGroup = v.InferOutput<typeof notionStatusGroupSchema>
54
+
55
+ export const notionDualPropertySchema = v.object({
56
+ synced_property_id: v.string(),
57
+ synced_property_name: v.string(),
58
+ })
59
+
60
+ export type NotionDualProperty = v.InferOutput<typeof notionDualPropertySchema>
61
+
62
+ const baseProp = v.object({
63
+ name: v.string(),
64
+ description: v.optional(v.string()),
65
+ })
66
+
67
+ /**
68
+ * Every Notion property type the bridge speaks, in a single readable list.
69
+ * Mirrors the Notion public API
70
+ * [property object](https://developers.notion.com/reference/property-object)
71
+ * type field. Internal-only types (`button`, `verification`,
72
+ * `last_visited_time`, `location`) and the four built-ins (`created_time`,
73
+ * `last_edited_time`, `created_by`, `last_edited_by`) are included under their
74
+ * bridge-native names.
75
+ */
76
+ export const NOTION_PROPERTY_TYPES = [
77
+ "title",
78
+ "rich_text",
79
+ "number",
80
+ "checkbox",
81
+ "url",
82
+ "email",
83
+ "phone_number",
84
+ "select",
85
+ "multi_select",
86
+ "status",
87
+ "date",
88
+ "people",
89
+ "files",
90
+ "unique_id",
91
+ "relation",
92
+ "place",
93
+ "formula",
94
+ "rollup",
95
+ "button",
96
+ "verification",
97
+ "last_visited_time",
98
+ "location",
99
+ "created_time",
100
+ "last_edited_time",
101
+ "created_by",
102
+ "last_edited_by",
103
+ ] as const
104
+
105
+ export const notionPropertyTypeSchema = v.picklist(NOTION_PROPERTY_TYPES)
106
+
107
+ /**
108
+ * String literal union of every supported Notion property type. Same set as
109
+ * the discriminator in `NotionPropertySchema` — split out so the manifest
110
+ * can declare expected property types without dragging in the per-type
111
+ * payload shapes.
112
+ */
113
+ export type NotionPropertyType = v.InferOutput<typeof notionPropertyTypeSchema>
114
+
115
+ /**
116
+ * Per-property schema as exposed by the host over the custom-block bridge.
117
+ * The `type` discriminator must be one of {@link NOTION_PROPERTY_TYPES}.
118
+ */
119
+ export const notionPropertySchemaSchema = v.variant("type", [
120
+ v.object({ ...baseProp.entries, type: v.literal("title") }),
121
+ v.object({ ...baseProp.entries, type: v.literal("rich_text") }),
122
+ v.object({ ...baseProp.entries, type: v.literal("number") }),
123
+ v.object({ ...baseProp.entries, type: v.literal("checkbox") }),
124
+ v.object({ ...baseProp.entries, type: v.literal("url") }),
125
+ v.object({ ...baseProp.entries, type: v.literal("email") }),
126
+ v.object({ ...baseProp.entries, type: v.literal("phone_number") }),
127
+ v.object({
128
+ ...baseProp.entries,
129
+ type: v.literal("select"),
130
+ options: v.array(notionPropertyOptionSchema),
131
+ }),
132
+ v.object({
133
+ ...baseProp.entries,
134
+ type: v.literal("multi_select"),
135
+ options: v.array(notionPropertyOptionSchema),
136
+ }),
137
+ v.object({
138
+ ...baseProp.entries,
139
+ type: v.literal("status"),
140
+ options: v.array(notionPropertyOptionSchema),
141
+ groups: v.array(notionStatusGroupSchema),
142
+ }),
143
+ v.object({ ...baseProp.entries, type: v.literal("date") }),
144
+ v.object({ ...baseProp.entries, type: v.literal("people") }),
145
+ v.object({ ...baseProp.entries, type: v.literal("files") }),
146
+ v.object({ ...baseProp.entries, type: v.literal("unique_id") }),
147
+ v.object({
148
+ ...baseProp.entries,
149
+ type: v.literal("relation"),
150
+ data_source_id: v.optional(v.string()),
151
+ dual_property: v.optional(notionDualPropertySchema),
152
+ }),
153
+ v.object({ ...baseProp.entries, type: v.literal("place") }),
154
+ v.object({ ...baseProp.entries, type: v.literal("formula") }),
155
+ v.object({ ...baseProp.entries, type: v.literal("rollup") }),
156
+
157
+ // Internal-only types passed through under their bridge-native names.
158
+ v.object({ ...baseProp.entries, type: v.literal("button") }),
159
+ v.object({ ...baseProp.entries, type: v.literal("verification") }),
160
+ v.object({ ...baseProp.entries, type: v.literal("last_visited_time") }),
161
+ v.object({ ...baseProp.entries, type: v.literal("location") }),
162
+
163
+ // Synthetic built-ins. The host always emits one of each per data source.
164
+ v.object({ ...baseProp.entries, type: v.literal("created_time") }),
165
+ v.object({ ...baseProp.entries, type: v.literal("last_edited_time") }),
166
+ v.object({ ...baseProp.entries, type: v.literal("created_by") }),
167
+ v.object({ ...baseProp.entries, type: v.literal("last_edited_by") }),
168
+ ])
169
+
170
+ export type NotionPropertySchema = v.InferOutput<
171
+ typeof notionPropertySchemaSchema
172
+ >
173
+
174
+ /**
175
+ * The four synthetic built-in property IDs the host always includes in every
176
+ * data source's `propertySchemasById` and every row's `propertiesById`.
177
+ */
178
+ export const NOTION_BUILTIN_PROPERTY_IDS = [
179
+ "created_time",
180
+ "last_edited_time",
181
+ "created_by",
182
+ "last_edited_by",
183
+ ] as const
184
+
185
+ export type NotionBuiltinPropertyId =
186
+ (typeof NOTION_BUILTIN_PROPERTY_IDS)[number]
@@ -0,0 +1,13 @@
1
+ import * as v from "valibot"
2
+
3
+ /**
4
+ * A pointer to a record in a database.
5
+ */
6
+ export const notionRecordPointerSchema = v.object({
7
+ id: v.string(),
8
+ table: v.string(),
9
+ })
10
+
11
+ export type NotionRecordPointer = v.InferOutput<
12
+ typeof notionRecordPointerSchema
13
+ >
@@ -0,0 +1,99 @@
1
+ import type { CustomBlockManifest } from "../manifest.js"
2
+ import type {
3
+ NotionDataSource,
4
+ NotionDataSourceBindings,
5
+ } from "./dataSource.js"
6
+ import type { NotionPropertySchema } from "./propertySchema.js"
7
+
8
+ type ResolveDataSourcesArgs = {
9
+ manifest: CustomBlockManifest | null
10
+ dataSourceBindings: NotionDataSourceBindings
11
+ }
12
+
13
+ /**
14
+ * Builds the public {@link NotionDataSource} list the SDK exposes to consumers.
15
+ *
16
+ * Combines the host-supplied bindings (collection pointers + schemas) with the
17
+ * manifest's declared data-source keys. When the manifest names a property
18
+ * that isn't in `propertyIdsByKey`, falls back to {@link findPropertyIdByManifestProperty}
19
+ * so renames in Notion still resolve as long as the schema name matches.
20
+ */
21
+ export function resolveDataSources(
22
+ args: ResolveDataSourcesArgs,
23
+ ): NotionDataSource[] {
24
+ if (args.manifest === null) {
25
+ return Object.entries(args.dataSourceBindings).map(([key, binding]) => ({
26
+ key,
27
+ collectionPointer: binding.collectionPointer,
28
+ collectionSchema: binding.collectionSchema,
29
+ propertyIdsByKey: { ...(binding.propertyIdsByKey ?? {}) },
30
+ propertySchemasById: binding.collectionSchema?.propertiesById ?? {},
31
+ }))
32
+ }
33
+
34
+ return Object.entries(args.manifest.dataSources).map(
35
+ ([key, manifestDataSource]) => {
36
+ const binding = args.dataSourceBindings[key]
37
+ const propertySchemasById =
38
+ binding?.collectionSchema?.propertiesById ?? {}
39
+
40
+ const bindingPropertyIdsByKey = binding?.propertyIdsByKey ?? {}
41
+ const propertyIdsByKey: Record<string, string | undefined> = {}
42
+ const manifestProperties = Object.entries(
43
+ manifestDataSource.properties ?? {},
44
+ )
45
+ for (const [propertyKey, manifestProperty] of manifestProperties) {
46
+ const propertyId =
47
+ propertyKey in bindingPropertyIdsByKey
48
+ ? bindingPropertyIdsByKey[propertyKey]
49
+ : findPropertyIdByManifestProperty(propertySchemasById, {
50
+ key: propertyKey,
51
+ type: manifestProperty.type,
52
+ })
53
+ const propertySchema =
54
+ propertyId === undefined ? undefined : propertySchemasById[propertyId]
55
+ propertyIdsByKey[propertyKey] =
56
+ propertySchema?.type === manifestProperty.type
57
+ ? propertyId
58
+ : undefined
59
+ }
60
+
61
+ return {
62
+ key,
63
+ collectionPointer: binding?.collectionPointer,
64
+ collectionSchema: binding?.collectionSchema,
65
+ propertyIdsByKey,
66
+ propertySchemasById,
67
+ }
68
+ },
69
+ )
70
+ }
71
+
72
+ export function findPropertyIdByManifestProperty(
73
+ propertySchemasById: Record<string, NotionPropertySchema>,
74
+ manifestProperty: { key: string; type: NotionPropertySchema["type"] },
75
+ ): string | undefined {
76
+ // `ManifestProperty.name` is display copy for setup UI. Binding fallback is based
77
+ // on the stable semantic key so copy changes don't affect property resolution.
78
+ const propertySchemaForKey = propertySchemasById[manifestProperty.key]
79
+ if (propertySchemaForKey?.type === manifestProperty.type) {
80
+ return manifestProperty.key
81
+ }
82
+
83
+ const normalizedKey = normalizePropertyName(manifestProperty.key)
84
+ for (const [propertyId, propertySchema] of Object.entries(
85
+ propertySchemasById,
86
+ )) {
87
+ if (
88
+ propertySchema.type === manifestProperty.type &&
89
+ normalizePropertyName(propertySchema.name) === normalizedKey
90
+ ) {
91
+ return propertyId
92
+ }
93
+ }
94
+ return undefined
95
+ }
96
+
97
+ function normalizePropertyName(value: string): string {
98
+ return value.trim().toLowerCase()
99
+ }
@@ -0,0 +1,130 @@
1
+ import * as v from "valibot"
2
+ import type { CustomBlockErrorInfo } from "../errors"
3
+ import type {
4
+ NotionPagePropertyInputMap,
5
+ NotionPagePropertyWriteMap,
6
+ } from "../pages/page.js"
7
+ import { notionPagePropertyValueSchema } from "../pages/page.js"
8
+ import type { NotionDataSource } from "./dataSource.js"
9
+
10
+ // The schema accepts any string code. The type lists known codes for
11
+ // autocomplete, with an open string fallback for newer senders.
12
+ export const customBlockPropertyErrorCodeSchema = v.string()
13
+
14
+ export type CustomBlockPropertyErrorCode =
15
+ | "unmapped_property"
16
+ | "property_id_mismatch"
17
+ | "duplicate_property"
18
+ | "invalid_property_value"
19
+ | (string & {})
20
+
21
+ export type CustomBlockPropertyErrorInfo =
22
+ CustomBlockErrorInfo<CustomBlockPropertyErrorCode>
23
+
24
+ export type PropertyWriteMapResolutionResult =
25
+ | { status: "success"; properties: NotionPagePropertyWriteMap }
26
+ | { status: "error"; error: CustomBlockPropertyErrorInfo }
27
+
28
+ function makePropertyError(
29
+ code: CustomBlockPropertyErrorCode,
30
+ message: string,
31
+ ): CustomBlockPropertyErrorInfo {
32
+ return { code, message, isRetryable: false }
33
+ }
34
+
35
+ /**
36
+ * Resolves a public SDK property write map into the ID-keyed bridge shape.
37
+ *
38
+ * Identifiers in `properties` may be raw property IDs or data-source property keys; the latter
39
+ * are looked up in the `dataSource`'s `propertyIdsByKey`. Each value is re-parsed through
40
+ * `notionPagePropertyValueSchema` with its `id` rewritten to the resolved property ID.
41
+ */
42
+ export function resolvePropertyWriteMapForDataSource(args: {
43
+ dataSource: NotionDataSource | undefined
44
+ properties: NotionPagePropertyInputMap
45
+ operationName: string
46
+ }): PropertyWriteMapResolutionResult {
47
+ const { dataSource, properties, operationName } = args
48
+
49
+ const resolvedProperties: NotionPagePropertyWriteMap = {}
50
+ for (const [identifier, value] of Object.entries(properties)) {
51
+ const propertyIdResult = resolvePropertyIdentifierForDataSource({
52
+ dataSource,
53
+ identifier,
54
+ operationName,
55
+ })
56
+ if (propertyIdResult.status === "error") {
57
+ return propertyIdResult
58
+ }
59
+
60
+ const propertyId = propertyIdResult.propertyId
61
+ if (
62
+ value.id !== undefined &&
63
+ value.id !== identifier &&
64
+ value.id !== propertyId
65
+ ) {
66
+ return {
67
+ status: "error",
68
+ error: makePropertyError(
69
+ "property_id_mismatch",
70
+ `Property ${identifier} resolved to ${propertyId} but value id was ${value.id}.`,
71
+ ),
72
+ }
73
+ }
74
+ if (resolvedProperties[propertyId] !== undefined) {
75
+ return {
76
+ status: "error",
77
+ error: makePropertyError(
78
+ "duplicate_property",
79
+ `Cannot set property ${propertyId} more than once.`,
80
+ ),
81
+ }
82
+ }
83
+
84
+ const parsedValue = v.safeParse(notionPagePropertyValueSchema, {
85
+ ...value,
86
+ id: propertyId,
87
+ })
88
+ if (!parsedValue.success) {
89
+ return {
90
+ status: "error",
91
+ error: makePropertyError(
92
+ "invalid_property_value",
93
+ `Invalid value for property ${identifier}.`,
94
+ ),
95
+ }
96
+ }
97
+
98
+ resolvedProperties[propertyId] = parsedValue.output
99
+ }
100
+
101
+ return { status: "success", properties: resolvedProperties }
102
+ }
103
+
104
+ /**
105
+ * Treats matching data-source keys as aliases for property IDs; all other identifiers are raw IDs.
106
+ */
107
+ export function resolvePropertyIdentifierForDataSource(args: {
108
+ dataSource: NotionDataSource | undefined
109
+ identifier: string
110
+ operationName: string
111
+ }):
112
+ | { status: "success"; propertyId: string }
113
+ | { status: "error"; error: CustomBlockPropertyErrorInfo } {
114
+ const { dataSource, identifier, operationName } = args
115
+ if (dataSource !== undefined && identifier in dataSource.propertyIdsByKey) {
116
+ const propertyId = dataSource.propertyIdsByKey[identifier]
117
+ if (propertyId === undefined) {
118
+ return {
119
+ status: "error",
120
+ error: makePropertyError(
121
+ "unmapped_property",
122
+ `${operationName} cannot resolve property key "${identifier}" because it is not bound to a Notion property.`,
123
+ ),
124
+ }
125
+ }
126
+ return { status: "success", propertyId }
127
+ }
128
+
129
+ return { status: "success", propertyId: identifier }
130
+ }