@notionhq/custom-blocks 0.1.32 → 0.1.33

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.
@@ -58,6 +58,7 @@ export declare class SandboxBridge {
58
58
  */
59
59
  setMockState(message: InitMessage): void;
60
60
  completeInitialization(): void;
61
+ private sendInitResultError;
61
62
  private applyInit;
62
63
  /**
63
64
  * Lets the initial application render commit before we acknowledge init. The host keeps the
@@ -1 +1 @@
1
- {"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/SandboxBridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/SandboxBridge.ts"],"names":[],"mappings":"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"}
@@ -53,6 +53,14 @@ export class SandboxBridge {
53
53
  if (!parsed.success) {
54
54
  console.warn("[custom-blocks-sdk] ignoring malformed host message", parsed.issues);
55
55
  const incomingType = readIncomingType(event.data);
56
+ if (!this.hasReceivedInit &&
57
+ incomingType === "init" &&
58
+ this.initializationId !== undefined &&
59
+ readInitializationId(event.data) === this.initializationId) {
60
+ this.hasReceivedInit = true;
61
+ this.sendInitResultError(invalidInitPayloadError(parsed.issues));
62
+ return;
63
+ }
56
64
  // Loop guard: never NACK a NACK. Excludes both directions —
57
65
  // `invalidSandboxMessage` is what the host normally sends, but
58
66
  // a buggy host that echoes our own `invalidHostMessage` back
@@ -400,6 +408,24 @@ export class SandboxBridge {
400
408
  this.postToHost(result);
401
409
  this.flushPendingOutboundMessages();
402
410
  }
411
+ sendInitResultError(error) {
412
+ if (this.hasSentInitResult || this.initializationId === undefined) {
413
+ return;
414
+ }
415
+ const result = {
416
+ type: "initResult",
417
+ initializationId: this.initializationId,
418
+ status: "error",
419
+ error,
420
+ };
421
+ this.hasSentInitResult = true;
422
+ this.postToHost(result);
423
+ if (this.rejectInit) {
424
+ this.rejectInit(new CustomBlockInitializationError(error));
425
+ this.resolveInit = undefined;
426
+ this.rejectInit = undefined;
427
+ }
428
+ }
403
429
  applyInit(message, postResult) {
404
430
  if (postResult) {
405
431
  this.isMockState = false;
@@ -429,18 +455,7 @@ export class SandboxBridge {
429
455
  : resolveMockDataSources(this.latestDataSourceBindings);
430
456
  const bindingError = getInitBindingError(message.manifest, dataSources);
431
457
  if (postResult && bindingError !== undefined) {
432
- const result = {
433
- type: "initResult",
434
- initializationId: message.initializationId,
435
- status: "error",
436
- error: bindingError,
437
- };
438
- this.postToHost(result);
439
- if (this.rejectInit) {
440
- this.rejectInit(new CustomBlockInitializationError(bindingError));
441
- this.resolveInit = undefined;
442
- this.rejectInit = undefined;
443
- }
458
+ this.sendInitResultError(bindingError);
444
459
  return;
445
460
  }
446
461
  this.hostState = {
@@ -840,6 +855,22 @@ function makeDataSourceSubscriptionId(args) {
840
855
  const { key } = args;
841
856
  return `data-source:${encodeURIComponent(key)}`;
842
857
  }
858
+ function invalidInitPayloadError(issues) {
859
+ return {
860
+ code: "invalid_init_payload",
861
+ message: formatInvalidHostReason("init", issues),
862
+ isRetryable: false,
863
+ };
864
+ }
865
+ function readInitializationId(data) {
866
+ if (typeof data === "object" &&
867
+ data !== null &&
868
+ "initializationId" in data &&
869
+ typeof data.initializationId === "string") {
870
+ return data.initializationId;
871
+ }
872
+ return undefined;
873
+ }
843
874
  function getInitBindingError(manifest, dataSources) {
844
875
  for (const [dataSourceKey, manifestDataSource] of Object.entries(manifest.dataSources)) {
845
876
  const dataSource = dataSources.find(entry => entry.key === dataSourceKey);
@@ -2,7 +2,7 @@ import * as v from "valibot";
2
2
  import type { CustomBlockErrorCode, CustomBlockErrorInfo } from "../errors.js";
3
3
  import type { CustomBlockInitResultErrorCode } from "./initResult.js";
4
4
  export declare const customBlockInitErrorCodeSchema: v.StringSchema<undefined>;
5
- export type CustomBlockInitErrorCode = CustomBlockErrorCode<"manifest_unavailable" | "manifest_invalid" | "invalid_protocol_version" | "unsupported_protocol_version" | "context_unavailable" | "current_user_unavailable" | "missing_data_source_binding" | "data_source_unavailable" | "missing_property_binding" | "invalid_property_binding">;
5
+ export type CustomBlockInitErrorCode = CustomBlockErrorCode<"manifest_unavailable" | "manifest_invalid" | "invalid_connect_payload" | "invalid_protocol_version" | "unsupported_protocol_version" | "context_unavailable" | "current_user_unavailable" | "missing_data_source_binding" | "data_source_unavailable" | "missing_property_binding" | "invalid_property_binding">;
6
6
  export type CustomBlockInitErrorInfo = CustomBlockErrorInfo<CustomBlockInitErrorCode>;
7
7
  /**
8
8
  * Every initialization failure visible to block code. This combines errors
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/protocol/src/messages/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAG5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAO9E,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAA;AAIrE,eAAO,MAAM,8BAA8B,2BAAa,CAAA;AAExD,MAAM,MAAM,wBAAwB,GAAG,oBAAoB,CACxD,sBAAsB,GACtB,kBAAkB,GAClB,0BAA0B,GAC1B,8BAA8B,GAC9B,qBAAqB,GACrB,0BAA0B,GAC1B,6BAA6B,GAC7B,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,CAC5B,CAAA;AAED,MAAM,MAAM,wBAAwB,GACnC,oBAAoB,CAAC,wBAAwB,CAAC,CAAA;AAE/C;;;;GAIG;AACH,MAAM,MAAM,kCAAkC,GAC3C,wBAAwB,GACxB,8BAA8B,GAC9B,oBAAoB,CAAC,eAAe,GAAG,cAAc,CAAC,CAAA;AAEzD,MAAM,MAAM,kCAAkC,GAC7C,oBAAoB,CAAC,kCAAkC,CAAC,CAAA;AAEzD,eAAO,MAAM,8BAA8B;;;;aAIzC,CAAA;AAEF,qBAAa,8BACZ,SAAQ,KACR,YAAW,oBAAoB;gBAEnB,KAAK,EAAE,kCAAkC;IAOrD,IAAI,EAAE,kCAAkC,CAAA;IACxC,WAAW,EAAE,OAAO,CAAA;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAuB5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/protocol/src/messages/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAG5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAO9E,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAA;AAIrE,eAAO,MAAM,8BAA8B,2BAAa,CAAA;AAExD,MAAM,MAAM,wBAAwB,GAAG,oBAAoB,CACxD,sBAAsB,GACtB,kBAAkB,GAClB,yBAAyB,GACzB,0BAA0B,GAC1B,8BAA8B,GAC9B,qBAAqB,GACrB,0BAA0B,GAC1B,6BAA6B,GAC7B,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,CAC5B,CAAA;AAED,MAAM,MAAM,wBAAwB,GACnC,oBAAoB,CAAC,wBAAwB,CAAC,CAAA;AAE/C;;;;GAIG;AACH,MAAM,MAAM,kCAAkC,GAC3C,wBAAwB,GACxB,8BAA8B,GAC9B,oBAAoB,CAAC,eAAe,GAAG,cAAc,CAAC,CAAA;AAEzD,MAAM,MAAM,kCAAkC,GAC7C,oBAAoB,CAAC,kCAAkC,CAAC,CAAA;AAEzD,eAAO,MAAM,8BAA8B;;;;aAIzC,CAAA;AAEF,qBAAa,8BACZ,SAAQ,KACR,YAAW,oBAAoB;gBAEnB,KAAK,EAAE,kCAAkC;IAOrD,IAAI,EAAE,kCAAkC,CAAA;IACxC,WAAW,EAAE,OAAO,CAAA;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAuB5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
@@ -1,7 +1,14 @@
1
1
  import * as v from "valibot";
2
2
  import type { CustomBlockErrorCode, CustomBlockErrorInfo } from "../errors.js";
3
3
  export declare const customBlockInitResultErrorCodeSchema: v.StringSchema<undefined>;
4
- export type CustomBlockInitResultErrorCode = CustomBlockErrorCode<"invalid_init_bindings">;
4
+ export type CustomBlockInitResultErrorCode = CustomBlockErrorCode<
5
+ /**
6
+ * The host-provided bindings defined in `init.dataSources` were rejected by the sandbox because
7
+ * they did not completely match the expected manifest keys.
8
+ */
9
+ "invalid_init_bindings"
10
+ /** The host-provided `init` payload failed to parse. */
11
+ | "invalid_init_payload">;
5
12
  export type CustomBlockInitResultErrorInfo = CustomBlockErrorInfo<CustomBlockInitResultErrorCode>;
6
13
  export declare const customBlockInitResultErrorInfoSchema: v.ObjectSchema<{
7
14
  readonly code: v.StringSchema<undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"initResult.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/protocol/src/messages/initResult.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAI9E,eAAO,MAAM,oCAAoC,2BAAa,CAAA;AAE9D,MAAM,MAAM,8BAA8B,GACzC,oBAAoB,CAAC,uBAAuB,CAAC,CAAA;AAE9C,MAAM,MAAM,8BAA8B,GACzC,oBAAoB,CAAC,8BAA8B,CAAC,CAAA;AAErD,eAAO,MAAM,oCAAoC;;;;aAI/C,CAAA;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;IAKlC,0EAA0E;;;;;;;;;;;0BAU1E,CAAA;AAEF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,uBAAuB,CAAC,CAAA"}
1
+ {"version":3,"file":"initResult.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/protocol/src/messages/initResult.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAI9E,eAAO,MAAM,oCAAoC,2BAAa,CAAA;AAE9D,MAAM,MAAM,8BAA8B,GAAG,oBAAoB;AAChE;;;GAGG;AACD,uBAAuB;AACzB,wDAAwD;GACtD,sBAAsB,CACxB,CAAA;AAED,MAAM,MAAM,8BAA8B,GACzC,oBAAoB,CAAC,8BAA8B,CAAC,CAAA;AAErD,eAAO,MAAM,oCAAoC;;;;aAI/C,CAAA;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;IAKlC,0EAA0E;;;;;;;;;;;0BAU1E,CAAA;AAEF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,uBAAuB,CAAC,CAAA"}
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  *
5
5
  * WARNING: Generated during SDK publish. Do not edit in the published package.
6
6
  */
7
- export const CUSTOM_BLOCKS_SDK_VERSION = "0.1.32"
7
+ export const CUSTOM_BLOCKS_SDK_VERSION = "0.1.33"
package/docs/errors.md CHANGED
@@ -39,6 +39,22 @@ Unlike request helpers, `initCustomBlock` rejects with `CustomBlockInitializatio
39
39
 
40
40
  `CustomBlockInitializationErrorInfo` is the matching `{ code, message, isRetryable }` object type.
41
41
 
42
+ Initialization errors have direction-specific meanings:
43
+
44
+ - `invalid_connect_payload` means that the host could not parse the SDK's
45
+ `connect` message. The host sends this code in `init.error` when it can read
46
+ the `initializationId`.
47
+ - `invalid_init_payload` means that the SDK could not parse the host's `init`
48
+ message. The SDK sends this code in `initResult.error` when it can read the
49
+ expected `initializationId`.
50
+ - `invalid_init_bindings` means that the SDK could not apply the data source
51
+ bindings in the host's valid `init` message. The SDK sends this code in
52
+ `initResult.error`.
53
+ - `invalid_init_result_payload` means that the host could not parse the SDK's
54
+ `initResult`. This is a host-local error. The SDK does not send this code.
55
+ - `no_init_result` means that the host did not receive a valid `initResult`
56
+ before its timeout.
57
+
42
58
  See [Lifecycle and initialization](./lifecycle.md) for initialization-specific error codes.
43
59
 
44
60
  ## Handling errors
package/docs/lifecycle.md CHANGED
@@ -1,27 +1,65 @@
1
1
  # Lifecycle
2
2
 
3
- The SDK host handshake, the React wrapper that runs it, and the auto-resize hook that keeps the iframe in sync with your content.
4
-
5
- ## Handshake
6
-
7
- `initCustomBlock()` handles three messages:
8
-
9
- 1. The SDK sends `connect` with a new initialization ID and version information.
10
- 2. The host sends `init`. It includes the same ID, the manifest, block context, current user, and data source bindings.
11
- 3. The SDK sends `initResult` with the ID and the initial block height.
12
-
13
- The promise resolves when the SDK applies the host state. Await it before React renders so hooks read initialized state. The SDK sends `initResult` after the initial render.
14
-
15
- - Rejects with `CustomBlockInitializationError` code `init_timeout` if the host doesn't respond.
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.
17
- - After init, compatible hosts use `*Changed` events (e.g. `themeChanged`, `contrastModeChanged`, `parentChanged`, `dataSourcesChanged`) to push updates and re-render the relevant hooks.
18
- - `initCustomBlock` is idempotent; subsequent calls return the same promise.
3
+ The SDK and host use a three-message `postMessage` handshake to initialize
4
+ a custom block.
5
+
6
+ This handshake can be completed with one of these APIs:
7
+
8
+ - `<NotionCustomBlock>` for most React blocks. It starts initialization and
9
+ renders `children` after the host state is ready.
10
+ - `useCustomBlockInit()` for React blocks that need to control loading and
11
+ error states.
12
+ - `initCustomBlock()` for framework-neutral code or code that must await
13
+ initialization before it renders.
14
+
15
+ Custom bridge integrations can also handle the `postMessage` wire messages
16
+ directly. This is advanced usage for host or integration authors.
17
+
18
+ ## Initialization protocol message
19
+
20
+ The full `postMessage` handshake is:
21
+
22
+ 1. The SDK sends `connect` with a new `initializationId` and version
23
+ information.
24
+ 2. The host sends `init` with the same `initializationId`, the manifest, data source bindings,
25
+ and additional block and app context.
26
+ 3. The SDK validates and applies `init`, renders the initial content, and sends
27
+ `initResult` with the same `initializationId` and the initial block height.
28
+
29
+ Both sides must check that the `initializationId` matches. The SDK ignores an
30
+ `init` with a different ID. It sends `initResult` only after it applies a
31
+ matching `init`.
32
+
33
+ The initialization promise resolves after the SDK applies the host state.
34
+ Await it before rendering code that reads initialized state. The SDK sends
35
+ `initResult` after the initial render.
36
+
37
+ - The promise rejects with `CustomBlockInitializationError` code
38
+ `init_timeout` if the host does not send a usable `init`.
39
+ - If a matching `init` is malformed, the SDK sends `initResult.error` with code
40
+ `invalid_init_payload` and rejects with the same structured error.
41
+ - If the host sends incomplete or invalid data source bindings, the SDK sends
42
+ `initResult.error` with code `invalid_init_bindings` and rejects with the same
43
+ structured error.
44
+ - If the SDK cannot correlate a malformed `init` to the handshake, it sends
45
+ `invalidHostMessage` when safe.
46
+ - After initialization, compatible hosts use `*Changed` messages to push live
47
+ updates.
48
+ - `initCustomBlock()` is idempotent. Later calls return the same promise.
49
+
50
+ ## Rendering inside a host
51
+
52
+ The SDK expects the custom block to run inside an iframe. In a top-level
53
+ browser tab, initialization rejects with `NotInIframeError` code
54
+ `not_in_iframe`.
55
+
56
+ `<NotionCustomBlock>` catches this error and renders a standalone preview with
57
+ a warning. This supports local development when no host is available.
19
58
 
20
59
  ## Sizing
21
60
 
22
- All blocks resize to fit their content. The Notion app limits block height to 10,000 pixels.
23
-
24
- To set a shorter height, set `max-height` and `overflow-y` on `#root`:
61
+ Custom blocks resize to fit their content by default. To set a shorter height, set
62
+ `max-height` and `overflow-y` on `#root`:
25
63
 
26
64
  ```css
27
65
  #root {
@@ -30,9 +68,25 @@ To set a shorter height, set `max-height` and `overflow-y` on `#root`:
30
68
  }
