@notionhq/custom-blocks 0.0.77 → 0.0.79
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.
- package/HOST.md +68 -34
- package/README.md +1 -1
- package/bin/src/bridge/manifest.js +3 -3
- package/dist/bridge/SandboxBridge.d.ts +8 -13
- package/dist/bridge/SandboxBridge.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.js +110 -39
- package/dist/bridge/dataSources/resolve.d.ts +3 -4
- package/dist/bridge/dataSources/resolve.d.ts.map +1 -1
- package/dist/bridge/dataSources/resolve.js +2 -12
- package/dist/bridge/hostState.d.ts +2 -0
- package/dist/bridge/hostState.d.ts.map +1 -1
- package/dist/bridge/loadManifest.d.ts +4 -4
- package/dist/bridge/loadManifest.d.ts.map +1 -1
- package/dist/bridge/loadManifest.js +2 -2
- package/dist/bridge/manifest.d.ts +3 -3
- package/dist/bridge/manifest.js +3 -3
- package/dist/bridge/messages/{ready.d.ts → connect.d.ts} +14 -12
- package/dist/bridge/messages/connect.d.ts.map +1 -0
- package/dist/bridge/messages/connect.js +38 -0
- package/dist/bridge/messages/hostToSandbox.d.ts +21 -0
- package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -1
- package/dist/bridge/messages/init.d.ts +35 -6
- package/dist/bridge/messages/init.d.ts.map +1 -1
- package/dist/bridge/messages/init.js +8 -4
- package/dist/bridge/messages/initResult.d.ts +29 -0
- package/dist/bridge/messages/initResult.d.ts.map +1 -0
- package/dist/bridge/messages/initResult.js +25 -0
- package/dist/bridge/messages/sandboxToHost.d.ts +21 -6
- package/dist/bridge/messages/sandboxToHost.d.ts.map +1 -1
- package/dist/bridge/messages/sandboxToHost.js +4 -2
- package/dist/bridge/sandboxClient.d.ts +2 -4
- package/dist/bridge/sandboxClient.d.ts.map +1 -1
- package/dist/bridge/sandboxClient.js +2 -5
- package/dist/customBlock.d.ts +1 -1
- package/dist/customBlock.d.ts.map +1 -1
- package/dist/customBlock.js +1 -1
- package/dist/host/createCustomBlockHost.d.ts +7 -4
- package/dist/host/createCustomBlockHost.d.ts.map +1 -1
- package/dist/host/createCustomBlockHost.js +215 -38
- package/dist/host/lifecycle/initErrors.d.ts +1 -1
- package/dist/host/lifecycle/initErrors.d.ts.map +1 -1
- package/dist/host/lifecycle/initErrors.js +25 -7
- package/dist/host/lifecycle/{ready.d.ts → protocolVersion.d.ts} +1 -1
- package/dist/host/lifecycle/protocolVersion.d.ts.map +1 -0
- package/dist/host/lifecycle/types.d.ts +6 -4
- package/dist/host/lifecycle/types.d.ts.map +1 -1
- package/dist/host/messages/invalidSandboxMessage.js +0 -3
- package/dist/host.d.ts +5 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +2 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/init.d.ts +7 -7
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +70 -50
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/standalonePreview.d.ts.map +1 -1
- package/dist/react/standalonePreview.js +2 -0
- package/dist/react/useCustomBlockInit.d.ts +5 -6
- package/dist/react/useCustomBlockInit.d.ts.map +1 -1
- package/dist/react/useCustomBlockInit.js +3 -19
- package/dist/react/useRuntimeState.d.ts +4 -3
- package/dist/react/useRuntimeState.d.ts.map +1 -1
- package/dist/react/useRuntimeState.js +3 -2
- package/dist/version.js +1 -1
- package/docs/data-sources.md +10 -8
- package/docs/errors.md +5 -1
- package/docs/lifecycle.md +19 -31
- package/docs/manifest.md +1 -1
- package/package.json +1 -1
- package/src/bridge/SandboxBridge.ts +138 -44
- package/src/bridge/dataSources/resolve.ts +3 -14
- package/src/bridge/hostState.ts +2 -0
- package/src/bridge/loadManifest.ts +6 -6
- package/src/bridge/manifest.ts +3 -3
- package/src/bridge/messages/connect.ts +42 -0
- package/src/bridge/messages/init.ts +24 -10
- package/src/bridge/messages/initResult.ts +37 -0
- package/src/bridge/messages/sandboxToHost.ts +4 -2
- package/src/bridge/sandboxClient.ts +3 -8
- package/src/customBlock.ts +2 -2
- package/src/host/createCustomBlockHost.ts +265 -45
- package/src/host/lifecycle/initErrors.ts +25 -7
- package/src/host/lifecycle/types.ts +13 -4
- package/src/host/messages/invalidSandboxMessage.ts +0 -3
- package/src/host.ts +13 -2
- package/src/index.ts +3 -1
- package/src/init.ts +73 -60
- package/src/react/index.ts +0 -1
- package/src/react/standalonePreview.ts +2 -0
- package/src/react/useCustomBlockInit.ts +6 -27
- package/src/react/useRuntimeState.ts +4 -3
- package/dist/bridge/messages/ready.d.ts.map +0 -1
- package/dist/bridge/messages/ready.js +0 -43
- package/dist/host/lifecycle/ready.d.ts.map +0 -1
- package/src/bridge/messages/ready.ts +0 -48
- /package/dist/host/lifecycle/{ready.js → protocolVersion.js} +0 -0
- /package/src/host/lifecycle/{ready.ts → protocolVersion.ts} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -22,8 +22,8 @@ export type { NotionCreatePagePosition } from "./bridge/messages/createPage.js";
|
|
|
22
22
|
export type { CustomBlockCreatePageErrorCode, CustomBlockCreatePageErrorInfo, } from "./bridge/messages/createPageResult.js";
|
|
23
23
|
export type { CustomBlockGetPageErrorCode, CustomBlockGetPageErrorInfo, } from "./bridge/messages/getPage.js";
|
|
24
24
|
export type { CustomBlockGetUserErrorCode, CustomBlockGetUserErrorInfo, } from "./bridge/messages/getUser.js";
|
|
25
|
-
export type { CustomBlockInitErrorCode, CustomBlockInitErrorInfo, } from "./bridge/messages/init.js";
|
|
26
|
-
export {
|
|
25
|
+
export type { CustomBlockInitErrorCode, CustomBlockInitErrorInfo, CustomBlockInitializationErrorCode, CustomBlockInitializationErrorInfo, } from "./bridge/messages/init.js";
|
|
26
|
+
export { CustomBlockInitializationError } from "./bridge/messages/init.js";
|
|
27
27
|
export type { CustomBlockListUsersErrorCode, CustomBlockListUsersErrorInfo, } from "./bridge/messages/listUsers.js";
|
|
28
28
|
export type { CustomBlockQueryDataSourceErrorCode, CustomBlockQueryDataSourceErrorInfo, } from "./bridge/messages/queryDataSourceResult.js";
|
|
29
29
|
export type { CustomBlockUpdatePageErrorCode, CustomBlockUpdatePageErrorInfo, } from "./bridge/messages/updatePageResult.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,oCAAoC,CAAA;AAC3C,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAA;AACpF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EACX,wCAAwC,EACxC,wCAAwC,GACxC,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,YAAY,EACX,4BAA4B,EAC5B,4BAA4B,GAC5B,MAAM,yCAAyC,CAAA;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,YAAY,EACX,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC/E,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,wBAAwB,EACxB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,oCAAoC,CAAA;AAC3C,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAA;AACpF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EACX,wCAAwC,EACxC,wCAAwC,GACxC,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,YAAY,EACX,4BAA4B,EAC5B,4BAA4B,GAC5B,MAAM,yCAAyC,CAAA;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,YAAY,EACX,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC/E,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,wBAAwB,EACxB,wBAAwB,EACxB,kCAAkC,EAClC,kCAAkC,GAClC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAA;AAC1E,YAAY,EACX,6BAA6B,EAC7B,6BAA6B,GAC7B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,mCAAmC,EACnC,mCAAmC,GACnC,MAAM,4CAA4C,CAAA;AACnD,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,0BAA0B,EAC1B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACN,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,eAAe,EACf,gBAAgB,GAChB,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* should import hooks and components from `@notionhq/custom-blocks/react`.
|
|
8
8
|
*/
|
|
9
9
|
export { NOTION_BUILTIN_PROPERTY_IDS, NOTION_PROPERTY_TYPES, } from "./bridge/dataSources/propertySchema.js";
|
|
10
|
-
export {
|
|
10
|
+
export { CustomBlockInitializationError } from "./bridge/messages/init.js";
|
|
11
11
|
export { pages, users } from "./bridge/sandboxClient.js";
|
|
12
12
|
export { customBlock } from "./customBlock.js";
|
|
13
13
|
export { initCustomBlock, NotInIframeError, } from "./init.js";
|
package/dist/init.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { NotionDataSource } from "./bridge/dataSources/dataSource.js";
|
|
2
2
|
import type { NotionBlockId } from "./bridge/ids.js";
|
|
3
|
-
import {
|
|
3
|
+
import { CustomBlockInitializationError } from "./bridge/messages/init.js";
|
|
4
4
|
import type { CustomBlockPage } from "./bridge/pages/page.js";
|
|
5
5
|
import type { NotionParent } from "./bridge/parent.js";
|
|
6
6
|
import type { NotionTheme } from "./bridge/theme.js";
|
|
7
7
|
import type { NotionUser } from "./bridge/users/user.js";
|
|
8
8
|
/**
|
|
9
|
-
* The payload sent by the host in the `init` message in response to the sandbox's `
|
|
9
|
+
* The payload sent by the host in the `init` message in response to the sandbox's `connect` message.
|
|
10
10
|
*/
|
|
11
11
|
export type CustomBlockInitPayload = {
|
|
12
12
|
theme: NotionTheme;
|
|
@@ -22,10 +22,9 @@ export type CustomBlockInitPayload = {
|
|
|
22
22
|
* `<NotionCustomBlock>` catches this specifically and falls back to a standalone preview with a
|
|
23
23
|
* warning banner. Direct callers can `instanceof` it to apply their own policy.
|
|
24
24
|
*/
|
|
25
|
-
export declare class NotInIframeError extends
|
|
25
|
+
export declare class NotInIframeError extends CustomBlockInitializationError {
|
|
26
26
|
constructor(message?: string);
|
|
27
|
-
code:
|
|
28
|
-
isRetryable: boolean;
|
|
27
|
+
code: "not_in_iframe";
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* Options for {@link initCustomBlock}.
|
|
@@ -41,9 +40,10 @@ export type InitCustomBlockOptions = {
|
|
|
41
40
|
};
|
|
42
41
|
/**
|
|
43
42
|
* Performs the SDK <-> host handshake: loads `custom_blocks.json`, posts
|
|
44
|
-
* `
|
|
43
|
+
* `connect`, then awaits the host's `init` message. Resolves after the sandbox
|
|
44
|
+
* applies the payload and returns `initResult.success`.
|
|
45
45
|
*
|
|
46
|
-
* Rejects with a `
|
|
46
|
+
* Rejects with a `CustomBlockInitializationError` if initialization fails.
|
|
47
47
|
*
|
|
48
48
|
* Idempotent: subsequent calls return the same promise as the first and ignore any new options.
|
|
49
49
|
* Mount your React tree (or call any SDK hook / `customBlock.subscribe`) only after the
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAA;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGxD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACpC,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,UAAU,CAAA;IACvB,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,8BAA8B;gBACvD,OAAO,GAAE,MAA8B;IAS3C,IAAI,EAAE,eAAe,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACpC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC9B,IAAI,GAAE,sBAA2B,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CAKjC"}
|
package/dist/init.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { loadManifest } from "./bridge/loadManifest.js";
|
|
2
|
-
import {
|
|
2
|
+
import { CustomBlockInitializationError } from "./bridge/messages/init.js";
|
|
3
3
|
import { customBlockHost } from "./bridge/sandboxClient.js";
|
|
4
|
+
import { unreachable } from "./utils.js";
|
|
4
5
|
/**
|
|
5
6
|
* Error thrown when the SDK is loaded in a top-level standalone window with no parent frame.
|
|
6
7
|
* `postMessage` would just hit the same window and the handshake can never complete.
|
|
7
8
|
* `<NotionCustomBlock>` catches this specifically and falls back to a standalone preview with a
|
|
8
9
|
* warning banner. Direct callers can `instanceof` it to apply their own policy.
|
|
9
10
|
*/
|
|
10
|
-
export class NotInIframeError extends
|
|
11
|
+
export class NotInIframeError extends CustomBlockInitializationError {
|
|
11
12
|
constructor(message = NOT_IN_IFRAME_MESSAGE) {
|
|
12
|
-
super(
|
|
13
|
+
super({
|
|
14
|
+
code: "not_in_iframe",
|
|
15
|
+
message,
|
|
16
|
+
isRetryable: false,
|
|
17
|
+
});
|
|
13
18
|
this.name = "NotInIframeError";
|
|
14
|
-
this.code = "not_in_iframe";
|
|
15
|
-
this.isRetryable = false;
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
21
|
const DEFAULT_INIT_TIMEOUT_MS = 15000;
|
|
@@ -20,9 +23,10 @@ const NOT_IN_IFRAME_MESSAGE = "<NotionCustomBlock> only works inside an iframe
|
|
|
20
23
|
let initPromise;
|
|
21
24
|
/**
|
|
22
25
|
* Performs the SDK <-> host handshake: loads `custom_blocks.json`, posts
|
|
23
|
-
* `
|
|
26
|
+
* `connect`, then awaits the host's `init` message. Resolves after the sandbox
|
|
27
|
+
* applies the payload and returns `initResult.success`.
|
|
24
28
|
*
|
|
25
|
-
* Rejects with a `
|
|
29
|
+
* Rejects with a `CustomBlockInitializationError` if initialization fails.
|
|
26
30
|
*
|
|
27
31
|
* Idempotent: subsequent calls return the same promise as the first and ignore any new options.
|
|
28
32
|
* Mount your React tree (or call any SDK hook / `customBlock.subscribe`) only after the
|
|
@@ -30,54 +34,70 @@ let initPromise;
|
|
|
30
34
|
*/
|
|
31
35
|
export function initCustomBlock(opts = {}) {
|
|
32
36
|
if (initPromise === undefined) {
|
|
33
|
-
initPromise = (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (hostState.status !== "initialized") {
|
|
64
|
-
throw new CustomBlockInitError({
|
|
37
|
+
initPromise = initializeCustomBlock(opts);
|
|
38
|
+
}
|
|
39
|
+
return initPromise;
|
|
40
|
+
}
|
|
41
|
+
async function initializeCustomBlock(opts) {
|
|
42
|
+
try {
|
|
43
|
+
// Fail fast with a typed error when rendered as a standalone tab and not in a parent frame.
|
|
44
|
+
// Otherwise, it would eventually hit the timeout, since `postMessage` to `window.parent`
|
|
45
|
+
// would just hit the same window and never arrive.
|
|
46
|
+
if (typeof window !== "undefined" && window.parent === window) {
|
|
47
|
+
throw new NotInIframeError();
|
|
48
|
+
}
|
|
49
|
+
// Load the manifest and send it to the host.
|
|
50
|
+
const manifestResult = await loadManifest();
|
|
51
|
+
customBlockHost.sendConnect(manifestResult);
|
|
52
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_INIT_TIMEOUT_MS;
|
|
53
|
+
await awaitHostInitWithTimeout(timeoutMs);
|
|
54
|
+
const hostState = customBlockHost.getState();
|
|
55
|
+
switch (hostState.status) {
|
|
56
|
+
case "initialized":
|
|
57
|
+
return {
|
|
58
|
+
theme: hostState.theme,
|
|
59
|
+
blockId: hostState.blockId,
|
|
60
|
+
parent: hostState.parent,
|
|
61
|
+
page: hostState.page,
|
|
62
|
+
currentUser: hostState.currentUser,
|
|
63
|
+
dataSources: hostState.dataSources,
|
|
64
|
+
};
|
|
65
|
+
case "uninitialized":
|
|
66
|
+
throw new CustomBlockInitializationError({
|
|
65
67
|
code: "context_unavailable",
|
|
66
68
|
message: "Host block payload is unavailable.",
|
|
67
69
|
isRetryable: true,
|
|
68
70
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
default:
|
|
72
|
+
return unreachable(hostState);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error instanceof CustomBlockInitializationError) {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
throw new CustomBlockInitializationError({
|
|
81
|
+
code: "unknown_error",
|
|
82
|
+
message,
|
|
83
|
+
isRetryable: false,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function awaitHostInitWithTimeout(timeoutMs) {
|
|
88
|
+
try {
|
|
89
|
+
await customBlockHost.awaitInit(AbortSignal.timeout(timeoutMs));
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (isTimeoutError(error)) {
|
|
93
|
+
throw new CustomBlockInitializationError({
|
|
94
|
+
code: "init_timeout",
|
|
95
|
+
message: "Host did not respond to init before the timeout.",
|
|
96
|
+
isRetryable: true,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
79
100
|
}
|
|
80
|
-
return initPromise;
|
|
81
101
|
}
|
|
82
102
|
function isTimeoutError(error) {
|
|
83
103
|
return (typeof error === "object" &&
|
package/dist/react/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { NotionCustomBlock, type NotionCustomBlockProps, } from "./NotionCustomBlock.js";
|
|
10
10
|
export { useCustomBlockAutoResize } from "./useCustomBlockAutoResize.js";
|
|
11
|
-
export { type
|
|
11
|
+
export { type UseCustomBlockInitResult, useCustomBlockInit, } from "./useCustomBlockInit.js";
|
|
12
12
|
export { useDataSource } from "./useDataSource.js";
|
|
13
13
|
export { useBlockId, useCurrentUser, useManifest, usePage, useParent, useTheme, } from "./useRuntimeState.js";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,iBAAiB,EACjB,KAAK,sBAAsB,GAC3B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,iBAAiB,EACjB,KAAK,sBAAsB,GAC3B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EACN,KAAK,wBAAwB,EAC7B,kBAAkB,GAClB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EACN,UAAU,EACV,cAAc,EACd,WAAW,EACX,OAAO,EACP,SAAS,EACT,QAAQ,GACR,MAAM,sBAAsB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalonePreview.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/standalonePreview.ts"],"names":[],"mappings":"AAOA,wBAAgB,0BAA0B,
|
|
1
|
+
{"version":3,"file":"standalonePreview.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/standalonePreview.ts"],"names":[],"mappings":"AAOA,wBAAgB,0BAA0B,SAsBzC"}
|
|
@@ -6,11 +6,13 @@ const previewPageId = v.parse(notionPageIdSchema, "");
|
|
|
6
6
|
export function seedStandalonePreviewState() {
|
|
7
7
|
customBlockHost.setMockState({
|
|
8
8
|
type: "init",
|
|
9
|
+
initializationId: "standalone-preview",
|
|
9
10
|
status: "success",
|
|
10
11
|
theme: "light",
|
|
11
12
|
blockId: previewBlockId,
|
|
12
13
|
parent: { type: "page_id", page_id: previewPageId },
|
|
13
14
|
page: { id: previewPageId, parent: { type: "workspace", workspace: true } },
|
|
15
|
+
manifest: { version: 1, dataSources: {} },
|
|
14
16
|
dataSources: { bindings: {} },
|
|
15
17
|
currentUser: {
|
|
16
18
|
object: "user",
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type CustomBlockInitPayload, type InitCustomBlockOptions
|
|
3
|
-
export type CustomBlockInitFailure = CustomBlockInitError | NotInIframeError;
|
|
1
|
+
import type { CustomBlockInitializationError } from "../bridge/messages/init.js";
|
|
2
|
+
import { type CustomBlockInitPayload, type InitCustomBlockOptions } from "../init.js";
|
|
4
3
|
/**
|
|
5
4
|
* Discriminated state returned by {@link useCustomBlockInit}.
|
|
6
5
|
*
|
|
7
6
|
* Branch on `isLoaded`/`error`:
|
|
8
7
|
* - `{ isLoaded: false, error: undefined }` — handshake in progress.
|
|
9
|
-
* - `{ isLoaded: false, error:
|
|
10
|
-
* `
|
|
8
|
+
* - `{ isLoaded: false, error: CustomBlockInitializationError }` — handshake failed (most commonly a
|
|
9
|
+
* `CustomBlockInitializationError` with code `init_timeout` because the host never sent `init`).
|
|
11
10
|
* - `{ isLoaded: true, initial }` — handshake complete; safe to render
|
|
12
11
|
* children that call `useTheme`, `useBlockId`, etc.
|
|
13
12
|
*/
|
|
@@ -16,7 +15,7 @@ export type UseCustomBlockInitResult = {
|
|
|
16
15
|
error: undefined;
|
|
17
16
|
} | {
|
|
18
17
|
isLoaded: false;
|
|
19
|
-
error:
|
|
18
|
+
error: CustomBlockInitializationError;
|
|
20
19
|
} | {
|
|
21
20
|
isLoaded: true;
|
|
22
21
|
error: undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCustomBlockInit.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useCustomBlockInit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useCustomBlockInit.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useCustomBlockInit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAA;AAChF,OAAO,EACN,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAE3B,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GACjC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACrC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,8BAA8B,CAAA;CAAE,GAC1D;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,sBAAsB,CAAA;CAAE,CAAA;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,CAAC,EAAE,sBAAsB,GAC3B,wBAAwB,CA2B1B"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { initCustomBlock, NotInIframeError, } from "../init.js";
|
|
2
|
+
import { initCustomBlock, } from "../init.js";
|
|
4
3
|
/**
|
|
5
4
|
* React wrapper around {@link initCustomBlock}. Kicks off the SDK ↔ host
|
|
6
5
|
* handshake on mount and returns a discriminated state object so the rest of
|
|
@@ -29,12 +28,9 @@ export function useCustomBlockInit(opts) {
|
|
|
29
28
|
if (!cancelled) {
|
|
30
29
|
setState({ isLoaded: true, error: undefined, initial });
|
|
31
30
|
}
|
|
32
|
-
},
|
|
31
|
+
}, error => {
|
|
33
32
|
if (!cancelled) {
|
|
34
|
-
setState({
|
|
35
|
-
isLoaded: false,
|
|
36
|
-
error: normalizeInitError(err),
|
|
37
|
-
});
|
|
33
|
+
setState({ isLoaded: false, error });
|
|
38
34
|
}
|
|
39
35
|
});
|
|
40
36
|
return () => {
|
|
@@ -46,15 +42,3 @@ export function useCustomBlockInit(opts) {
|
|
|
46
42
|
}, []);
|
|
47
43
|
return state;
|
|
48
44
|
}
|
|
49
|
-
function normalizeInitError(error) {
|
|
50
|
-
if (error instanceof CustomBlockInitError ||
|
|
51
|
-
error instanceof NotInIframeError) {
|
|
52
|
-
return error;
|
|
53
|
-
}
|
|
54
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
55
|
-
return new CustomBlockInitError({
|
|
56
|
-
code: "unknown_error",
|
|
57
|
-
message,
|
|
58
|
-
isRetryable: false,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
@@ -54,13 +54,14 @@ export declare function useTheme(): NotionTheme;
|
|
|
54
54
|
*/
|
|
55
55
|
export declare function useCurrentUser(): NotionUser;
|
|
56
56
|
/**
|
|
57
|
-
* Returns the
|
|
57
|
+
* Returns the authoritative manifest received from the host — the semantic
|
|
58
58
|
* data-source keys plus their declared `name`, `description`, and property declarations.
|
|
59
|
-
*
|
|
59
|
+
*
|
|
60
|
+
* Throws if called before `initCustomBlock` has resolved.
|
|
60
61
|
*
|
|
61
62
|
* This is the configuration the block declared, not host-resolved bindings: use
|
|
62
63
|
* `useDataSource(key)` for rows and resolved schema. Handy for enumerating the declared
|
|
63
64
|
* data-source keys (e.g. picking a default key, or rendering a key switcher).
|
|
64
65
|
*/
|
|
65
|
-
export declare function useManifest(): CustomBlockManifest
|
|
66
|
+
export declare function useManifest(): CustomBlockManifest;
|
|
66
67
|
//# sourceMappingURL=useRuntimeState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRuntimeState.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useRuntimeState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAGzD;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,aAAa,CAE1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAExC;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,eAAe,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,IAAI,WAAW,CAEtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAE3C;AAED
|
|
1
|
+
{"version":3,"file":"useRuntimeState.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useRuntimeState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAGzD;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,aAAa,CAE1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAExC;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,eAAe,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,IAAI,WAAW,CAEtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAE3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,IAAI,mBAAmB,CAEjD"}
|
|
@@ -60,9 +60,10 @@ export function useCurrentUser() {
|
|
|
60
60
|
return useSyncExternalStore(customBlock.subscribe, customBlock.getCurrentUser);
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
* Returns the
|
|
63
|
+
* Returns the authoritative manifest received from the host — the semantic
|
|
64
64
|
* data-source keys plus their declared `name`, `description`, and property declarations.
|
|
65
|
-
*
|
|
65
|
+
*
|
|
66
|
+
* Throws if called before `initCustomBlock` has resolved.
|
|
66
67
|
*
|
|
67
68
|
* This is the configuration the block declared, not host-resolved bindings: use
|
|
68
69
|
* `useDataSource(key)` for rows and resolved schema. Handy for enumerating the declared
|
package/dist/version.js
CHANGED
package/docs/data-sources.md
CHANGED
|
@@ -61,24 +61,26 @@ Query failures follow the SDK's [error-handling contract](./errors.md).
|
|
|
61
61
|
### `useManifest()`
|
|
62
62
|
|
|
63
63
|
```ts
|
|
64
|
-
function useManifest(): CustomBlockManifest
|
|
64
|
+
function useManifest(): CustomBlockManifest;
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Returns the
|
|
67
|
+
Returns the authoritative block manifest received from the host during initialization, including the semantic data source keys plus their declared `name`, `description`, and property declarations. Handy for enumerating declared keys:
|
|
68
68
|
|
|
69
69
|
```tsx
|
|
70
70
|
const manifest = useManifest();
|
|
71
|
-
const keys = Object.keys(manifest
|
|
71
|
+
const keys = Object.keys(manifest.dataSources);
|
|
72
72
|
const activeKey = keys[0] ?? "default";
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
This API throws if called before initialization. This does not include host-resolved bindings nor does it include any actual data rows.
|
|
76
|
+
|
|
75
77
|
### `customBlock.getManifest()`
|
|
76
78
|
|
|
77
79
|
```ts
|
|
78
|
-
function customBlock.getManifest(): CustomBlockManifest
|
|
80
|
+
function customBlock.getManifest(): CustomBlockManifest;
|
|
79
81
|
```
|
|
80
82
|
|
|
81
|
-
Framework-neutral getter for the same manifest returned by `useManifest()`. The manifest is static for the lifetime of the sandbox, so there is nothing to subscribe to.
|
|
83
|
+
Framework-neutral getter for the same manifest returned by `useManifest()`. Throws if called before `initCustomBlock()` resolves. The manifest is static for the lifetime of the sandbox, so there is nothing to subscribe to.
|
|
82
84
|
|
|
83
85
|
```ts
|
|
84
86
|
await initCustomBlock();
|
|
@@ -113,8 +115,8 @@ export function ScoreList() {
|
|
|
113
115
|
if (error) return <div role="alert">Couldn't load: {error.message}</div>;
|
|
114
116
|
if (isLoading && items.length === 0) return <div>Loading…</div>;
|
|
115
117
|
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
+
const displayItems = items.filter(isComplete);
|
|
119
|
+
if (displayItems.length === 0) {
|
|
118
120
|
return (
|
|
119
121
|
<div>
|
|
120
122
|
Map a data source with key <code>{KEY}</code> exposing <code>name</code>{" "}
|
|
@@ -126,7 +128,7 @@ export function ScoreList() {
|
|
|
126
128
|
return (
|
|
127
129
|
<div>
|
|
128
130
|
<ul>
|
|
129
|
-
{
|
|
131
|
+
{displayItems.map((item) => (
|
|
130
132
|
<li key={item.id}>
|
|
131
133
|
{String(item.propertiesByKey.name)} —{" "}
|
|
132
134
|
{Number(item.propertiesByKey.score)}
|
package/docs/errors.md
CHANGED
|
@@ -35,7 +35,11 @@ Each API narrows `code` to its own open string union. The known literals provide
|
|
|
35
35
|
|
|
36
36
|
## Initialization errors
|
|
37
37
|
|
|
38
|
-
Unlike request helpers, `initCustomBlock` rejects with `
|
|
38
|
+
Unlike request helpers, `initCustomBlock` rejects with `CustomBlockInitializationError`. Its `code` type is `CustomBlockInitializationErrorCode`, which covers failures reported by either side of the handshake plus SDK-local timeout and iframe errors.
|
|
39
|
+
|
|
40
|
+
`CustomBlockInitializationErrorInfo` is the matching `{ code, message, isRetryable }` object type.
|
|
41
|
+
|
|
42
|
+
Host implementers use the narrower message-specific types: `CustomBlockInitErrorInfo` for `init.error` and `CustomBlockInitResultErrorInfo` for `initResult.error`.
|
|
39
43
|
|
|
40
44
|
See [Lifecycle and initialization](./lifecycle.md) for initialization-specific error codes.
|
|
41
45
|
|
package/docs/lifecycle.md
CHANGED
|
@@ -4,9 +4,15 @@ The SDK ↔ host handshake, the React wrapper that runs it, and the auto-resize
|
|
|
4
4
|
|
|
5
5
|
## Handshake
|
|
6
6
|
|
|
7
|
-
`initCustomBlock()`
|
|
7
|
+
`initCustomBlock()` completes a three-message handshake:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
1. The SDK sends `connect` with a new initialization ID and some version info.
|
|
10
|
+
2. The host replies with `init`, echoing that initialization ID and providing the manifest, block context, current user, and data source bindings.
|
|
11
|
+
3. The SDK confirms that state is compatible and sends `initResult` with the same initialization ID.
|
|
12
|
+
|
|
13
|
+
The promise resolves only after the SDK sends `initResult.success`. Await it before mounting React so hooks always see initialized state.
|
|
14
|
+
|
|
15
|
+
- Rejects with `CustomBlockInitializationError` code `init_timeout` if the host doesn't respond.
|
|
10
16
|
- In a top-level browser tab (no parent frame), rejects with `NotInIframeError` code `not_in_iframe`. `<NotionCustomBlock>` catches this, seeds placeholders, and renders `children` behind a warning banner so dev-time previews still work.
|
|
11
17
|
- After init, `*Changed` events (e.g. `themeChanged`, `parentChanged`, `dataSourcesChanged`) push updates and the relevant hooks re-render.
|
|
12
18
|
- `initCustomBlock` is idempotent; subsequent calls return the same promise.
|
|
@@ -44,7 +50,7 @@ function useCustomBlockInit(
|
|
|
44
50
|
|
|
45
51
|
type UseCustomBlockInitResult =
|
|
46
52
|
| { isLoaded: false; error: undefined }
|
|
47
|
-
| { isLoaded: false; error:
|
|
53
|
+
| { isLoaded: false; error: CustomBlockInitializationError }
|
|
48
54
|
| { isLoaded: true; error: undefined; initial: CustomBlockInitPayload };
|
|
49
55
|
```
|
|
50
56
|
|
|
@@ -69,39 +75,21 @@ function initCustomBlock(
|
|
|
69
75
|
type InitCustomBlockOptions = { timeoutMs?: number };
|
|
70
76
|
```
|
|
71
77
|
|
|
72
|
-
The lower-level promise API. `<NotionCustomBlock>` and `useCustomBlockInit` both call it for you. Reach for it directly only when you want to `await` init at module scope (e.g. before `ReactDOM.createRoot`).
|
|
78
|
+
The lower-level promise API. `<NotionCustomBlock>` and `useCustomBlockInit` both call it for you. Reach for it directly only when you want to `await` init at module scope (e.g. before `ReactDOM.createRoot`). Expected failures reject with `CustomBlockInitializationError`.
|
|
73
79
|
|
|
74
|
-
### `
|
|
80
|
+
### `CustomBlockInitializationError`
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
class CustomBlockInitError extends Error {
|
|
78
|
-
code: CustomBlockInitErrorCode;
|
|
79
|
-
isRetryable: boolean;
|
|
80
|
-
}
|
|
82
|
+
The code tells you where initialization failed:
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| "manifest_unavailable"
|
|
86
|
-
| "manifest_invalid"
|
|
87
|
-
| "invalid_protocol_version"
|
|
88
|
-
| "unsupported_protocol_version"
|
|
89
|
-
| "context_unavailable"
|
|
90
|
-
| "current_user_unavailable"
|
|
91
|
-
| "missing_data_source_binding"
|
|
92
|
-
| "data_source_unavailable"
|
|
93
|
-
| "missing_property_binding"
|
|
94
|
-
| "invalid_property_binding"
|
|
95
|
-
| "not_in_iframe"
|
|
96
|
-
| "init_timeout"
|
|
97
|
-
| "unknown_error";
|
|
98
|
-
```
|
|
84
|
+
- `CustomBlockInitErrorCode`: the host rejected initialization in `init.error`.
|
|
85
|
+
- `CustomBlockInitResultErrorCode`: the SDK could not apply the host's state and reported why in `initResult.error`.
|
|
86
|
+
- `not_in_iframe` and `init_timeout`: the SDK failed before the handshake completed.
|
|
99
87
|
|
|
100
|
-
|
|
88
|
+
All code types are open string unions, so keep a default branch. Use `isRetryable` to decide whether offering a retry makes sense, and treat `message` as display text rather than a stable identifier. See [Error handling](./errors.md) for the shared error contract.
|
|
101
89
|
|
|
102
90
|
### `customBlock`
|
|
103
91
|
|
|
104
|
-
Framework-neutral runtime APIs for renderers that do not use React hooks. `customBlock.getState()` returns a `CustomBlockState` snapshot that hides internal query cache details. Initialized-only getters (`getTheme`, `getBlockId`, `getParent
|
|
92
|
+
Framework-neutral runtime APIs for renderers that do not use React hooks. `customBlock.getState()` returns a `CustomBlockState` snapshot that hides internal query cache details. Initialized-only getters (e.g. `getTheme`, `getBlockId`, `getParent`) throw until `initCustomBlock()` resolves.
|
|
105
93
|
|
|
106
94
|
`customBlock` covers runtime state and sizing. Row querying still goes through `useDataSource`, while imperative APIs such as `pages.*` and `users.*` are already framework-neutral functions.
|
|
107
95
|
|
|
@@ -127,7 +115,7 @@ stopAutoResize();
|
|
|
127
115
|
|
|
128
116
|
### `NotInIframeError`
|
|
129
117
|
|
|
130
|
-
Thrown when `initCustomBlock` is called in a top-level tab (no parent frame). It has `code: "not_in_iframe"` and `isRetryable: false`. `<NotionCustomBlock>` catches it and falls back to a standalone preview with a warning banner
|
|
118
|
+
Thrown when `initCustomBlock` is called in a top-level tab (no parent frame). It extends `CustomBlockInitializationError`, has `code: "not_in_iframe"` and `isRetryable: false`, and can be detected specifically with `instanceof NotInIframeError`. `<NotionCustomBlock>` catches it and falls back to a standalone preview with a warning banner.
|
|
131
119
|
|
|
132
120
|
### `useCustomBlockAutoResize({ enabled? })`
|
|
133
121
|
|
|
@@ -154,7 +142,7 @@ function App() {
|
|
|
154
142
|
Press `\` while focused in a custom block to toggle a debug overlay that replaces the block's children with a `<pre>` log of every `postMessage` sent and received over the bridge. Each line is formatted as:
|
|
155
143
|
|
|
156
144
|
```
|
|
157
|
-
[ISO timestamp] sent/received: {"type":"
|
|
145
|
+
[ISO timestamp] sent/received: {"type":"connect", …}
|
|
158
146
|
```
|
|
159
147
|
|
|
160
148
|
The log is intentionally plain — no filtering or decoration — so it can be copied and pasted directly to a local coding agent for debugging.
|
package/docs/manifest.md
CHANGED
|
@@ -18,7 +18,7 @@ A custom block declares its required data sources in `custom_blocks.json` at the
|
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`initCustomBlock()` fetches the manifest and forwards it with `
|
|
21
|
+
`initCustomBlock()` fetches the manifest and forwards it with `connect`. 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 omits `manifest` from `connect`. If the file is unavailable for another reason or invalid, the SDK sends `connect` with `status: "error"` and an `error` payload. The host returns its authoritative manifest in `init`. The SDK uses that manifest even when it differs from the manifest sent in `connect`.
|
|
22
22
|
|
|
23
23
|
## Vite plugin
|
|
24
24
|
|