@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,8 +1,9 @@
1
1
  import * as v from "valibot"
2
2
  import { manifestSchema } from "../manifest.js"
3
3
 
4
- const readyMessageCommonEntries = {
5
- type: v.literal("ready"),
4
+ const connectMessageCommonEntries = {
5
+ type: v.literal("connect"),
6
+ initializationId: v.string(),
6
7
  /**
7
8
  * Used to ensure that the host and client are using the same version of the bridge protocol. A
8
9
  * single host needs to support multiple custom blocks built with different versions of the bridge
@@ -10,7 +11,7 @@ const readyMessageCommonEntries = {
10
11
  */
11
12
  bridgeProtocolVersion: v.number(),
12
13
  /**
13
- * Semver version of the SDK package that sent this ready message. Should only be used for
14
+ * Semver version of the SDK package that sent this connect message. Should only be used for
14
15
  * analytics purposes. Business logic should compare against `bridgeProtocolVersion` instead.
15
16
  */
16
17
  sdkVersion: v.string(),
@@ -18,31 +19,31 @@ const readyMessageCommonEntries = {
18
19
 
19
20
  // TODO(custom-blocks): Replace with `customBlockErrorInfoSchema` which makes `isRetryable` required
20
21
  // once min supported bridge protocol version is bumped to 3.
21
- const readyErrorSchema = v.object({
22
+ const connectErrorSchema = v.object({
22
23
  code: v.string(),
23
24
  message: v.string(),
24
25
  isRetryable: v.optional(v.boolean(), false),
25
26
  })
26
27
 
27
28
  /**
28
- * First message the sandbox sends after mount, kicking off the bridge handshake. The host replies
29
- * with `init`.
29
+ * First message the sandbox sends after mount. It identifies the sandbox and starts the bridge
30
+ * initialization exchange. The host echoes `initializationId` in its `init` response.
30
31
  */
31
- export const readyMessageSchema = v.union([
32
+ export const connectMessageSchema = v.variant("status", [
32
33
  v.object({
33
34
  status: v.literal("success"),
34
35
  /**
35
- * The data sources and settings the custom block expects, or null when the
36
- * block has no manifest and no declared data requirements.
36
+ * The data sources and settings the custom block expects. Hosts may omit
37
+ * this when they already have an authoritative manifest.
37
38
  */
38
- manifest: v.union([manifestSchema, v.null_()]),
39
- ...readyMessageCommonEntries,
39
+ manifest: v.optional(manifestSchema),
40
+ ...connectMessageCommonEntries,
40
41
  }),
41
42
  v.object({
42
43
  status: v.literal("error"),
43
- error: readyErrorSchema,
44
- ...readyMessageCommonEntries,
44
+ error: connectErrorSchema,
45
+ ...connectMessageCommonEntries,
45
46
  }),
46
47
  ])
47
48
 
48
- export type ReadyMessage = v.InferOutput<typeof readyMessageSchema>
49
+ export type ConnectMessage = v.InferOutput<typeof connectMessageSchema>
@@ -9,10 +9,7 @@ import { invalidSandboxMessageSchema } from "./invalidSandboxMessage.js"
9
9
  import { listUsersResultMessageSchema } from "./listUsers.js"
10
10
  import { pageChangedMessageSchema } from "./pageChanged.js"
11
11
  import { parentChangedMessageSchema } from "./parentChanged.js"
12
- import {
13
- legacyQueryDataSourceResultMessageSchema,
14
- statusQueryDataSourceResultMessageSchema,
15
- } from "./queryDataSourceResult.js"
12
+ import { queryDataSourceResultMessageSchema } from "./queryDataSourceResult.js"
16
13
  import { themeChangedMessageSchema } from "./themeChanged.js"
17
14
  import { updatePageResultMessageSchema } from "./updatePageResult.js"
18
15
 
@@ -26,8 +23,7 @@ export const hostToSandboxMessageSchema = v.variant("type", [
26
23
  pageChangedMessageSchema,
27
24
  currentUserChangedMessageSchema,
28
25
  dataSourcesChangedMessageSchema,
29
- statusQueryDataSourceResultMessageSchema,
30
- legacyQueryDataSourceResultMessageSchema,
26
+ queryDataSourceResultMessageSchema,
31
27
  createPageResultMessageSchema,
32
28
  getPageResultMessageSchema,
33
29
  getUserResultMessageSchema,
@@ -2,18 +2,18 @@ import * as v from "valibot"
2
2
  import { notionDataSourceBindingsSchema } from "../dataSources/dataSource.js"
3
3
  import type { CustomBlockErrorCode, CustomBlockErrorInfo } from "../errors.js"
4
4
  import { notionBlockIdSchema } from "../ids.js"
5
+ import { manifestSchema } from "../manifest.js"
5
6
  import { customBlockPageSchema } from "../pages/page.js"
6
7
  import { notionParentSchema } from "../parent.js"
7
8
  import { notionThemeSchema } from "../theme.js"
8
9
  import { notionUserSchema } from "../users/user.js"
10
+ import type { CustomBlockInitResultErrorCode } from "./initResult.js"
9
11
 
10
12
  // The schema accepts any string code. The type lists known codes for
11
13
  // autocomplete, with an open string fallback for newer senders.
12
14
  export const customBlockInitErrorCodeSchema = v.string()
13
15
 
14
16
  export type CustomBlockInitErrorCode = CustomBlockErrorCode<
15
- | "no_ready"
16
- | "invalid_ready"
17
17
  | "manifest_unavailable"
18
18
  | "manifest_invalid"
19
19
  | "invalid_protocol_version"
@@ -24,47 +24,60 @@ export type CustomBlockInitErrorCode = CustomBlockErrorCode<
24
24
  | "data_source_unavailable"
25
25
  | "missing_property_binding"
26
26
  | "invalid_property_binding"
27
- | "not_in_iframe"
28
- | "init_timeout"
29
27
  >
30
28
 
31
29
  export type CustomBlockInitErrorInfo =
32
30
  CustomBlockErrorInfo<CustomBlockInitErrorCode>
33
31
 
32
+ /**
33
+ * Every initialization failure visible to block code. This combines errors
34
+ * received in `init`, errors the sandbox reports in `initResult`, and failures
35
+ * detected locally while running `initCustomBlock()`.
36
+ */
37
+ export type CustomBlockInitializationErrorCode =
38
+ | CustomBlockInitErrorCode
39
+ | CustomBlockInitResultErrorCode
40
+ | CustomBlockErrorCode<"not_in_iframe" | "init_timeout">
41
+
42
+ export type CustomBlockInitializationErrorInfo =
43
+ CustomBlockErrorInfo<CustomBlockInitializationErrorCode>
44
+
34
45
  export const customBlockInitErrorInfoSchema = v.object({
35
46
  code: customBlockInitErrorCodeSchema,
36
47
  message: v.string(),
37
48
  isRetryable: v.boolean(),
38
49
  })
39
50
 
40
- export class CustomBlockInitError
51
+ export class CustomBlockInitializationError
41
52
  extends Error
42
53
  implements CustomBlockErrorInfo
43
54
  {
44
- constructor(error: CustomBlockInitErrorInfo) {
55
+ constructor(error: CustomBlockInitializationErrorInfo) {
45
56
  super(error.message)
46
- this.name = "CustomBlockInitError"
57
+ this.name = "CustomBlockInitializationError"
47
58
  this.code = error.code
48
59
  this.isRetryable = error.isRetryable
49
60
  }
50
61
 
51
- code: CustomBlockInitErrorCode
62
+ code: CustomBlockInitializationErrorCode
52
63
  isRetryable: boolean
53
64
  }
54
65
 
55
66
  /**
56
67
  * Initialization message sent by the host to the sandbox exactly once, in response to the
57
- * sandbox's `ready` message. After init, live updates flow through narrower messages
58
- * (`themeChanged`, `parentChanged`, `pageChanged`, `dataSourcesChanged`).
68
+ * sandbox's `connect` message. The sandbox echoes `initializationId` in `initResult`. After
69
+ * successful initialization, live updates flow through narrower messages.
59
70
  */
60
71
  export const initMessageSchema = v.variant("status", [
61
72
  v.object({
62
73
  type: v.literal("init"),
74
+ initializationId: v.string(),
63
75
  status: v.literal("success"),
64
76
  theme: notionThemeSchema,
65
77
  blockId: notionBlockIdSchema,
66
78
  parent: notionParentSchema,
67
79
  page: customBlockPageSchema,
80
+ manifest: manifestSchema,
68
81
  dataSources: v.object({
69
82
  bindings: notionDataSourceBindingsSchema,
70
83
  }),
@@ -72,6 +85,7 @@ export const initMessageSchema = v.variant("status", [
72
85
  }),
73
86
  v.object({
74
87
  type: v.literal("init"),
88
+ initializationId: v.string(),
75
89
  status: v.literal("error"),
76
90
  error: customBlockInitErrorInfoSchema,
77
91
  }),
@@ -0,0 +1,37 @@
1
+ import * as v from "valibot"
2
+ import type { CustomBlockErrorCode, CustomBlockErrorInfo } from "../errors.js"
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 customBlockInitResultErrorCodeSchema = v.string()
7
+
8
+ export type CustomBlockInitResultErrorCode =
9
+ CustomBlockErrorCode<"invalid_init_bindings">
10
+
11
+ export type CustomBlockInitResultErrorInfo =
12
+ CustomBlockErrorInfo<CustomBlockInitResultErrorCode>
13
+
14
+ export const customBlockInitResultErrorInfoSchema = v.object({
15
+ code: customBlockInitResultErrorCodeSchema,
16
+ message: v.string(),
17
+ isRetryable: v.boolean(),
18
+ })
19
+
20
+ /**
21
+ * Acknowledges whether the sandbox successfully applied the host's `init` response.
22
+ */
23
+ export const initResultMessageSchema = v.variant("status", [
24
+ v.object({
25
+ type: v.literal("initResult"),
26
+ initializationId: v.string(),
27
+ status: v.literal("success"),
28
+ }),
29
+ v.object({
30
+ type: v.literal("initResult"),
31
+ initializationId: v.string(),
32
+ status: v.literal("error"),
33
+ error: customBlockInitResultErrorInfoSchema,
34
+ }),
35
+ ])
36
+
37
+ export type InitResultMessage = v.InferOutput<typeof initResultMessageSchema>
@@ -7,15 +7,11 @@ import { notionDataSourceIdSchema } from "../ids.js"
7
7
  */
8
8
  export const queryDataSourceMessageSchema = v.object({
9
9
  type: v.literal("queryDataSource"),
10
- requestId: v.string(),
11
- /**
12
- * The stable snapshot ID that identifies the SDK result slot to update. This is stable for the
13
- * lifetime of the subscription.
14
- */
15
- snapshotId: v.string(),
10
+ /** Stable for the lifetime of this query subscription. */
11
+ subscriptionId: v.string(),
16
12
  /** The raw Notion data source ID to read from. */
17
13
  dataSourceId: notionDataSourceIdSchema,
18
- /** The number of items to return in the snapshot. */
14
+ /** The number of items to return in each subscription update. */
19
15
  limit: v.number(),
20
16
  })
21
17
 
@@ -22,44 +22,24 @@ export const customBlockQueryDataSourceErrorInfoSchema = v.object({
22
22
  })
23
23
 
24
24
  /**
25
- * Message sent by the host to the sandbox in response to a `queryDataSource` request.
25
+ * Message sent by the host to update a `queryDataSource` subscription.
26
26
  */
27
- export const legacyQueryDataSourceResultMessageSchema = v.object({
28
- type: v.literal("queryDataSourceResult"),
29
- requestId: v.string(),
30
- snapshotId: v.string(),
31
- items: v.array(notionDataSourcePageBridgeSchema),
32
- hasMore: v.boolean(),
33
- error: v.optional(customBlockQueryDataSourceErrorInfoSchema),
34
- })
35
-
36
- export const statusQueryDataSourceResultMessageSchema = v.variant("status", [
27
+ export const queryDataSourceResultMessageSchema = v.variant("status", [
37
28
  v.object({
38
29
  type: v.literal("queryDataSourceResult"),
39
- requestId: v.string(),
40
- snapshotId: v.string(),
30
+ subscriptionId: v.string(),
41
31
  status: v.literal("success"),
42
32
  items: v.array(notionDataSourcePageBridgeSchema),
43
33
  hasMore: v.boolean(),
44
34
  }),
45
35
  v.object({
46
36
  type: v.literal("queryDataSourceResult"),
47
- requestId: v.string(),
48
- snapshotId: v.string(),
37
+ subscriptionId: v.string(),
49
38
  status: v.literal("error"),
50
39
  error: customBlockQueryDataSourceErrorInfoSchema,
51
40
  }),
52
41
  ])
53
42
 
54
- /**
55
- * TODO(custom-blocks): Update when bumping bridge protocol version to 3.
56
- * Protocol version 2 hosts and sandboxes use the legacy optional-error shape.
57
- */
58
- export const queryDataSourceResultMessageSchema = v.union([
59
- legacyQueryDataSourceResultMessageSchema,
60
- statusQueryDataSourceResultMessageSchema,
61
- ])
62
-
63
43
  export type QueryDataSourceResultMessage = v.InferOutput<
64
44
  typeof queryDataSourceResultMessageSchema
65
45
  >
@@ -1,11 +1,12 @@
1
1
  import * as v from "valibot"
2
+ import { connectMessageSchema } from "./connect.js"
2
3
  import { createPageMessageSchema } from "./createPage.js"
3
4
  import { getPageMessageSchema } from "./getPage.js"
4
5
  import { getUserMessageSchema } from "./getUser.js"
6
+ import { initResultMessageSchema } from "./initResult.js"
5
7
  import { invalidHostMessageSchema } from "./invalidHostMessage.js"
6
8
  import { listUsersMessageSchema } from "./listUsers.js"
7
9
  import { queryDataSourceMessageSchema } from "./queryDataSource.js"
8
- import { readyMessageSchema } from "./ready.js"
9
10
  import { resizeMessageSchema } from "./resize.js"
10
11
  import { updatePageMessageSchema } from "./updatePage.js"
11
12
 
@@ -14,7 +15,8 @@ import { updatePageMessageSchema } from "./updatePage.js"
14
15
  * inbound traffic from sandboxes without re-implementing validation logic.
15
16
  */
16
17
  export const sandboxToHostMessageSchema = v.union([
17
- readyMessageSchema,
18
+ connectMessageSchema,
19
+ initResultMessageSchema,
18
20
  queryDataSourceMessageSchema,
19
21
  createPageMessageSchema,
20
22
  getPageMessageSchema,
@@ -17,7 +17,6 @@ import {
17
17
  getDataSourceQueryView as getDataSourceQueryViewWithBridge,
18
18
  } from "./hostState.js"
19
19
  import type { ManifestLoadResult } from "./loadManifest.js"
20
- import type { CustomBlockManifest } from "./manifest.js"
21
20
  import type { InitMessage } from "./messages/init.js"
22
21
  import { type MessageLogEntry, SandboxBridge } from "./SandboxBridge.js"
23
22
 
@@ -26,11 +25,11 @@ export type { MessageLogEntry }
26
25
  const bridge = new SandboxBridge()
27
26
 
28
27
  export const customBlockHost = {
29
- sendReady: (manifestResult: ManifestLoadResult) => {
30
- bridge.sendReady(manifestResult)
28
+ sendConnect: (manifestResult: ManifestLoadResult) => {
29
+ bridge.sendConnect(manifestResult)
31
30
  },
32
31
 
33
- awaitInit: (signal?: AbortSignal): Promise<InitMessage> => {
32
+ awaitInit: (signal?: AbortSignal): Promise<void> => {
34
33
  return bridge.awaitInit(signal)
35
34
  },
36
35
 
@@ -42,10 +41,6 @@ export const customBlockHost = {
42
41
  return bridge.getHostState()
43
42
  },
44
43
 
45
- getManifest: (): CustomBlockManifest | null => {
46
- return bridge.getManifest()
47
- },
48
-
49
44
  /**
50
45
  * Apply an `init` payload directly, bypassing the postMessage handshake for
51
46
  * standalone preview state.
@@ -57,8 +57,8 @@ export const customBlock = {
57
57
  return getInitializedHostState("getPage").page
58
58
  },
59
59
 
60
- getManifest(): CustomBlockManifest | null {
61
- return customBlockHost.getManifest()
60
+ getManifest(): CustomBlockManifest {
61
+ return getInitializedHostState("getManifest").manifest
62
62
  },
63
63
 
64
64
  autoResize,