31
69
  ```
32
70
 
71
+ The Notion app enforces a maximum custom block height of 10,000 pixels.
72
+
73
+ The SDK measures the `#root` element and sends its initial height in
74
+ `initResult.success`. It sends later height changes in `resize` messages. The
75
+ host uses these messages to keep the iframe height in sync.
76
+
77
+ Using `<NotionCustomBlock>` enables this behavior automatically. Use
78
+ `customBlock.autoResize()` for a custom, framework-neutral initialization wrapper.
79
+
33
80
  ## API
34
81
 
35
- Import framework-neutral APIs from `@notionhq/custom-blocks`; import React hooks and components from `@notionhq/custom-blocks/react`. The runtime APIs below assume `initCustomBlock()` has resolved — initialized-only hooks and `customBlock` getters throw if called before that. Inside `<NotionCustomBlock>` (or past the `isLoaded` gate of `useCustomBlockInit`), single-value hooks return non-nullable values.
82
+ Import framework-neutral APIs from `@notionhq/custom-blocks`. Import React
83
+ hooks and components from `@notionhq/custom-blocks/react`.
84
+
85
+ The APIs below require successful initialization unless stated otherwise.
86
+ Initialized-only hooks and `customBlock` getters throw before
87
+ `initCustomBlock()` resolves. Inside `<NotionCustomBlock>`, or after the
88
+ `isLoaded` gate of `useCustomBlockInit`, single-value hooks return non-nullable
89
+ values.
36
90
 
