@notionhq/custom-blocks 0.0.76 → 0.0.78

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 (109) hide show
  1. package/HOST.md +68 -37
  2. package/bin/src/bridge/manifest.js +3 -3
  3. package/dist/bridge/SandboxBridge.d.ts +6 -12
  4. package/dist/bridge/SandboxBridge.d.ts.map +1 -1
  5. package/dist/bridge/SandboxBridge.js +123 -71
  6. package/dist/bridge/dataSources/resolve.d.ts +3 -4
  7. package/dist/bridge/dataSources/resolve.d.ts.map +1 -1
  8. package/dist/bridge/dataSources/resolve.js +2 -12
  9. package/dist/bridge/hostState.d.ts +3 -2
  10. package/dist/bridge/hostState.d.ts.map +1 -1
  11. package/dist/bridge/loadManifest.d.ts +4 -4
  12. package/dist/bridge/loadManifest.d.ts.map +1 -1
  13. package/dist/bridge/loadManifest.js +2 -2
  14. package/dist/bridge/manifest.d.ts +3 -3
  15. package/dist/bridge/manifest.js +3 -3
  16. package/dist/bridge/messages/{ready.d.ts → connect.d.ts} +13 -11
  17. package/dist/bridge/messages/connect.d.ts.map +1 -0
  18. package/dist/bridge/messages/{ready.js → connect.js} +14 -13
  19. package/dist/bridge/messages/hostToSandbox.d.ts +24 -79
  20. package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -1
  21. package/dist/bridge/messages/hostToSandbox.js +2 -3
  22. package/dist/bridge/messages/init.d.ts +35 -6
  23. package/dist/bridge/messages/init.d.ts.map +1 -1
  24. package/dist/bridge/messages/init.js +8 -4
  25. package/dist/bridge/messages/initResult.d.ts +29 -0
  26. package/dist/bridge/messages/initResult.d.ts.map +1 -0
  27. package/dist/bridge/messages/initResult.js +25 -0
  28. package/dist/bridge/messages/queryDataSource.d.ts +3 -7
  29. package/dist/bridge/messages/queryDataSource.d.ts.map +1 -1
  30. package/dist/bridge/messages/queryDataSource.js +3 -7
  31. package/dist/bridge/messages/queryDataSourceResult.d.ts +4 -240
  32. package/dist/bridge/messages/queryDataSourceResult.d.ts.map +1 -1
  33. package/dist/bridge/messages/queryDataSourceResult.js +4 -22
  34. package/dist/bridge/messages/sandboxToHost.d.ts +21 -7
  35. package/dist/bridge/messages/sandboxToHost.d.ts.map +1 -1
  36. package/dist/bridge/messages/sandboxToHost.js +4 -2
  37. package/dist/bridge/sandboxClient.d.ts +2 -4
  38. package/dist/bridge/sandboxClient.d.ts.map +1 -1
  39. package/dist/bridge/sandboxClient.js +2 -5
  40. package/dist/customBlock.d.ts +1 -1
  41. package/dist/customBlock.d.ts.map +1 -1
  42. package/dist/customBlock.js +1 -1
  43. package/dist/host/createCustomBlockHost.d.ts +6 -3
  44. package/dist/host/createCustomBlockHost.d.ts.map +1 -1
  45. package/dist/host/createCustomBlockHost.js +227 -58
  46. package/dist/host/lifecycle/initErrors.d.ts +1 -1
  47. package/dist/host/lifecycle/initErrors.d.ts.map +1 -1
  48. package/dist/host/lifecycle/initErrors.js +25 -7
  49. package/dist/host/lifecycle/types.d.ts +6 -4
  50. package/dist/host/lifecycle/types.d.ts.map +1 -1
  51. package/dist/host/messages/invalidSandboxMessage.js +0 -3
  52. package/dist/host/queries/querySubscriptions.d.ts +10 -10
  53. package/dist/host/queries/querySubscriptions.d.ts.map +1 -1
  54. package/dist/host/queries/querySubscriptions.js +35 -19
  55. package/dist/host/queries/types.d.ts +5 -4
  56. package/dist/host/queries/types.d.ts.map +1 -1
  57. package/dist/host.d.ts +5 -3
  58. package/dist/host.d.ts.map +1 -1
  59. package/dist/host.js +2 -1
  60. package/dist/index.d.ts +2 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +1 -1
  63. package/dist/init.d.ts +7 -7
  64. package/dist/init.d.ts.map +1 -1
  65. package/dist/init.js +70 -50
  66. package/dist/react/index.d.ts +1 -1
  67. package/dist/react/index.d.ts.map +1 -1
  68. package/dist/react/standalonePreview.d.ts.map +1 -1
  69. package/dist/react/standalonePreview.js +2 -0
  70. package/dist/react/useCustomBlockInit.d.ts +5 -6
  71. package/dist/react/useCustomBlockInit.d.ts.map +1 -1
  72. package/dist/react/useCustomBlockInit.js +3 -19
  73. package/dist/react/useRuntimeState.d.ts +4 -3
  74. package/dist/react/useRuntimeState.d.ts.map +1 -1
  75. package/dist/react/useRuntimeState.js +3 -2
  76. package/dist/version.js +1 -1
  77. package/docs/data-sources.md +7 -5
  78. package/docs/errors.md +5 -1
  79. package/docs/lifecycle.md +19 -31
  80. package/docs/manifest.md +1 -1
  81. package/package.json +1 -1
  82. package/src/bridge/SandboxBridge.ts +151 -77
  83. package/src/bridge/dataSources/resolve.ts +3 -14
  84. package/src/bridge/hostState.ts +3 -2
  85. package/src/bridge/loadManifest.ts +6 -6
  86. package/src/bridge/manifest.ts +3 -3
  87. package/src/bridge/messages/{ready.ts → connect.ts} +15 -14
  88. package/src/bridge/messages/hostToSandbox.ts +2 -6
  89. package/src/bridge/messages/init.ts +24 -10
  90. package/src/bridge/messages/initResult.ts +37 -0
  91. package/src/bridge/messages/queryDataSource.ts +3 -7
  92. package/src/bridge/messages/queryDataSourceResult.ts +4 -24
  93. package/src/bridge/messages/sandboxToHost.ts +4 -2
  94. package/src/bridge/sandboxClient.ts +3 -8
  95. package/src/customBlock.ts +2 -2
  96. package/src/host/createCustomBlockHost.ts +269 -64
  97. package/src/host/lifecycle/initErrors.ts +25 -7
  98. package/src/host/lifecycle/types.ts +13 -4
  99. package/src/host/messages/invalidSandboxMessage.ts +0 -3
  100. package/src/host/queries/querySubscriptions.ts +58 -39
  101. package/src/host/queries/types.ts +10 -11
  102. package/src/host.ts +13 -2
  103. package/src/index.ts +3 -1
  104. package/src/init.ts +73 -60
  105. package/src/react/index.ts +0 -1
  106. package/src/react/standalonePreview.ts +2 -0
  107. package/src/react/useCustomBlockInit.ts +6 -27
  108. package/src/react/useRuntimeState.ts +4 -3
  109. package/dist/bridge/messages/ready.d.ts.map +0 -1
