@notionhq/custom-blocks-host 0.2.9 → 0.2.11
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/dist/browser.js +1 -3308
- package/dist/createCustomBlockHost.d.ts.map +1 -1
- package/dist/createCustomBlockHost.js +11 -11
- package/dist/lifecycle/initErrors.d.ts +21 -10
- package/dist/lifecycle/initErrors.d.ts.map +1 -1
- package/dist/lifecycle/initErrors.js +104 -155
- package/dist/lifecycle/initializationController.d.ts.map +1 -1
- package/dist/lifecycle/initializationController.js +11 -9
- package/dist/messages/sandboxMessageRouter.d.ts.map +1 -1
- package/dist/messages/sandboxMessageRouter.js +3 -3
- package/package.json +1 -1
- package/src/createCustomBlockHost.ts +18 -13
- package/src/lifecycle/initErrors.ts +120 -166
- package/src/lifecycle/initializationController.ts +21 -15
- package/src/messages/sandboxMessageRouter.ts +6 -3
|
@@ -1,171 +1,125 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CustomBlockInitErrorCode,
|
|
3
|
-
CustomBlockInitErrorInfo,
|
|
4
|
-
} from "@notionhq/custom-blocks-protocol/messages/init.js"
|
|
5
|
-
|
|
6
|
-
const UNKNOWN_ERROR_MESSAGE =
|
|
7
|
-
"Unexpected error while initializing custom block."
|
|
1
|
+
import type { CustomBlockErrorInfo } from "@notionhq/custom-blocks-protocol/errors.js"
|
|
8
2
|
|
|
9
3
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `connect` message. `isRetryable` means a fresh iframe / `init` attempt could plausibly succeed
|
|
14
|
-
* without changing block code or host configuration.
|
|
4
|
+
* Initialization handshakes are one-shot: after an error, this host instance will not answer
|
|
5
|
+
* another `connect` message. `isRetryable` means a fresh host and iframe could plausibly
|
|
6
|
+
* initialize without changing block code or host configuration.
|
|
15
7
|
*/
|
|
16
|
-
export function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
code: reason,
|
|
133
|
-
message: "Sandbox did not acknowledge initialization.",
|
|
134
|
-
isRetryable: true,
|
|
135
|
-
}
|
|
136
|
-
case "invalid_init_result_payload":
|
|
137
|
-
return {
|
|
138
|
-
code: reason,
|
|
139
|
-
message: "Sandbox sent an invalid initialization result.",
|
|
140
|
-
isRetryable: false,
|
|
141
|
-
}
|
|
142
|
-
case "invalid_init_bindings":
|
|
143
|
-
return {
|
|
144
|
-
code: reason,
|
|
145
|
-
message: "Sandbox rejected the host-provided data source bindings.",
|
|
146
|
-
isRetryable: false,
|
|
147
|
-
}
|
|
148
|
-
case "not_in_iframe":
|
|
149
|
-
return {
|
|
150
|
-
code: reason,
|
|
151
|
-
message: "<NotionCustomBlock> only works inside an iframe.",
|
|
152
|
-
// The block must be embedded in an iframe.
|
|
153
|
-
isRetryable: false,
|
|
154
|
-
}
|
|
155
|
-
case "unknown_error":
|
|
156
|
-
return {
|
|
157
|
-
code: reason,
|
|
158
|
-
message: UNKNOWN_ERROR_MESSAGE,
|
|
159
|
-
// Treat unknown errors as non-retryable.
|
|
160
|
-
isRetryable: false,
|
|
161
|
-
}
|
|
162
|
-
default:
|
|
163
|
-
console.warn(`Unexpected custom block init error: ${reason}`)
|
|
164
|
-
return {
|
|
165
|
-
code: reason,
|
|
166
|
-
message: UNKNOWN_ERROR_MESSAGE,
|
|
167
|
-
// Treat unknown error codes as non-retryable.
|
|
168
|
-
isRetryable: false,
|
|
169
|
-
}
|
|
8
|
+
export function noConnectError(): CustomBlockErrorInfo<"no_connect"> {
|
|
9
|
+
return {
|
|
10
|
+
code: "no_connect",
|
|
11
|
+
message: "Sandbox did not send a connect message.",
|
|
12
|
+
// A fresh iframe may finish loading and send connect before the timeout.
|
|
13
|
+
isRetryable: true,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function invalidConnectPayloadError(): CustomBlockErrorInfo<"invalid_connect_payload"> {
|
|
18
|
+
return {
|
|
19
|
+
code: "invalid_connect_payload",
|
|
20
|
+
message: "Sandbox sent an invalid connect message.",
|
|
21
|
+
// The sandbox must be updated to send a valid connect message.
|
|
22
|
+
isRetryable: false,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function invalidProtocolVersionError(args: {
|
|
27
|
+
currentBridgeProtocolVersion: number | undefined
|
|
28
|
+
}): CustomBlockErrorInfo<"invalid_protocol_version"> {
|
|
29
|
+
const { currentBridgeProtocolVersion } = args
|
|
30
|
+
const versionText = currentBridgeProtocolVersion
|
|
31
|
+
? `: ${currentBridgeProtocolVersion}`
|
|
32
|
+
: "."
|
|
33
|
+
return {
|
|
34
|
+
code: "invalid_protocol_version",
|
|
35
|
+
message: `Sandbox reported an invalid bridge protocol version ${versionText}`,
|
|
36
|
+
// The sandbox must be updated to a supported protocol version.
|
|
37
|
+
isRetryable: false,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function unsupportedProtocolVersionError(args: {
|
|
42
|
+
currentBridgeProtocolVersion: number
|
|
43
|
+
minBridgeProtocolVersion: number
|
|
44
|
+
}): CustomBlockErrorInfo<"unsupported_protocol_version"> {
|
|
45
|
+
const { currentBridgeProtocolVersion, minBridgeProtocolVersion } = args
|
|
46
|
+
return {
|
|
47
|
+
code: "unsupported_protocol_version",
|
|
48
|
+
message: `Sandbox bridge protocol version ${currentBridgeProtocolVersion} is not supported. Minimum supported version is ${minBridgeProtocolVersion}.`,
|
|
49
|
+
// The sandbox must be updated to a supported protocol version.
|
|
50
|
+
isRetryable: false,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function contextUnavailableError(): CustomBlockErrorInfo<"context_unavailable"> {
|
|
55
|
+
return {
|
|
56
|
+
code: "context_unavailable",
|
|
57
|
+
message: "Host page context is unavailable.",
|
|
58
|
+
// Page context may become available before a fresh initialization attempt.
|
|
59
|
+
isRetryable: true,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function initialStateTimeoutError(): CustomBlockErrorInfo<"initial_state_timeout"> {
|
|
64
|
+
return {
|
|
65
|
+
code: "initial_state_timeout",
|
|
66
|
+
message: "Host did not prepare initial state before the timeout.",
|
|
67
|
+
// A fresh attempt may finish loading host dependencies before the timeout.
|
|
68
|
+
isRetryable: true,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function missingDataSourceBindingError(): CustomBlockErrorInfo<"missing_data_source_binding"> {
|
|
73
|
+
return {
|
|
74
|
+
code: "missing_data_source_binding",
|
|
75
|
+
message: "A required data source is not mapped.",
|
|
76
|
+
// Host configuration must be changed before this block can initialize.
|
|
77
|
+
isRetryable: false,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function missingPropertyBindingError(): CustomBlockErrorInfo<"missing_property_binding"> {
|
|
82
|
+
return {
|
|
83
|
+
code: "missing_property_binding",
|
|
84
|
+
message: "A required data source property is not mapped.",
|
|
85
|
+
// Host configuration must be changed before this block can initialize.
|
|
86
|
+
isRetryable: false,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function invalidPropertyBindingError(): CustomBlockErrorInfo<"invalid_property_binding"> {
|
|
91
|
+
return {
|
|
92
|
+
code: "invalid_property_binding",
|
|
93
|
+
message: "A mapped data source property is missing or incompatible.",
|
|
94
|
+
// The bound property's schema must be updated or the binding must be updated to
|
|
95
|
+
// a property with a compatible schema.
|
|
96
|
+
isRetryable: false,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function noInitResultError(): CustomBlockErrorInfo<"no_init_result"> {
|
|
101
|
+
return {
|
|
102
|
+
code: "no_init_result",
|
|
103
|
+
message: "Sandbox did not acknowledge initialization.",
|
|
104
|
+
// A fresh iframe may process init and acknowledge it before the timeout.
|
|
105
|
+
isRetryable: true,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function invalidInitResultPayloadError(): CustomBlockErrorInfo<"invalid_init_result_payload"> {
|
|
110
|
+
return {
|
|
111
|
+
code: "invalid_init_result_payload",
|
|
112
|
+
message: "Sandbox sent an invalid initialization result.",
|
|
113
|
+
// The sandbox must be updated to send a valid initialization result.
|
|
114
|
+
isRetryable: false,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function unknownInitializationError(): CustomBlockErrorInfo<"unknown_error"> {
|
|
119
|
+
return {
|
|
120
|
+
code: "unknown_error",
|
|
121
|
+
message: "Unexpected error while initializing custom block.",
|
|
122
|
+
// Without a known transient cause, conservatively treat unknown errors as non-retryable.
|
|
123
|
+
isRetryable: false,
|
|
170
124
|
}
|
|
171
125
|
}
|
|
@@ -8,7 +8,14 @@ import type { InitResultMessage } from "@notionhq/custom-blocks-protocol/message
|
|
|
8
8
|
import type { InferInput } from "valibot"
|
|
9
9
|
import type { CustomBlockHostFailure } from "../messages/types.js"
|
|
10
10
|
import { unreachable } from "../utils.js"
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
initialStateTimeoutError,
|
|
13
|
+
invalidProtocolVersionError,
|
|
14
|
+
noConnectError,
|
|
15
|
+
noInitResultError,
|
|
16
|
+
unknownInitializationError,
|
|
17
|
+
unsupportedProtocolVersionError,
|
|
18
|
+
} from "./initErrors.js"
|
|
12
19
|
import { isValidBridgeProtocolVersion } from "./protocolVersion.js"
|
|
13
20
|
import type {
|
|
14
21
|
ConnectSuccessMessage,
|
|
@@ -141,7 +148,7 @@ export function createInitializationController(
|
|
|
141
148
|
if (initStatus !== "preparingInit") {
|
|
142
149
|
return
|
|
143
150
|
}
|
|
144
|
-
const error =
|
|
151
|
+
const error = initialStateTimeoutError()
|
|
145
152
|
warn({
|
|
146
153
|
...error,
|
|
147
154
|
initializationId: connect.initializationId,
|
|
@@ -183,7 +190,7 @@ export function createInitializationController(
|
|
|
183
190
|
return
|
|
184
191
|
}
|
|
185
192
|
initStatus = "error"
|
|
186
|
-
const error =
|
|
193
|
+
const error = noInitResultError()
|
|
187
194
|
onConnectionFailure?.(error)
|
|
188
195
|
warn({
|
|
189
196
|
...error,
|
|
@@ -200,7 +207,7 @@ export function createInitializationController(
|
|
|
200
207
|
})
|
|
201
208
|
sendInitError({
|
|
202
209
|
initializationId: connect.initializationId,
|
|
203
|
-
error:
|
|
210
|
+
error: unknownInitializationError(),
|
|
204
211
|
})
|
|
205
212
|
}
|
|
206
213
|
}
|
|
@@ -215,7 +222,7 @@ export function createInitializationController(
|
|
|
215
222
|
|
|
216
223
|
// Verify the bridge protocol version is valid.
|
|
217
224
|
if (!isValidBridgeProtocolVersion(message.bridgeProtocolVersion)) {
|
|
218
|
-
const initError =
|
|
225
|
+
const initError = invalidProtocolVersionError({
|
|
219
226
|
currentBridgeProtocolVersion: message.bridgeProtocolVersion,
|
|
220
227
|
})
|
|
221
228
|
sendInitError({
|
|
@@ -225,13 +232,10 @@ export function createInitializationController(
|
|
|
225
232
|
return
|
|
226
233
|
}
|
|
227
234
|
if (message.bridgeProtocolVersion < minBridgeProtocolVersion) {
|
|
228
|
-
const initError =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
minBridgeProtocolVersion,
|
|
233
|
-
},
|
|
234
|
-
)
|
|
235
|
+
const initError = unsupportedProtocolVersionError({
|
|
236
|
+
currentBridgeProtocolVersion: message.bridgeProtocolVersion,
|
|
237
|
+
minBridgeProtocolVersion,
|
|
238
|
+
})
|
|
235
239
|
sendInitError({
|
|
236
240
|
initializationId: message.initializationId,
|
|
237
241
|
error: initError,
|
|
@@ -273,9 +277,11 @@ export function createInitializationController(
|
|
|
273
277
|
// when the malformed message includes a numeric version.
|
|
274
278
|
if (bridgeProtocolVersion !== undefined) {
|
|
275
279
|
if (!isValidBridgeProtocolVersion(bridgeProtocolVersion)) {
|
|
276
|
-
error =
|
|
280
|
+
error = invalidProtocolVersionError({
|
|
281
|
+
currentBridgeProtocolVersion: undefined,
|
|
282
|
+
})
|
|
277
283
|
} else if (bridgeProtocolVersion < minBridgeProtocolVersion) {
|
|
278
|
-
error =
|
|
284
|
+
error = unsupportedProtocolVersionError({
|
|
279
285
|
currentBridgeProtocolVersion: bridgeProtocolVersion,
|
|
280
286
|
minBridgeProtocolVersion,
|
|
281
287
|
})
|
|
@@ -329,7 +335,7 @@ export function createInitializationController(
|
|
|
329
335
|
return
|
|
330
336
|
}
|
|
331
337
|
initStatus = "error"
|
|
332
|
-
const error =
|
|
338
|
+
const error = noConnectError()
|
|
333
339
|
warn(error)
|
|
334
340
|
onConnectionFailure?.(error)
|
|
335
341
|
}, noConnectTimeoutMs)
|
|
@@ -13,7 +13,10 @@ import { sandboxToHostMessageSchema } from "@notionhq/custom-blocks-protocol/mes
|
|
|
13
13
|
import type { UnsubscribeDataSourceQueryMessage } from "@notionhq/custom-blocks-protocol/messages/unsubscribeDataSourceQuery.js"
|
|
14
14
|
import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
|
|
15
15
|
import * as v from "valibot"
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
invalidConnectPayloadError,
|
|
18
|
+
invalidInitResultPayloadError,
|
|
19
|
+
} from "../lifecycle/initErrors.js"
|
|
17
20
|
import type { InitializationController } from "../lifecycle/initializationController.js"
|
|
18
21
|
import type { InitStatus } from "../lifecycle/types.js"
|
|
19
22
|
import { unreachable } from "../utils.js"
|
|
@@ -95,7 +98,7 @@ export function createSandboxMessageRouter(
|
|
|
95
98
|
initializationId: parsedIdentity.success
|
|
96
99
|
? parsedIdentity.output.initializationId
|
|
97
100
|
: undefined,
|
|
98
|
-
error:
|
|
101
|
+
error: invalidConnectPayloadError(),
|
|
99
102
|
bridgeProtocolVersion: parsedVersion.success
|
|
100
103
|
? parsedVersion.output.bridgeProtocolVersion
|
|
101
104
|
: undefined,
|
|
@@ -112,7 +115,7 @@ export function createSandboxMessageRouter(
|
|
|
112
115
|
initializationId: parsedIdentity.success
|
|
113
116
|
? parsedIdentity.output.initializationId
|
|
114
117
|
: undefined,
|
|
115
|
-
error:
|
|
118
|
+
error: invalidInitResultPayloadError(),
|
|
116
119
|
})
|
|
117
120
|
}
|
|
118
121
|
|