37
91
  ### `<NotionCustomBlock>`
38
92
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/custom-blocks",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -258,6 +258,16 @@ export class SandboxBridge {
258
258
  parsed.issues,
259
259
  )
260
260
  const incomingType = readIncomingType(event.data)
261
+ if (
262
+ !this.hasReceivedInit &&
263
+ incomingType === "init" &&
264
+ this.initializationId !== undefined &&
265
+ readInitializationId(event.data) === this.initializationId
266
+ ) {
267
+ this.hasReceivedInit = true
268
+ this.sendInitResultError(invalidInitPayloadError(parsed.issues))
269
+ return
270
+ }
261
271
  // Loop guard: never NACK a NACK. Excludes both directions —
262
272
  // `invalidSandboxMessage` is what the host normally sends, but
263
273
  // a buggy host that echoes our own `invalidHostMessage` back
@@ -548,6 +558,25 @@ export class SandboxBridge {
548
558
  this.flushPendingOutboundMessages()
549
559
  }
550
560
 
561
+ private sendInitResultError(error: CustomBlockInitResultErrorInfo) {
562
+ if (this.hasSentInitResult || this.initializationId === undefined) {
563
+ return
564
+ }
565
+ const result: InitResultMessage = {
566
+ type: "initResult",
567
+ initializationId: this.initializationId,
568
+ status: "error",
569
+ error,
570
+ }
571
+ this.hasSentInitResult = true
572
+ this.postToHost(result)
573
+ if (this.rejectInit) {
574
+ this.rejectInit(new CustomBlockInitializationError(error))
575
+ this.resolveInit = undefined
576
+ this.rejectInit = undefined
577
+ }
578
+ }
579
+
551
580
  private applyInit(message: InitMessage, postResult: boolean) {
552
581
  if (postResult) {
553
582
  this.isMockState = false
@@ -581,18 +610,7 @@ export class SandboxBridge {
581
610
  : resolveMockDataSources(this.latestDataSourceBindings)
582
611
  const bindingError = getInitBindingError(message.manifest, dataSources)
583
612
  if (postResult && bindingError !== undefined) {
584
- const result: InitResultMessage = {
585
- type: "initResult",
586
- initializationId: message.initializationId,
587
- status: "error",
588
- error: bindingError,
589
- }
590
- this.postToHost(result)
591
- if (this.rejectInit) {
592
- this.rejectInit(new CustomBlockInitializationError(bindingError))
593
- this.resolveInit = undefined
594
- this.rejectInit = undefined
595
- }
613
+ this.sendInitResultError(bindingError)
596
614
  return
597
615
  }
598
616
  this.hostState = {
@@ -1066,6 +1084,28 @@ function makeDataSourceSubscriptionId(args: { key: string }): string {
1066
1084
  return `data-source:${encodeURIComponent(key)}`
1067
1085
  }
1068
1086
 
1087
+ function invalidInitPayloadError(
1088
+ issues: readonly v.BaseIssue<unknown>[],
1089
+ ): CustomBlockInitResultErrorInfo {
1090
+ return {
1091
+ code: "invalid_init_payload",
1092
+ message: formatInvalidHostReason("init", issues),
1093
+ isRetryable: false,
1094
+ }
1095
+ }
1096
+
1097
+ function readInitializationId(data: unknown): string | undefined {
1098
+ if (
1099
+ typeof data === "object" &&
1100
+ data !== null &&
1101
+ "initializationId" in data &&
1102
+ typeof data.initializationId === "string"
1103
+ ) {
1104
+ return data.initializationId
1105
+ }
1106
+ return undefined
1107
+ }
1108
+
1069
1109
  function getInitBindingError(
1070
1110
  manifest: CustomBlockManifest,
1071
1111
  dataSources: NotionDataSource[],