@@ -1,52 +1,71 @@
1
1
  import type { NotionDataSourceId } from "../../bridge/ids.js"
2
2
  import type { QueryDataSourceMessage } from "../../bridge/messages/queryDataSource.js"
3
- import type {
4
- CustomBlockHostQueryDataSourceResult,
5
- QuerySubscriptionState,
6
- } from "./types.js"
7
-
8
- export type QueryRefreshResult =
9
- | {
10
- status: "success"
11
- requestId: string
12
- snapshotId: string
13
- response: CustomBlockHostQueryDataSourceResult
14
- }
15
- | { status: "missing" }
3
+ import type { CustomBlockHostQueryDataSourceResult } from "./types.js"
4
+
5
+ export type QueryRefresh = {
6
+ subscriptionId: string
7
+ response: CustomBlockHostQueryDataSourceResult
8
+ }
9
+
10
+ type QuerySubscriptionToken = object
11
+
12
+ type QuerySubscriptionState = {
13
+ dataSourceId: NotionDataSourceId
14
+ limit: number
15
+ token: QuerySubscriptionToken
16
+ }
16
17
 
17
18
  export class QuerySubscriptions {
18
- private readonly latestByDataSourceId = new Map<
19
- NotionDataSourceId,
20
- QuerySubscriptionState
21
- >()
22
-
23
- track(message: QueryDataSourceMessage) {
24
- this.latestByDataSourceId.set(message.dataSourceId, {
25
- requestId: message.requestId,
26
- snapshotId: message.snapshotId,
19
+ private readonly bySubscriptionId = new Map<string, QuerySubscriptionState>()
20
+
21
+ track(message: QueryDataSourceMessage): QuerySubscriptionToken {
22
+ const token = {}
23
+ this.bySubscriptionId.set(message.subscriptionId, {
24
+ dataSourceId: message.dataSourceId,
27
25
  limit: message.limit,
26
+ token,
28
27
  })
28
+ return token
29
+ }
30
+
31
+ isCurrent(subscriptionId: string, token: QuerySubscriptionToken): boolean {
32
+ return this.bySubscriptionId.get(subscriptionId)?.token === token
29
33
  }
30
34
 
31
- resolveRefresh(args: {
35
+ resolveRefreshes(args: {
32
36
  dataSourceId: NotionDataSourceId
33
37
  response: CustomBlockHostQueryDataSourceResult
34
- }): QueryRefreshResult {
35
- const queryState = this.latestByDataSourceId.get(args.dataSourceId)
36
- if (!queryState) {
37
- return { status: "missing" }
38
- }
39
- const items = args.response.items.slice(0, queryState.limit)
40
- return {
41
- status: "success",
42
- requestId: queryState.requestId,
43
- snapshotId: queryState.snapshotId,
44
- response: {
45
- items,
46
- hasMore:
47
- args.response.hasMore ?? args.response.items.length > items.length,
48
- error: args.response.error,
49
- },
38
+ }): QueryRefresh[] {
39
+ const refreshes: QueryRefresh[] = []
40
+ for (const [subscriptionId, queryState] of this.bySubscriptionId) {
41
+ if (queryState.dataSourceId !== args.dataSourceId) {
42
+ continue
43
+ }
44
+ queryState.token = {}
45
+ refreshes.push({
46
+ subscriptionId,
47
+ response: limitResponse(args.response, queryState.limit),
48
+ })
50
49
  }
50
+ return refreshes
51
+ }
52
+
53
+ clear() {
54
+ this.bySubscriptionId.clear()
55
+ }
56
+ }
57
+
58
+ function limitResponse(
59
+ response: CustomBlockHostQueryDataSourceResult,
60
+ limit: number,
61
+ ): CustomBlockHostQueryDataSourceResult {
62
+ if (response.status === "error") {
63
+ return response
64
+ }
65
+ const items = response.items.slice(0, limit)
66
+ return {
67
+ status: "success",
68
+ items,
69
+ hasMore: response.hasMore || response.items.length > items.length,
51
70
  }
52
71
  }
@@ -1,14 +1,13 @@
1
1
  import type { NotionDataSourcePageBridge } from "../../bridge/dataSources/dataSourcePage.js"
2
- import type { QueryDataSourceMessage } from "../../bridge/messages/queryDataSource.js"
3
2
  import type { CustomBlockQueryDataSourceErrorInfo } from "../../bridge/messages/queryDataSourceResult.js"
4
3
 
5
- export type CustomBlockHostQueryDataSourceResult = {
6
- items: NotionDataSourcePageBridge[]
7
- hasMore?: boolean
8
- error?: CustomBlockQueryDataSourceErrorInfo
9
- }
10
-
11
- export type QuerySubscriptionState = Pick<
12
- QueryDataSourceMessage,
13
- "requestId" | "snapshotId" | "limit"
14
- >
4
+ export type CustomBlockHostQueryDataSourceResult =
5
+ | {
6
+ status: "success"
7
+ items: NotionDataSourcePageBridge[]
8
+ hasMore: boolean
9
+ }
10
+ | {
11
+ status: "error"
12
+ error: CustomBlockQueryDataSourceErrorInfo
13
+ }
package/src/host.ts CHANGED
@@ -38,6 +38,8 @@ export {
38
38
  notionPageIdSchema,
39
39
  } from "./bridge/ids.js"
40
40
  export { readIncomingType } from "./bridge/incomingType.js"
41
+ export type { ConnectMessage } from "./bridge/messages/connect.js"
42
+ export { connectMessageSchema } from "./bridge/messages/connect.js"
41
43
  export type { CreatePageMessage } from "./bridge/messages/createPage.js"
42
44
  export { createPageMessageSchema } from "./bridge/messages/createPage.js"
43
45
  export type {
@@ -90,6 +92,16 @@ export {
90
92
  customBlockInitErrorInfoSchema,
91
93
  initMessageSchema,
92
94
  } from "./bridge/messages/init.js"
95
+ export type {
96
+ CustomBlockInitResultErrorCode,
97
+ CustomBlockInitResultErrorInfo,
98
+ InitResultMessage,
99
+ } from "./bridge/messages/initResult.js"
100
+ export {
101
+ customBlockInitResultErrorCodeSchema,
102
+ customBlockInitResultErrorInfoSchema,
103
+ initResultMessageSchema,
104
+ } from "./bridge/messages/initResult.js"
93
105
  export type { InvalidHostMessage } from "./bridge/messages/invalidHostMessage.js"
94
106
  export { invalidHostMessageSchema } from "./bridge/messages/invalidHostMessage.js"
95
107
  export type { InvalidSandboxMessage } from "./bridge/messages/invalidSandboxMessage.js"
@@ -122,8 +134,6 @@ export {
122
134
  customBlockQueryDataSourceErrorInfoSchema,
123
135
  queryDataSourceResultMessageSchema,
124
136
  } from "./bridge/messages/queryDataSourceResult.js"
125
- export type { ReadyMessage } from "./bridge/messages/ready.js"
126
- export { readyMessageSchema } from "./bridge/messages/ready.js"
127
137
  export type { ResizeMessage } from "./bridge/messages/resize.js"
128
138
  export { resizeMessageSchema } from "./bridge/messages/resize.js"
129
139
  export type { SandboxToHostMessage } from "./bridge/messages/sandboxToHost.js"
@@ -151,6 +161,7 @@ export {
151
161
  createCustomBlockHost,
152
162
  } from "./host/createCustomBlockHost.js"
153
163
  export type {
164
+ ConnectSuccessMessage,
154
165
  CustomBlockHostDataSourcesPayload,
155
166
  CustomBlockHostInitialDataSources,
156
167
  CustomBlockHostInitialState,
package/src/index.ts CHANGED
@@ -79,8 +79,10 @@ export type {
79
79
  export type {
80
80
  CustomBlockInitErrorCode,
81
81
  CustomBlockInitErrorInfo,
82
+ CustomBlockInitializationErrorCode,
83
+ CustomBlockInitializationErrorInfo,
82
84
  } from "./bridge/messages/init.js"
83
- export { CustomBlockInitError } from "./bridge/messages/init.js"
85
+ export { CustomBlockInitializationError } from "./bridge/messages/init.js"
84
86
  export type {
85
87
  CustomBlockListUsersErrorCode,
86
88
  CustomBlockListUsersErrorInfo,
package/src/init.ts CHANGED
@@ -1,19 +1,16 @@
1
1
  import type { NotionDataSource } from "./bridge/dataSources/dataSource.js"
2
2
  import type { NotionBlockId } from "./bridge/ids.js"
3
3
  import { loadManifest } from "./bridge/loadManifest.js"
4
- import {
5
- CustomBlockInitError,
6
- type CustomBlockInitErrorCode,
7
- type InitMessage,
8
- } from "./bridge/messages/init.js"
4
+ import { CustomBlockInitializationError } from "./bridge/messages/init.js"
9
5
  import type { CustomBlockPage } from "./bridge/pages/page.js"
10
6
  import type { NotionParent } from "./bridge/parent.js"
11
7
  import { customBlockHost } from "./bridge/sandboxClient.js"
12
8
  import type { NotionTheme } from "./bridge/theme.js"
13
9
  import type { NotionUser } from "./bridge/users/user.js"
10
+ import { unreachable } from "./utils.js"
14
11
 
15
12
  /**
16
- * The payload sent by the host in the `init` message in response to the sandbox's `ready` message.
13
+ * The payload sent by the host in the `init` message in response to the sandbox's `connect` message.
17
14
  */
18
15
  export type CustomBlockInitPayload = {
19
16
  theme: NotionTheme
@@ -30,16 +27,17 @@ export type CustomBlockInitPayload = {
30
27
  * `<NotionCustomBlock>` catches this specifically and falls back to a standalone preview with a
31
28
  * warning banner. Direct callers can `instanceof` it to apply their own policy.
32
29
  */
33
- export class NotInIframeError extends Error {
30
+ export class NotInIframeError extends CustomBlockInitializationError {
34
31
  constructor(message: string = NOT_IN_IFRAME_MESSAGE) {
35
- super(message)
32
+ super({
33
+ code: "not_in_iframe",
34
+ message,
35
+ isRetryable: false,
36
+ })
36
37
  this.name = "NotInIframeError"
37
- this.code = "not_in_iframe"
38
- this.isRetryable = false
39
38
  }
40
39
 
41
- code: CustomBlockInitErrorCode
42
- isRetryable: boolean
40
+ declare code: "not_in_iframe"
43
41
  }
44
42
 
45
43
  /**
@@ -64,9 +62,10 @@ let initPromise: Promise<CustomBlockInitPayload> | undefined
64
62
 
65
63
  /**
66
64
  * Performs the SDK <-> host handshake: loads `custom_blocks.json`, posts
67
- * `ready`, then awaits the host's `init` message. Resolves with that payload.
65
+ * `connect`, then awaits the host's `init` message. Resolves after the sandbox
66
+ * applies the payload and returns `initResult.success`.
68
67
  *
69
- * Rejects with a `CustomBlockInitError` if the host doesn't respond inside `timeoutMs`.
68
+ * Rejects with a `CustomBlockInitializationError` if initialization fails.
70
69
  *
71
70
  * Idempotent: subsequent calls return the same promise as the first and ignore any new options.
72
71
  * Mount your React tree (or call any SDK hook / `customBlock.subscribe`) only after the
@@ -76,61 +75,75 @@ export function initCustomBlock(
76
75
  opts: InitCustomBlockOptions = {},
77
76
  ): Promise<CustomBlockInitPayload> {
78
77
  if (initPromise === undefined) {
79
- initPromise = (async () => {
80
- // Fail fast with a typed error when rendered as a standalone tab and not in a parent frame.
81
- // Otherwise, it would eventually hit the timeout, since `postMessage` to `window.parent`
82
- // would just hit the same window and never arrive.
83
- if (typeof window !== "undefined" && window.parent === window) {
84
- throw new NotInIframeError()
85
- }
78
+ initPromise = initializeCustomBlock(opts)
79
+ }
80
+ return initPromise
81
+ }
86
82
 
87
- // Load the manifest and send it to the host.
88
- const manifestResult = await loadManifest()
89
- customBlockHost.sendReady(manifestResult)
83
+ async function initializeCustomBlock(
84
+ opts: InitCustomBlockOptions,
85
+ ): Promise<CustomBlockInitPayload> {
86
+ try {
87
+ // Fail fast with a typed error when rendered as a standalone tab and not in a parent frame.
88
+ // Otherwise, it would eventually hit the timeout, since `postMessage` to `window.parent`
89
+ // would just hit the same window and never arrive.
90
+ if (typeof window !== "undefined" && window.parent === window) {
91
+ throw new NotInIframeError()
92
+ }
90
93
 
91
- const timeoutMs = opts.timeoutMs ?? DEFAULT_INIT_TIMEOUT_MS
92
- let message: InitMessage
93
- try {
94
- message = await customBlockHost.awaitInit(
95
- AbortSignal.timeout(timeoutMs),
96
- )
97
- } catch (error) {
98
- if (isTimeoutError(error)) {
99
- throw new CustomBlockInitError({
100
- code: "init_timeout",
101
- message: "Host did not respond to init before the timeout.",
102
- isRetryable: true,
103
- })
104
- }
105
- throw error
106
- }
107
- if (message.status === "error") {
108
- console.error(
109
- `[custom-blocks-sdk] host reported init error (${message.error.code}): ${message.error.message}`,
110
- )
111
- throw new CustomBlockInitError(message.error)
112
- }
94
+ // Load the manifest and send it to the host.
95
+ const manifestResult = await loadManifest()
96
+ customBlockHost.sendConnect(manifestResult)
113
97
 
114
- const hostState = customBlockHost.getState()
115
- if (hostState.status !== "initialized") {
116
- throw new CustomBlockInitError({
98
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_INIT_TIMEOUT_MS
99
+ await awaitHostInitWithTimeout(timeoutMs)
100
+
101
+ const hostState = customBlockHost.getState()
102
+ switch (hostState.status) {
103
+ case "initialized":
104
+ return {
105
+ theme: hostState.theme,
106
+ blockId: hostState.blockId,
107
+ parent: hostState.parent,
108
+ page: hostState.page,
109
+ currentUser: hostState.currentUser,
110
+ dataSources: hostState.dataSources,
111
+ }
112
+ case "uninitialized":
113
+ throw new CustomBlockInitializationError({
117
114
  code: "context_unavailable",
118
115
  message: "Host block payload is unavailable.",
119
116
  isRetryable: true,
120
117
  })
121
- }
118
+ default:
119
+ return unreachable(hostState)
120
+ }
121
+ } catch (error) {
122
+ if (error instanceof CustomBlockInitializationError) {
123
+ throw error
124
+ }
125
+ const message = error instanceof Error ? error.message : String(error)
126
+ throw new CustomBlockInitializationError({
127
+ code: "unknown_error",
128
+ message,
129
+ isRetryable: false,
130
+ })
131
+ }
132
+ }
122
133
 
123
- return {
124
- theme: message.theme,
125
- blockId: hostState.blockId,
126
- parent: hostState.parent,
127
- page: hostState.page,
128
- currentUser: message.currentUser,
129
- dataSources: hostState.dataSources,
130
- }
131
- })()
134
+ async function awaitHostInitWithTimeout(timeoutMs: number): Promise<void> {
135
+ try {
136
+ await customBlockHost.awaitInit(AbortSignal.timeout(timeoutMs))
137
+ } catch (error) {
138
+ if (isTimeoutError(error)) {
139
+ throw new CustomBlockInitializationError({
140
+ code: "init_timeout",
141
+ message: "Host did not respond to init before the timeout.",
142
+ isRetryable: true,
143
+ })
144
+ }
145
+ throw error
132
146
  }
133
- return initPromise
134
147
  }
135
148
 
136
149
  function isTimeoutError(error: unknown): boolean {
@@ -13,7 +13,6 @@ export {
13
13
  } from "./NotionCustomBlock.js"
14
14
  export { useCustomBlockAutoResize } from "./useCustomBlockAutoResize.js"
15
15
  export {
16
- type CustomBlockInitFailure,
17
16
  type UseCustomBlockInitResult,
18
17
  useCustomBlockInit,
19
18
  } from "./useCustomBlockInit.js"
@@ -8,11 +8,13 @@ const previewPageId = v.parse(notionPageIdSchema, "")
8
8
  export function seedStandalonePreviewState() {
9
9
  customBlockHost.setMockState({
10
10
  type: "init",
11
+ initializationId: "standalone-preview",
11
12
  status: "success",
12
13
  theme: "light",
13
14
  blockId: previewBlockId,
14
15
  parent: { type: "page_id", page_id: previewPageId },
15
16
  page: { id: previewPageId, parent: { type: "workspace", workspace: true } },
17
+ manifest: { version: 1, dataSources: {} },
16
18
  dataSources: { bindings: {} },
17
19
  currentUser: {
18
20
  object: "user",
@@ -1,27 +1,24 @@
1
1
  import { useEffect, useState } from "react"
2
- import { CustomBlockInitError } from "../bridge/messages/init.js"
2
+ import type { CustomBlockInitializationError } from "../bridge/messages/init.js"
3
3
  import {
4
4
  type CustomBlockInitPayload,
5
5
  type InitCustomBlockOptions,
6
6
  initCustomBlock,
7
- NotInIframeError,
8
7
  } from "../init.js"
9
8
 
10
- export type CustomBlockInitFailure = CustomBlockInitError | NotInIframeError
11
-
12
9
  /**
13
10
  * Discriminated state returned by {@link useCustomBlockInit}.
14
11
  *
15
12
  * Branch on `isLoaded`/`error`:
16
13
  * - `{ isLoaded: false, error: undefined }` — handshake in progress.
17
- * - `{ isLoaded: false, error: CustomBlockInitFailure }` — handshake failed (most commonly a
18
- * `CustomBlockInitError` with code `init_timeout` because the host never sent `init`).
14
+ * - `{ isLoaded: false, error: CustomBlockInitializationError }` — handshake failed (most commonly a
15
+ * `CustomBlockInitializationError` with code `init_timeout` because the host never sent `init`).
19
16
  * - `{ isLoaded: true, initial }` — handshake complete; safe to render
20
17
  * children that call `useTheme`, `useBlockId`, etc.
21
18
  */
22
19
  export type UseCustomBlockInitResult =
23
20
  | { isLoaded: false; error: undefined }
24
- | { isLoaded: false; error: CustomBlockInitFailure }
21
+ | { isLoaded: false; error: CustomBlockInitializationError }
25
22
  | { isLoaded: true; error: undefined; initial: CustomBlockInitPayload }
26
23
 
27
24
  /**
@@ -56,12 +53,9 @@ export function useCustomBlockInit(
56
53
  setState({ isLoaded: true, error: undefined, initial })
57
54
  }
58
55
  },
59
- err => {
56
+ error => {
60
57
  if (!cancelled) {
61
- setState({
62
- isLoaded: false,
63
- error: normalizeInitError(err),
64
- })
58
+ setState({ isLoaded: false, error })
65
59
  }
66
60
  },
67
61
  )
@@ -74,18 +68,3 @@ export function useCustomBlockInit(
74
68
  }, [])
75
69
  return state
76
70
  }
77
-
78
- function normalizeInitError(error: unknown): CustomBlockInitFailure {
79
- if (
80
- error instanceof CustomBlockInitError ||
81
- error instanceof NotInIframeError
82
- ) {
83
- return error
84
- }
85
- const message = error instanceof Error ? error.message : String(error)
86
- return new CustomBlockInitError({
87
- code: "unknown_error",
88
- message,
89
- isRetryable: false,
90
- })
91
- }
@@ -72,14 +72,15 @@ export function useCurrentUser(): NotionUser {
72
72
  }
73
73
 
74
74
  /**
75
- * Returns the author-declared manifest loaded from `custom_blocks.json` — the semantic
75
+ * Returns the authoritative manifest received from the host — the semantic
76
76
  * data-source keys plus their declared `name`, `description`, and property declarations.
77
- * `null` when the block ships no manifest.
77
+ *
78
+ * Throws if called before `initCustomBlock` has resolved.
78
79
  *
79
80
  * This is the configuration the block declared, not host-resolved bindings: use
80
81
  * `useDataSource(key)` for rows and resolved schema. Handy for enumerating the declared
81
82
  * data-source keys (e.g. picking a default key, or rendering a key switcher).
82
83
  */
83
- export function useManifest(): CustomBlockManifest | null {
84
+ export function useManifest(): CustomBlockManifest {
84
85
  return useSyncExternalStore(customBlock.subscribe, customBlock.getManifest)
85
86
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/ready.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AA0B5B;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;IAG7B;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BASH,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,kBAAkB,CAAC,CAAA"}