@notionhq/custom-blocks-host 0.1.9 → 0.1.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/README.md +19 -13
- package/dist/createCustomBlockHost.d.ts.map +1 -1
- package/dist/createCustomBlockHost.js +20 -102
- package/dist/lifecycle/initErrors.d.ts.map +1 -1
- package/dist/lifecycle/initErrors.js +6 -6
- package/dist/lifecycle/initializationController.d.ts +8 -2
- package/dist/lifecycle/initializationController.d.ts.map +1 -1
- package/dist/lifecycle/initializationController.js +32 -23
- package/dist/messages/invalidSandboxMessage.js +1 -1
- package/dist/messages/sandboxMessageRouter.d.ts +35 -0
- package/dist/messages/sandboxMessageRouter.d.ts.map +1 -0
- package/dist/messages/sandboxMessageRouter.js +107 -0
- package/dist/messages/types.d.ts +1 -1
- package/dist/messages/types.d.ts.map +1 -1
- package/dist/protocol/index.d.ts +3 -2
- package/dist/protocol/index.js +3 -2
- package/dist/protocol/messages/init.d.ts +2 -2
- package/dist/protocol/messages/isInitHandshakeMessage.d.ts +4 -0
- package/dist/protocol/messages/isInitHandshakeMessage.js +11 -0
- package/dist/protocol/{messagePayload.d.ts → messages/messagePayload.d.ts} +1 -1
- package/dist/queries/types.d.ts +1 -1
- package/dist/queries/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/createCustomBlockHost.ts +21 -117
- package/src/lifecycle/initErrors.ts +6 -7
- package/src/lifecycle/initializationController.ts +51 -27
- package/src/messages/invalidSandboxMessage.ts +1 -1
- package/src/messages/sandboxMessageRouter.ts +176 -0
- package/src/messages/types.ts +1 -1
- package/src/queries/types.ts +1 -1
- /package/dist/protocol/{incomingType.d.ts → messages/incomingType.d.ts} +0 -0
- /package/dist/protocol/{incomingType.js → messages/incomingType.js} +0 -0
- /package/dist/protocol/{messagePayload.js → messages/messagePayload.js} +0 -0
package/README.md
CHANGED
|
@@ -151,19 +151,25 @@ the ID in the `init` message. The host ignores a result with a different ID.
|
|
|
151
151
|
If no result arrives, or only a stale valid result arrives, before the timeout,
|
|
152
152
|
initialization ends with `no_init_result`.
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
before
|
|
156
|
-
identify the message
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
-
|
|
166
|
-
|
|
154
|
+
The host validates each inbound sandbox message with `sandboxToHostMessageSchema`
|
|
155
|
+
before it handles the message. If parsing fails, the host uses `readIncomingType()`
|
|
156
|
+
to identify the attempted message. It replies with `invalidSandboxMessage`, a
|
|
157
|
+
negative acknowledgment (NACK). The host never sends a NACK in response to a NACK.
|
|
158
|
+
|
|
159
|
+
Malformed sandbox messages do not change the host's initialization state or
|
|
160
|
+
timeout, except in these two cases:
|
|
161
|
+
|
|
162
|
+
- The host expects `connect` and receives a malformed `connect` with a readable
|
|
163
|
+
`initializationId`. The host sends `init.error` with `invalid_connect_payload`
|
|
164
|
+
instead of a NACK, then fails initialization.
|
|
165
|
+
- The host expects `initResult` and receives a malformed `initResult` with the
|
|
166
|
+
active `initializationId`. The host sends a NACK and fails initialization with
|
|
167
|
+
`invalid_init_result_payload`. This error code describes a local host failure.
|
|
168
|
+
The host does not send it in `initResult.error`.
|
|
169
|
+
|
|
170
|
+
A malformed `initResult` with a missing or stale ID does not end initialization
|
|
171
|
+
or reset its timeout. Malformed messages do not restart initialization after
|
|
172
|
+
it succeeds or fails.
|
|
167
173
|
|
|
168
174
|
The host accepts a valid `initResult.error` as a terminal initialization
|
|
169
175
|
failure. It logs and ignores a valid `initResult` with a stale
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCustomBlockHost.d.ts","sourceRoot":"","sources":["../src/createCustomBlockHost.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,8CAA8C,CAAA;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AAavF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;
|
|
1
|
+
{"version":3,"file":"createCustomBlockHost.d.ts","sourceRoot":"","sources":["../src/createCustomBlockHost.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,8CAA8C,CAAA;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AAavF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AAatG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAE9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAGhF,OAAO,KAAK,EACX,iCAAiC,EACjC,2BAA2B,EAC3B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EACX,uBAAuB,EACvB,oCAAoC,EACpC,2BAA2B,EAC3B,MAAM,qBAAqB,CAAA;AAS5B,MAAM,MAAM,sBAAsB,GAAG;IACpC,MAAM,EAAE,iBAAiB,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,wBAAwB,EAAE,MAAM,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE,2BAA2B,CAAA;IACzC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,oHAAoH;IACpH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACpD,gGAAgG;IAChG,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QACvB,QAAQ,EAAE,mBAAmB,CAAA;QAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;KACtB,KAAK,IAAI,CAAA;IACV,6FAA6F;IAC7F,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,oCAAoC,KACvC,IAAI,CAAA;IACT;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,2BAA2B,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAC1E,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IACnC,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,eAAe,EAAE,CAAC,YAAY,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC3D,SAAS,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACxC,cAAc,EAAE,CAAC,WAAW,EAAE,iCAAiC,KAAK,IAAI,CAAA;IACxE,cAAc,EAAE,CAAC,WAAW,EAAE,UAAU,KAAK,IAAI,CAAA;IACjD,YAAY,EAAE,CAAC,IAAI,EAAE;QAAE,YAAY,EAAE,kBAAkB,CAAA;KAAE,KAAK,IAAI,CAAA;CAClE,CAAA;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,sBAAsB,GAC7B,qBAAqB,CAsYvB"}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { DEFAULT_CONTRAST_MODE, } from "./protocol/contrast.js";
|
|
2
|
-
import { sandboxToHostMessageSchema } from "./protocol/messages/sandboxToHost.js";
|
|
3
2
|
import { CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION } from "./protocol/protocolVersion.js";
|
|
4
|
-
import * as v from "valibot";
|
|
5
3
|
import { initErrorForFailureReason } from "./lifecycle/initErrors.js";
|
|
6
4
|
import { createInitializationController } from "./lifecycle/initializationController.js";
|
|
7
|
-
import {
|
|
5
|
+
import { createSandboxMessageRouter } from "./messages/sandboxMessageRouter.js";
|
|
8
6
|
import { QuerySubscriptions, } from "./queries/querySubscriptions.js";
|
|
9
7
|
import { validateQueryDataSourceFilter } from "./queries/validateQueryDataSourceFilter.js";
|
|
10
8
|
import { validateQueryDataSourceSorts } from "./queries/validateQueryDataSourceSorts.js";
|
|
11
|
-
import { unreachable } from "./utils.js";
|
|
12
|
-
const initializationIdentitySchema = v.object({
|
|
13
|
-
initializationId: v.string(),
|
|
14
|
-
});
|
|
15
9
|
export function createCustomBlockHost(options) {
|
|
16
10
|
const { iframe, initialState, handlers, onManifest, onInitialized, onInitializationFailure, onRestartRequired, onLog, sandboxOrigin, minBridgeProtocolVersion: configuredMinBridgeProtocolVersion, noConnectTimeoutMs, noInitResultTimeoutMs, } = options;
|
|
17
11
|
const minBridgeProtocolVersion = Math.max(configuredMinBridgeProtocolVersion ?? CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION, CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION);
|
|
@@ -224,101 +218,25 @@ export function createCustomBlockHost(options) {
|
|
|
224
218
|
onRestartRequired,
|
|
225
219
|
onInitializationFailure,
|
|
226
220
|
});
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (response.incomingType === "initResult" &&
|
|
247
|
-
initializationController.handleInvalidInitResult()) {
|
|
248
|
-
if (response.nack !== undefined) {
|
|
249
|
-
post(response.nack);
|
|
250
|
-
}
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
if (response.nack !== undefined) {
|
|
254
|
-
post(response.nack);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function onMessage(event) {
|
|
258
|
-
// Ignore messages from windows other than this host's iframe.
|
|
259
|
-
if (event.source !== iframe.contentWindow) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
// Ignore messages that do not come from the configured sandbox origin.
|
|
263
|
-
if (event.origin !== sandboxOrigin) {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const parsed = v.safeParse(sandboxToHostMessageSchema, event.data);
|
|
267
|
-
if (!parsed.success) {
|
|
268
|
-
onInvalidSandboxMessage(event.data, parsed.issues);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
const message = parsed.output;
|
|
272
|
-
emit("in", message);
|
|
273
|
-
if (message.type !== "connect" &&
|
|
274
|
-
message.type !== "initResult" &&
|
|
275
|
-
initializationController.status !== "success") {
|
|
276
|
-
// Ignore all non-handshake messages until initialization succeeds.
|
|
277
|
-
if (message.type !== "resize") {
|
|
278
|
-
emit("warn", {
|
|
279
|
-
message: `Ignored ${message.type} before initialization completed`,
|
|
280
|
-
payload: message,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
switch (message.type) {
|
|
286
|
-
case "connect":
|
|
287
|
-
initializationController.handleConnect(message);
|
|
288
|
-
return;
|
|
289
|
-
case "initResult":
|
|
290
|
-
initializationController.handleInitResult(message);
|
|
291
|
-
return;
|
|
292
|
-
case "queryDataSource":
|
|
293
|
-
void handleQuery(message);
|
|
294
|
-
return;
|
|
295
|
-
case "unsubscribeDataSourceQuery":
|
|
296
|
-
querySubscriptions.unsubscribe(message.subscriptionId);
|
|
297
|
-
return;
|
|
298
|
-
case "createPage":
|
|
299
|
-
void handleCreatePage(message);
|
|
300
|
-
return;
|
|
301
|
-
case "getPage":
|
|
302
|
-
void handleGetPage(message);
|
|
303
|
-
return;
|
|
304
|
-
case "getUser":
|
|
305
|
-
void handleGetUser(message);
|
|
306
|
-
return;
|
|
307
|
-
case "listUsers":
|
|
308
|
-
void handleListUsers(message);
|
|
309
|
-
return;
|
|
310
|
-
case "updatePage":
|
|
311
|
-
void handleUpdatePage(message);
|
|
312
|
-
return;
|
|
313
|
-
case "resize":
|
|
314
|
-
handlers.resize?.(message);
|
|
315
|
-
return;
|
|
316
|
-
case "invalidHostMessage":
|
|
317
|
-
return;
|
|
318
|
-
default:
|
|
319
|
-
unreachable(message);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
221
|
+
const onMessage = createSandboxMessageRouter({
|
|
222
|
+
iframe,
|
|
223
|
+
sandboxOrigin,
|
|
224
|
+
getInitStatus: () => initializationController.status,
|
|
225
|
+
emit,
|
|
226
|
+
post,
|
|
227
|
+
onInvalidConnect: initializationController.handleInvalidConnect,
|
|
228
|
+
onInvalidInitResult: initializationController.handleInvalidInitResult,
|
|
229
|
+
onConnect: initializationController.handleConnect,
|
|
230
|
+
onInitResult: initializationController.handleInitResult,
|
|
231
|
+
onQueryDataSource: handleQuery,
|
|
232
|
+
onUnsubscribeDataSourceQuery: message => querySubscriptions.unsubscribe(message.subscriptionId),
|
|
233
|
+
onCreatePage: handleCreatePage,
|
|
234
|
+
onGetPage: handleGetPage,
|
|
235
|
+
onGetUser: handleGetUser,
|
|
236
|
+
onListUsers: handleListUsers,
|
|
237
|
+
onUpdatePage: handleUpdatePage,
|
|
238
|
+
onResize: message => handlers.resize?.(message),
|
|
239
|
+
});
|
|
322
240
|
window.addEventListener("message", onMessage);
|
|
323
241
|
iframe.addEventListener("load", initializationController.onIframeLoad);
|
|
324
242
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initErrors.d.ts","sourceRoot":"","sources":["../../src/lifecycle/initErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,MAAM,mDAAmD,CAAA;AAK1D;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACxC,MAAM,EAAE,wBAAwB,EAChC,IAAI,GAAE;IACL,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,4BAA4B,CAAC,EAAE,MAAM,CAAA;CAChC,GACJ,wBAAwB,
|
|
1
|
+
{"version":3,"file":"initErrors.d.ts","sourceRoot":"","sources":["../../src/lifecycle/initErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,wBAAwB,EACxB,wBAAwB,EACxB,MAAM,mDAAmD,CAAA;AAK1D;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACxC,MAAM,EAAE,wBAAwB,EAChC,IAAI,GAAE;IACL,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,4BAA4B,CAAC,EAAE,MAAM,CAAA;CAChC,GACJ,wBAAwB,CA+I1B"}
|
|
@@ -59,6 +59,12 @@ export function initErrorForFailureReason(reason, data = {}) {
|
|
|
59
59
|
isRetryable: false,
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
case "init_timeout":
|
|
63
|
+
return {
|
|
64
|
+
code: reason,
|
|
65
|
+
message: "Host dependencies did not finish loading before the timeout.",
|
|
66
|
+
isRetryable: true,
|
|
67
|
+
};
|
|
62
68
|
case "context_unavailable":
|
|
63
69
|
return {
|
|
64
70
|
code: reason,
|
|
@@ -127,12 +133,6 @@ export function initErrorForFailureReason(reason, data = {}) {
|
|
|
127
133
|
// The block must be embedded in an iframe.
|
|
128
134
|
isRetryable: false,
|
|
129
135
|
};
|
|
130
|
-
case "init_timeout":
|
|
131
|
-
return {
|
|
132
|
-
code: reason,
|
|
133
|
-
message: "Host did not respond to the `connect` message before the timeout.",
|
|
134
|
-
isRetryable: true,
|
|
135
|
-
};
|
|
136
136
|
case "unknown_error":
|
|
137
137
|
return {
|
|
138
138
|
code: reason,
|
|
@@ -45,8 +45,14 @@ export type InitializationController = {
|
|
|
45
45
|
readonly hasConnectedSandbox: boolean;
|
|
46
46
|
handleConnect: (message: ConnectMessage) => void;
|
|
47
47
|
handleInitResult: (message: InitResultMessage) => void;
|
|
48
|
-
handleInvalidConnect: (
|
|
49
|
-
|
|
48
|
+
handleInvalidConnect: (args: {
|
|
49
|
+
initializationId: string;
|
|
50
|
+
error: CustomBlockInitErrorInfo;
|
|
51
|
+
}) => "initErrorSent" | "nack";
|
|
52
|
+
handleInvalidInitResult: (args: {
|
|
53
|
+
initializationId: string | undefined;
|
|
54
|
+
error: CustomBlockInitErrorInfo;
|
|
55
|
+
}) => void;
|
|
50
56
|
onIframeLoad: () => void;
|
|
51
57
|
stop: () => void;
|
|
52
58
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initializationController.d.ts","sourceRoot":"","sources":["../../src/lifecycle/initializationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAA;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AACtG,OAAO,KAAK,EACX,wBAAwB,EAExB,MAAM,mDAAmD,CAAA;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,sBAAsB,CAAA;AAGhF,OAAO,KAAK,EACX,qBAAqB,EACrB,iCAAiC,EACjC,UAAU,EACV,MAAM,YAAY,CAAA;AAKnB,KAAK,mBAAmB,GAAG;IAC1B,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,UAAU,CAAA;CACvB,CAAA;AAED,KAAK,yBAAyB,GAC3B;IACA,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,WAAW,EAAE,iCAAiC,CAAA;CAC7C,GACD;IACA,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,wBAAwB,CAAA;CAC9B,CAAA;AAEJ,MAAM,MAAM,+BAA+B,GAAG;IAC7C,OAAO,EAAE,aAAa,CAAA;IACtB,QAAQ,EAAE,MAAM,mBAAmB,CAAA;IACnC,WAAW,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,yBAAyB,CAAA;IAC1E,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,4BAA4B,EAAE,MAAM,IAAI,CAAA;IACxC,wBAAwB,EAAE,MAAM,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACnD,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,oCAAoC,KACvC,IAAI,CAAA;CACT,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAA;IACrC,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAA;IAChD,gBAAgB,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACtD,oBAAoB,EAAE,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"initializationController.d.ts","sourceRoot":"","sources":["../../src/lifecycle/initializationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAA;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AACtG,OAAO,KAAK,EACX,wBAAwB,EAExB,MAAM,mDAAmD,CAAA;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,sBAAsB,CAAA;AAGhF,OAAO,KAAK,EACX,qBAAqB,EACrB,iCAAiC,EACjC,UAAU,EACV,MAAM,YAAY,CAAA;AAKnB,KAAK,mBAAmB,GAAG;IAC1B,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,UAAU,CAAA;CACvB,CAAA;AAED,KAAK,yBAAyB,GAC3B;IACA,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,WAAW,EAAE,iCAAiC,CAAA;CAC7C,GACD;IACA,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,wBAAwB,CAAA;CAC9B,CAAA;AAEJ,MAAM,MAAM,+BAA+B,GAAG;IAC7C,OAAO,EAAE,aAAa,CAAA;IACtB,QAAQ,EAAE,MAAM,mBAAmB,CAAA;IACnC,WAAW,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,yBAAyB,CAAA;IAC1E,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,4BAA4B,EAAE,MAAM,IAAI,CAAA;IACxC,wBAAwB,EAAE,MAAM,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACnD,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,oCAAoC,KACvC,IAAI,CAAA;CACT,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAA;IACrC,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAA;IAChD,gBAAgB,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACtD,oBAAoB,EAAE,CAAC,IAAI,EAAE;QAC5B,gBAAgB,EAAE,MAAM,CAAA;QACxB,KAAK,EAAE,wBAAwB,CAAA;KAC/B,KAAK,eAAe,GAAG,MAAM,CAAA;IAC9B,uBAAuB,EAAE,CAAC,IAAI,EAAE;QAC/B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;QACpC,KAAK,EAAE,wBAAwB,CAAA;KAC/B,KAAK,IAAI,CAAA;IACV,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,IAAI,EAAE,MAAM,IAAI,CAAA;CAChB,CAAA;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,+BAA+B,GACtC,wBAAwB,CAyP1B"}
|
|
@@ -21,7 +21,8 @@ export function createInitializationController(options) {
|
|
|
21
21
|
noInitResultTimeoutId = undefined;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
function sendInitError(
|
|
24
|
+
function sendInitError(args) {
|
|
25
|
+
const { initializationId, error } = args;
|
|
25
26
|
if (initStatus !== "waitingForConnect") {
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
@@ -42,7 +43,10 @@ export function createInitializationController(options) {
|
|
|
42
43
|
}
|
|
43
44
|
const preparation = prepareInit(connect);
|
|
44
45
|
if (preparation.status === "error") {
|
|
45
|
-
sendInitError(
|
|
46
|
+
sendInitError({
|
|
47
|
+
initializationId: connect.initializationId,
|
|
48
|
+
error: preparation.error,
|
|
49
|
+
});
|
|
46
50
|
return false;
|
|
47
51
|
}
|
|
48
52
|
initStatus = "waitingForInitResult";
|
|
@@ -96,7 +100,10 @@ export function createInitializationController(options) {
|
|
|
96
100
|
const initError = initErrorForFailureReason("invalid_protocol_version", {
|
|
97
101
|
currentBridgeProtocolVersion: message.bridgeProtocolVersion,
|
|
98
102
|
});
|
|
99
|
-
sendInitError(
|
|
103
|
+
sendInitError({
|
|
104
|
+
initializationId: message.initializationId,
|
|
105
|
+
error: initError,
|
|
106
|
+
});
|
|
100
107
|
return;
|
|
101
108
|
}
|
|
102
109
|
if (message.bridgeProtocolVersion < minBridgeProtocolVersion) {
|
|
@@ -104,44 +111,46 @@ export function createInitializationController(options) {
|
|
|
104
111
|
currentBridgeProtocolVersion: message.bridgeProtocolVersion,
|
|
105
112
|
minBridgeProtocolVersion,
|
|
106
113
|
});
|
|
107
|
-
sendInitError(
|
|
114
|
+
sendInitError({
|
|
115
|
+
initializationId: message.initializationId,
|
|
116
|
+
error: initError,
|
|
117
|
+
});
|
|
108
118
|
return;
|
|
109
119
|
}
|
|
110
120
|
// If the sandbox reported an error during `connect`, return it as an `init` error.
|
|
111
121
|
if (message.status === "error") {
|
|
112
|
-
sendInitError(
|
|
122
|
+
sendInitError({
|
|
123
|
+
initializationId: message.initializationId,
|
|
124
|
+
error: message.error,
|
|
125
|
+
});
|
|
113
126
|
return;
|
|
114
127
|
}
|
|
115
128
|
if (sendInit(message)) {
|
|
116
129
|
hasConnectedSandbox = true;
|
|
117
130
|
}
|
|
118
131
|
}
|
|
119
|
-
function handleInvalidConnect(
|
|
132
|
+
function handleInvalidConnect(args) {
|
|
133
|
+
const { initializationId, error } = args;
|
|
120
134
|
if (initStatus !== "waitingForConnect") {
|
|
121
|
-
|
|
135
|
+
// `connect` messages received when not waiting for one are NACKed like generic invalid messages.
|
|
136
|
+
return "nack";
|
|
122
137
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
clearNoConnectTimeout();
|
|
127
|
-
warn(error);
|
|
128
|
-
onInitializationFailure?.(error);
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
sendInitError(initializationId, error);
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
138
|
+
// The sandbox awaits `init`. Reply with `init.error` using its initialization ID.
|
|
139
|
+
sendInitError({ initializationId, error });
|
|
140
|
+
return "initErrorSent";
|
|
134
141
|
}
|
|
135
|
-
function handleInvalidInitResult() {
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
function handleInvalidInitResult(args) {
|
|
143
|
+
const { initializationId, error } = args;
|
|
144
|
+
if (initStatus !== "waitingForInitResult" ||
|
|
145
|
+
initializationId === undefined ||
|
|
146
|
+
initializationId !== activeInitializationId) {
|
|
147
|
+
return;
|
|
138
148
|
}
|
|
149
|
+
clearNoConnectTimeout();
|
|
139
150
|
clearNoInitResultTimeout();
|
|
140
151
|
initStatus = "error";
|
|
141
|
-
const error = initErrorForFailureReason("invalid_init_result_payload");
|
|
142
152
|
warn(error);
|
|
143
153
|
onInitializationFailure?.(error);
|
|
144
|
-
return true;
|
|
145
154
|
}
|
|
146
155
|
function onIframeLoad() {
|
|
147
156
|
clearNoConnectTimeout();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readIncomingType } from "../protocol/incomingType.js";
|
|
1
|
+
import { readIncomingType } from "../protocol/messages/incomingType.js";
|
|
2
2
|
export function getInvalidSandboxMessageResponse(data) {
|
|
3
3
|
const incomingType = readIncomingType(data);
|
|
4
4
|
if (incomingType === "invalidHostMessage" ||
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ConnectMessage } from "../protocol/messages/connect.js";
|
|
2
|
+
import type { CreatePageMessage } from "../protocol/messages/createPage.js";
|
|
3
|
+
import type { GetPageMessage } from "../protocol/messages/getPage.js";
|
|
4
|
+
import type { GetUserMessage } from "../protocol/messages/getUser.js";
|
|
5
|
+
import type { HostToSandboxMessage } from "../protocol/messages/hostToSandbox.js";
|
|
6
|
+
import type { InitResultMessage } from "../protocol/messages/initResult.js";
|
|
7
|
+
import type { ListUsersMessage } from "../protocol/messages/listUsers.js";
|
|
8
|
+
import type { QueryDataSourceMessage } from "../protocol/messages/queryDataSource.js";
|
|
9
|
+
import type { ResizeMessage } from "../protocol/messages/resize.js";
|
|
10
|
+
import type { UnsubscribeDataSourceQueryMessage } from "../protocol/messages/unsubscribeDataSourceQuery.js";
|
|
11
|
+
import type { UpdatePageMessage } from "../protocol/messages/updatePage.js";
|
|
12
|
+
import type { InitializationController } from "../lifecycle/initializationController.js";
|
|
13
|
+
import type { InitStatus } from "../lifecycle/types.js";
|
|
14
|
+
import type { CustomBlockHostLogDirection } from "./types.js";
|
|
15
|
+
export type SandboxMessageRouterOptions = {
|
|
16
|
+
iframe: HTMLIFrameElement;
|
|
17
|
+
sandboxOrigin: string;
|
|
18
|
+
getInitStatus: () => InitStatus;
|
|
19
|
+
emit: (direction: CustomBlockHostLogDirection, payload: unknown) => void;
|
|
20
|
+
post: (message: HostToSandboxMessage) => void;
|
|
21
|
+
onInvalidConnect: InitializationController["handleInvalidConnect"];
|
|
22
|
+
onInvalidInitResult: InitializationController["handleInvalidInitResult"];
|
|
23
|
+
onConnect: (message: ConnectMessage) => void;
|
|
24
|
+
onInitResult: (message: InitResultMessage) => void;
|
|
25
|
+
onQueryDataSource: (message: QueryDataSourceMessage) => void | Promise<void>;
|
|
26
|
+
onUnsubscribeDataSourceQuery: (message: UnsubscribeDataSourceQueryMessage) => void;
|
|
27
|
+
onCreatePage: (message: CreatePageMessage) => void | Promise<void>;
|
|
28
|
+
onGetPage: (message: GetPageMessage) => void | Promise<void>;
|
|
29
|
+
onGetUser: (message: GetUserMessage) => void | Promise<void>;
|
|
30
|
+
onListUsers: (message: ListUsersMessage) => void | Promise<void>;
|
|
31
|
+
onUpdatePage: (message: UpdatePageMessage) => void | Promise<void>;
|
|
32
|
+
onResize: (message: ResizeMessage) => void;
|
|
33
|
+
};
|
|
34
|
+
export declare function createSandboxMessageRouter(options: SandboxMessageRouterOptions): (event: MessageEvent) => void;
|
|
35
|
+
//# sourceMappingURL=sandboxMessageRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandboxMessageRouter.d.ts","sourceRoot":"","sources":["../../src/messages/sandboxMessageRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAA;AAC1F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAA;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAA;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AACtG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wDAAwD,CAAA;AAC9F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAA;AAC1G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qDAAqD,CAAA;AAExF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,yEAAyE,CAAA;AAChI,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAGhG,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAA;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAM7D,MAAM,MAAM,2BAA2B,GAAG;IACzC,MAAM,EAAE,iBAAiB,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,UAAU,CAAA;IAC/B,IAAI,EAAE,CAAC,SAAS,EAAE,2BAA2B,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IACxE,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC7C,gBAAgB,EAAE,wBAAwB,CAAC,sBAAsB,CAAC,CAAA;IAClE,mBAAmB,EAAE,wBAAwB,CAAC,yBAAyB,CAAC,CAAA;IACxE,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAA;IAC5C,YAAY,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAClD,iBAAiB,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5E,4BAA4B,EAAE,CAC7B,OAAO,EAAE,iCAAiC,KACtC,IAAI,CAAA;IACT,YAAY,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,WAAW,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,YAAY,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,0BAA0B,CACzC,OAAO,EAAE,2BAA2B,GAClC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CA8H/B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isInitHandshakeMessage } from "../protocol/messages/isInitHandshakeMessage.js";
|
|
2
|
+
import { sandboxToHostMessageSchema } from "../protocol/messages/sandboxToHost.js";
|
|
3
|
+
import * as v from "valibot";
|
|
4
|
+
import { initErrorForFailureReason } from "../lifecycle/initErrors.js";
|
|
5
|
+
import { unreachable } from "../utils.js";
|
|
6
|
+
import { getInvalidSandboxMessageResponse } from "./invalidSandboxMessage.js";
|
|
7
|
+
const initializationIdentitySchema = v.object({
|
|
8
|
+
initializationId: v.string(),
|
|
9
|
+
});
|
|
10
|
+
export function createSandboxMessageRouter(options) {
|
|
11
|
+
const { iframe, sandboxOrigin, getInitStatus, emit, post, onInvalidConnect, onInvalidInitResult, onConnect, onInitResult, onQueryDataSource, onUnsubscribeDataSourceQuery, onCreatePage, onGetPage, onGetUser, onListUsers, onUpdatePage, onResize, } = options;
|
|
12
|
+
function onInvalidSandboxMessage(data, issues) {
|
|
13
|
+
emit("warn", {
|
|
14
|
+
message: "Ignored unsupported sandbox message",
|
|
15
|
+
payload: data,
|
|
16
|
+
issues,
|
|
17
|
+
});
|
|
18
|
+
const response = getInvalidSandboxMessageResponse(data);
|
|
19
|
+
if (response.incomingType === "connect") {
|
|
20
|
+
const parsedIdentity = v.safeParse(initializationIdentitySchema, data);
|
|
21
|
+
if (parsedIdentity.success) {
|
|
22
|
+
const responseType = onInvalidConnect({
|
|
23
|
+
initializationId: parsedIdentity.output.initializationId,
|
|
24
|
+
error: initErrorForFailureReason("invalid_connect_payload"),
|
|
25
|
+
});
|
|
26
|
+
if (responseType === "initErrorSent") {
|
|
27
|
+
// The controller already sent `init.error`, so no need to also send a NACK.
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (response.incomingType === "initResult") {
|
|
33
|
+
const parsedIdentity = v.safeParse(initializationIdentitySchema, data);
|
|
34
|
+
onInvalidInitResult({
|
|
35
|
+
initializationId: parsedIdentity.success
|
|
36
|
+
? parsedIdentity.output.initializationId
|
|
37
|
+
: undefined,
|
|
38
|
+
error: initErrorForFailureReason("invalid_init_result_payload"),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Other messages get NACKed indicating they were invalid and skipped
|
|
42
|
+
if (response.nack !== undefined) {
|
|
43
|
+
post(response.nack);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return function onMessage(event) {
|
|
47
|
+
// Verify the sender is this host's iframe, not another window with the same origin.
|
|
48
|
+
const isExpectedSource = event.source === iframe.contentWindow;
|
|
49
|
+
// Verify the sender's origin, since the iframe can navigate to another origin.
|
|
50
|
+
const isExpectedOrigin = event.origin === sandboxOrigin;
|
|
51
|
+
if (!isExpectedSource || !isExpectedOrigin) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Parse and validate the message from the sandbox.
|
|
55
|
+
const parsed = v.safeParse(sandboxToHostMessageSchema, event.data);
|
|
56
|
+
if (!parsed.success) {
|
|
57
|
+
onInvalidSandboxMessage(event.data, parsed.issues);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const message = parsed.output;
|
|
61
|
+
if (!isInitHandshakeMessage(message) && getInitStatus() !== "success") {
|
|
62
|
+
emit("warn", {
|
|
63
|
+
message: `Ignored ${message.type} before initialization completed`,
|
|
64
|
+
payload: message,
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
emit("in", message);
|
|
69
|
+
switch (message.type) {
|
|
70
|
+
case "connect":
|
|
71
|
+
onConnect(message);
|
|
72
|
+
return;
|
|
73
|
+
case "initResult":
|
|
74
|
+
onInitResult(message);
|
|
75
|
+
return;
|
|
76
|
+
case "queryDataSource":
|
|
77
|
+
void onQueryDataSource(message);
|
|
78
|
+
return;
|
|
79
|
+
case "unsubscribeDataSourceQuery":
|
|
80
|
+
onUnsubscribeDataSourceQuery(message);
|
|
81
|
+
return;
|
|
82
|
+
case "createPage":
|
|
83
|
+
void onCreatePage(message);
|
|
84
|
+
return;
|
|
85
|
+
case "getPage":
|
|
86
|
+
void onGetPage(message);
|
|
87
|
+
return;
|
|
88
|
+
case "getUser":
|
|
89
|
+
void onGetUser(message);
|
|
90
|
+
return;
|
|
91
|
+
case "listUsers":
|
|
92
|
+
void onListUsers(message);
|
|
93
|
+
return;
|
|
94
|
+
case "updatePage":
|
|
95
|
+
void onUpdatePage(message);
|
|
96
|
+
return;
|
|
97
|
+
case "resize":
|
|
98
|
+
onResize(message);
|
|
99
|
+
return;
|
|
100
|
+
case "invalidHostMessage":
|
|
101
|
+
// The inbound log records this rejection. Do not reply, to avoid an error-response loop.
|
|
102
|
+
return;
|
|
103
|
+
default:
|
|
104
|
+
unreachable(message);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
package/dist/messages/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { BridgeMessagePayload } from "../protocol/messagePayload.js";
|
|
2
1
|
import type { CreatePageMessage } from "../protocol/messages/createPage.js";
|
|
3
2
|
import type { CreatePageResultMessage, CustomBlockCreatePageErrorInfo } from "../protocol/messages/createPageResult.js";
|
|
4
3
|
import type { CustomBlockGetPageErrorInfo, GetPageMessage, GetPageResultMessage } from "../protocol/messages/getPage.js";
|
|
@@ -6,6 +5,7 @@ import type { CustomBlockGetUserErrorInfo, GetUserMessage, GetUserResultMessage
|
|
|
6
5
|
import type { CustomBlockInitErrorInfo } from "../protocol/messages/init.js";
|
|
7
6
|
import type { CustomBlockInitResultErrorInfo } from "../protocol/messages/initResult.js";
|
|
8
7
|
import type { CustomBlockListUsersErrorInfo, ListUsersMessage, ListUsersResultMessage } from "../protocol/messages/listUsers.js";
|
|
8
|
+
import type { BridgeMessagePayload } from "../protocol/messages/messagePayload.js";
|
|
9
9
|
import type { QueryDataSourceMessage } from "../protocol/messages/queryDataSource.js";
|
|
10
10
|
import type { ResizeMessage } from "../protocol/messages/resize.js";
|
|
11
11
|
import type { UpdatePageMessage } from "../protocol/messages/updatePage.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/messages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/messages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EACX,uBAAuB,EACvB,8BAA8B,EAC9B,MAAM,+DAA+D,CAAA;AACtE,OAAO,KAAK,EACX,2BAA2B,EAC3B,cAAc,EACd,oBAAoB,EACpB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EACX,2BAA2B,EAC3B,cAAc,EACd,oBAAoB,EACpB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAA;AACjG,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,yDAAyD,CAAA;AAC7G,OAAO,KAAK,EACX,6BAA6B,EAC7B,gBAAgB,EAChB,sBAAsB,EACtB,MAAM,wDAAwD,CAAA;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AACvG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAA;AAC1G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qDAAqD,CAAA;AACxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EACX,8BAA8B,EAC9B,uBAAuB,EACvB,MAAM,+DAA+D,CAAA;AACtE,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,qBAAqB,CAAA;AAE/E,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAErC,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CACjE,uBAAuB,EACvB,8BAA8B,CAC9B,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,CAC9D,oBAAoB,EACpB,2BAA2B,CAC3B,CAAA;AAED,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CACjE,uBAAuB,EACvB,8BAA8B,CAC9B,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,CAC9D,oBAAoB,EACpB,2BAA2B,CAC3B,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,oBAAoB,CAChE,sBAAsB,EACtB,6BAA6B,CAC7B,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACrC,eAAe,EAAE,CAChB,OAAO,EAAE,sBAAsB,KAC3B,YAAY,CAAC,oCAAoC,CAAC,CAAA;IACvD,UAAU,CAAC,EAAE,CACZ,OAAO,EAAE,iBAAiB,KACtB,YAAY,CAAC,+BAA+B,CAAC,CAAA;IAClD,OAAO,CAAC,EAAE,CACT,OAAO,EAAE,cAAc,KACnB,YAAY,CAAC,4BAA4B,CAAC,CAAA;IAC/C,OAAO,CAAC,EAAE,CACT,OAAO,EAAE,cAAc,KACnB,YAAY,CAAC,4BAA4B,CAAC,CAAA;IAC/C,SAAS,CAAC,EAAE,CACX,OAAO,EAAE,gBAAgB,KACrB,YAAY,CAAC,8BAA8B,CAAC,CAAA;IACjD,UAAU,CAAC,EAAE,CACZ,OAAO,EAAE,iBAAiB,KACtB,YAAY,CAAC,+BAA+B,CAAC,CAAA;IAClD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;CACzC,CAAA;AAED,MAAM,MAAM,oCAAoC,GAC7C,wBAAwB,GACxB,8BAA8B,CAAA;AAEjC,MAAM,MAAM,2BAA2B,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,CAAA"}
|
package/dist/protocol/index.d.ts
CHANGED
|
@@ -15,9 +15,7 @@ export * from "./dataSources/propertySchema.js";
|
|
|
15
15
|
export * from "./dataSources/recordPointer.js";
|
|
16
16
|
export * from "./errors.js";
|
|
17
17
|
export * from "./ids.js";
|
|
18
|
-
export * from "./incomingType.js";
|
|
19
18
|
export * from "./manifest.js";
|
|
20
|
-
export * from "./messagePayload.js";
|
|
21
19
|
export * from "./messages/connect.js";
|
|
22
20
|
export * from "./messages/contrastModeChanged.js";
|
|
23
21
|
export * from "./messages/createPage.js";
|
|
@@ -27,11 +25,14 @@ export * from "./messages/dataSourcesChanged.js";
|
|
|
27
25
|
export * from "./messages/getPage.js";
|
|
28
26
|
export * from "./messages/getUser.js";
|
|
29
27
|
export * from "./messages/hostToSandbox.js";
|
|
28
|
+
export * from "./messages/incomingType.js";
|
|
30
29
|
export * from "./messages/init.js";
|
|
31
30
|
export * from "./messages/initResult.js";
|
|
32
31
|
export * from "./messages/invalidHostMessage.js";
|
|
33
32
|
export * from "./messages/invalidSandboxMessage.js";
|
|
33
|
+
export * from "./messages/isInitHandshakeMessage.js";
|
|
34
34
|
export * from "./messages/listUsers.js";
|
|
35
|
+
export * from "./messages/messagePayload.js";
|
|
35
36
|
export * from "./messages/pageChanged.js";
|
|
36
37
|
export * from "./messages/parentChanged.js";
|
|
37
38
|
export * from "./messages/queryDataSource.js";
|
package/dist/protocol/index.js
CHANGED
|
@@ -15,9 +15,7 @@ export * from "./dataSources/propertySchema.js";
|
|
|
15
15
|
export * from "./dataSources/recordPointer.js";
|
|
16
16
|
export * from "./errors.js";
|
|
17
17
|
export * from "./ids.js";
|
|
18
|
-
export * from "./incomingType.js";
|
|
19
18
|
export * from "./manifest.js";
|
|
20
|
-
export * from "./messagePayload.js";
|
|
21
19
|
export * from "./messages/connect.js";
|
|
22
20
|
export * from "./messages/contrastModeChanged.js";
|
|
23
21
|
export * from "./messages/createPage.js";
|
|
@@ -27,11 +25,14 @@ export * from "./messages/dataSourcesChanged.js";
|
|
|
27
25
|
export * from "./messages/getPage.js";
|
|
28
26
|
export * from "./messages/getUser.js";
|
|
29
27
|
export * from "./messages/hostToSandbox.js";
|
|
28
|
+
export * from "./messages/incomingType.js";
|
|
30
29
|
export * from "./messages/init.js";
|
|
31
30
|
export * from "./messages/initResult.js";
|
|
32
31
|
export * from "./messages/invalidHostMessage.js";
|
|
33
32
|
export * from "./messages/invalidSandboxMessage.js";
|
|
33
|
+
export * from "./messages/isInitHandshakeMessage.js";
|
|
34
34
|
export * from "./messages/listUsers.js";
|
|
35
|
+
export * from "./messages/messagePayload.js";
|
|
35
36
|
export * from "./messages/pageChanged.js";
|
|
36
37
|
export * from "./messages/parentChanged.js";
|
|
37
38
|
export * from "./messages/queryDataSource.js";
|
|
@@ -2,14 +2,14 @@ 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_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">;
|
|
5
|
+
export type CustomBlockInitErrorCode = CustomBlockErrorCode<"manifest_unavailable" | "manifest_invalid" | "invalid_connect_payload" | "invalid_protocol_version" | "unsupported_protocol_version" | "init_timeout" | "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
|
|
9
9
|
* received in `init`, errors the sandbox reports in `initResult`, and failures
|
|
10
10
|
* detected locally while running `initCustomBlock()`.
|
|
11
11
|
*/
|
|
12
|
-
export type CustomBlockInitializationErrorCode = CustomBlockInitErrorCode | CustomBlockInitResultErrorCode | CustomBlockErrorCode<"not_in_iframe"
|
|
12
|
+
export type CustomBlockInitializationErrorCode = CustomBlockInitErrorCode | CustomBlockInitResultErrorCode | CustomBlockErrorCode<"not_in_iframe">;
|
|
13
13
|
export type CustomBlockInitializationErrorInfo = CustomBlockErrorInfo<CustomBlockInitializationErrorCode>;
|
|
14
14
|
export declare const customBlockInitErrorInfoSchema: v.ObjectSchema<{
|
|
15
15
|
readonly code: v.StringSchema<undefined>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HostToSandboxMessage } from "./hostToSandbox.js";
|
|
2
|
+
import type { SandboxToHostMessage } from "./sandboxToHost.js";
|
|
3
|
+
/** Returns whether a message belongs to the initialization handshake. */
|
|
4
|
+
export declare function isInitHandshakeMessage(message: SandboxToHostMessage | HostToSandboxMessage): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CustomBlockErrorInfo } from "
|
|
1
|
+
import type { CustomBlockErrorInfo } from "../errors.js";
|
|
2
2
|
type WithTypedErrorInfo<T, TErrorInfo extends CustomBlockErrorInfo | undefined> = TErrorInfo extends CustomBlockErrorInfo ? T extends {
|
|
3
3
|
error: CustomBlockErrorInfo;
|
|
4
4
|
} ? Omit<T, "error"> & {
|
package/dist/queries/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BridgeMessagePayload } from "../protocol/messagePayload.js";
|
|
1
|
+
import type { BridgeMessagePayload } from "../protocol/messages/messagePayload.js";
|
|
2
2
|
import type { CustomBlockQueryDataSourceErrorInfo, QueryDataSourceResultMessage } from "../protocol/messages/queryDataSourceResult.js";
|
|
3
3
|
export type CustomBlockHostQueryDataSourceResult = BridgeMessagePayload<QueryDataSourceResultMessage, CustomBlockQueryDataSourceErrorInfo>;
|
|
4
4
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/queries/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/queries/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AACvG,OAAO,KAAK,EACX,mCAAmC,EACnC,4BAA4B,EAC5B,MAAM,oEAAoE,CAAA;AAE3E,MAAM,MAAM,oCAAoC,GAAG,oBAAoB,CACtE,4BAA4B,EAC5B,mCAAmC,CACnC,CAAA"}
|
package/package.json
CHANGED
|
@@ -26,7 +26,6 @@ import type { PageChangedMessage } from "@notionhq/custom-blocks-protocol/messag
|
|
|
26
26
|
import type { ParentChangedMessage } from "@notionhq/custom-blocks-protocol/messages/parentChanged.js"
|
|
27
27
|
import type { QueryDataSourceMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSource.js"
|
|
28
28
|
import type { QueryDataSourceResultMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSourceResult.js"
|
|
29
|
-
import { sandboxToHostMessageSchema } from "@notionhq/custom-blocks-protocol/messages/sandboxToHost.js"
|
|
30
29
|
import type { ThemeChangedMessage } from "@notionhq/custom-blocks-protocol/messages/themeChanged.js"
|
|
31
30
|
import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
|
|
32
31
|
import type { UpdatePageResultMessage } from "@notionhq/custom-blocks-protocol/messages/updatePageResult.js"
|
|
@@ -35,14 +34,13 @@ import type { NotionParent } from "@notionhq/custom-blocks-protocol/parent.js"
|
|
|
35
34
|
import { CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION } from "@notionhq/custom-blocks-protocol/protocolVersion.js"
|
|
36
35
|
import type { NotionTheme } from "@notionhq/custom-blocks-protocol/theme.js"
|
|
37
36
|
import type { NotionUser } from "@notionhq/custom-blocks-protocol/users/user.js"
|
|
38
|
-
import * as v from "valibot"
|
|
39
37
|
import { initErrorForFailureReason } from "./lifecycle/initErrors.js"
|
|
40
38
|
import { createInitializationController } from "./lifecycle/initializationController.js"
|
|
41
39
|
import type {
|
|
42
40
|
CustomBlockHostDataSourcesPayload,
|
|
43
41
|
CustomBlockHostInitialState,
|
|
44
42
|
} from "./lifecycle/types.js"
|
|
45
|
-
import {
|
|
43
|
+
import { createSandboxMessageRouter } from "./messages/sandboxMessageRouter.js"
|
|
46
44
|
import type {
|
|
47
45
|
CustomBlockHostHandlers,
|
|
48
46
|
CustomBlockHostInitializationFailure,
|
|
@@ -55,7 +53,6 @@ import {
|
|
|
55
53
|
import type { CustomBlockHostQueryDataSourceResult } from "./queries/types.js"
|
|
56
54
|
import { validateQueryDataSourceFilter } from "./queries/validateQueryDataSourceFilter.js"
|
|
57
55
|
import { validateQueryDataSourceSorts } from "./queries/validateQueryDataSourceSorts.js"
|
|
58
|
-
import { unreachable } from "./utils.js"
|
|
59
56
|
|
|
60
57
|
export type CustomBlockHostOptions = {
|
|
61
58
|
iframe: HTMLIFrameElement
|
|
@@ -96,10 +93,6 @@ export type CustomBlockHostHandle = {
|
|
|
96
93
|
refreshQuery: (args: { dataSourceId: NotionDataSourceId }) => void
|
|
97
94
|
}
|
|
98
95
|
|
|
99
|
-
const initializationIdentitySchema = v.object({
|
|
100
|
-
initializationId: v.string(),
|
|
101
|
-
})
|
|
102
|
-
|
|
103
96
|
export function createCustomBlockHost(
|
|
104
97
|
options: CustomBlockHostOptions,
|
|
105
98
|
): CustomBlockHostHandle {
|
|
@@ -363,115 +356,26 @@ export function createCustomBlockHost(
|
|
|
363
356
|
onInitializationFailure,
|
|
364
357
|
})
|
|
365
358
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
emit
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (
|
|
390
|
-
response.incomingType === "initResult" &&
|
|
391
|
-
initializationController.handleInvalidInitResult()
|
|
392
|
-
) {
|
|
393
|
-
if (response.nack !== undefined) {
|
|
394
|
-
post(response.nack)
|
|
395
|
-
}
|
|
396
|
-
return
|
|
397
|
-
}
|
|
398
|
-
if (response.nack !== undefined) {
|
|
399
|
-
post(response.nack)
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
function onMessage(event: MessageEvent) {
|
|
404
|
-
// Ignore messages from windows other than this host's iframe.
|
|
405
|
-
if (event.source !== iframe.contentWindow) {
|
|
406
|
-
return
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// Ignore messages that do not come from the configured sandbox origin.
|
|
410
|
-
if (event.origin !== sandboxOrigin) {
|
|
411
|
-
return
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const parsed = v.safeParse(sandboxToHostMessageSchema, event.data)
|
|
415
|
-
if (!parsed.success) {
|
|
416
|
-
onInvalidSandboxMessage(event.data, parsed.issues)
|
|
417
|
-
return
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const message = parsed.output
|
|
421
|
-
emit("in", message)
|
|
422
|
-
|
|
423
|
-
if (
|
|
424
|
-
message.type !== "connect" &&
|
|
425
|
-
message.type !== "initResult" &&
|
|
426
|
-
initializationController.status !== "success"
|
|
427
|
-
) {
|
|
428
|
-
// Ignore all non-handshake messages until initialization succeeds.
|
|
429
|
-
if (message.type !== "resize") {
|
|
430
|
-
emit("warn", {
|
|
431
|
-
message: `Ignored ${message.type} before initialization completed`,
|
|
432
|
-
payload: message,
|
|
433
|
-
})
|
|
434
|
-
}
|
|
435
|
-
return
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
switch (message.type) {
|
|
439
|
-
case "connect":
|
|
440
|
-
initializationController.handleConnect(message)
|
|
441
|
-
return
|
|
442
|
-
case "initResult":
|
|
443
|
-
initializationController.handleInitResult(message)
|
|
444
|
-
return
|
|
445
|
-
case "queryDataSource":
|
|
446
|
-
void handleQuery(message)
|
|
447
|
-
return
|
|
448
|
-
case "unsubscribeDataSourceQuery":
|
|
449
|
-
querySubscriptions.unsubscribe(message.subscriptionId)
|
|
450
|
-
return
|
|
451
|
-
case "createPage":
|
|
452
|
-
void handleCreatePage(message)
|
|
453
|
-
return
|
|
454
|
-
case "getPage":
|
|
455
|
-
void handleGetPage(message)
|
|
456
|
-
return
|
|
457
|
-
case "getUser":
|
|
458
|
-
void handleGetUser(message)
|
|
459
|
-
return
|
|
460
|
-
case "listUsers":
|
|
461
|
-
void handleListUsers(message)
|
|
462
|
-
return
|
|
463
|
-
case "updatePage":
|
|
464
|
-
void handleUpdatePage(message)
|
|
465
|
-
return
|
|
466
|
-
case "resize":
|
|
467
|
-
handlers.resize?.(message)
|
|
468
|
-
return
|
|
469
|
-
case "invalidHostMessage":
|
|
470
|
-
return
|
|
471
|
-
default:
|
|
472
|
-
unreachable(message)
|
|
473
|
-
}
|
|
474
|
-
}
|
|
359
|
+
const onMessage = createSandboxMessageRouter({
|
|
360
|
+
iframe,
|
|
361
|
+
sandboxOrigin,
|
|
362
|
+
getInitStatus: () => initializationController.status,
|
|
363
|
+
emit,
|
|
364
|
+
post,
|
|
365
|
+
onInvalidConnect: initializationController.handleInvalidConnect,
|
|
366
|
+
onInvalidInitResult: initializationController.handleInvalidInitResult,
|
|
367
|
+
onConnect: initializationController.handleConnect,
|
|
368
|
+
onInitResult: initializationController.handleInitResult,
|
|
369
|
+
onQueryDataSource: handleQuery,
|
|
370
|
+
onUnsubscribeDataSourceQuery: message =>
|
|
371
|
+
querySubscriptions.unsubscribe(message.subscriptionId),
|
|
372
|
+
onCreatePage: handleCreatePage,
|
|
373
|
+
onGetPage: handleGetPage,
|
|
374
|
+
onGetUser: handleGetUser,
|
|
375
|
+
onListUsers: handleListUsers,
|
|
376
|
+
onUpdatePage: handleUpdatePage,
|
|
377
|
+
onResize: message => handlers.resize?.(message),
|
|
378
|
+
})
|
|
475
379
|
|
|
476
380
|
window.addEventListener("message", onMessage)
|
|
477
381
|
iframe.addEventListener("load", initializationController.onIframeLoad)
|
|
@@ -72,6 +72,12 @@ export function initErrorForFailureReason(
|
|
|
72
72
|
isRetryable: false,
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
+
case "init_timeout":
|
|
76
|
+
return {
|
|
77
|
+
code: reason,
|
|
78
|
+
message: "Host dependencies did not finish loading before the timeout.",
|
|
79
|
+
isRetryable: true,
|
|
80
|
+
}
|
|
75
81
|
case "context_unavailable":
|
|
76
82
|
return {
|
|
77
83
|
code: reason,
|
|
@@ -140,13 +146,6 @@ export function initErrorForFailureReason(
|
|
|
140
146
|
// The block must be embedded in an iframe.
|
|
141
147
|
isRetryable: false,
|
|
142
148
|
}
|
|
143
|
-
case "init_timeout":
|
|
144
|
-
return {
|
|
145
|
-
code: reason,
|
|
146
|
-
message:
|
|
147
|
-
"Host did not respond to the `connect` message before the timeout.",
|
|
148
|
-
isRetryable: true,
|
|
149
|
-
}
|
|
150
149
|
case "unknown_error":
|
|
151
150
|
return {
|
|
152
151
|
code: reason,
|
|
@@ -65,8 +65,14 @@ export type InitializationController = {
|
|
|
65
65
|
readonly hasConnectedSandbox: boolean
|
|
66
66
|
handleConnect: (message: ConnectMessage) => void
|
|
67
67
|
handleInitResult: (message: InitResultMessage) => void
|
|
68
|
-
handleInvalidConnect: (
|
|
69
|
-
|
|
68
|
+
handleInvalidConnect: (args: {
|
|
69
|
+
initializationId: string
|
|
70
|
+
error: CustomBlockInitErrorInfo
|
|
71
|
+
}) => "initErrorSent" | "nack"
|
|
72
|
+
handleInvalidInitResult: (args: {
|
|
73
|
+
initializationId: string | undefined
|
|
74
|
+
error: CustomBlockInitErrorInfo
|
|
75
|
+
}) => void
|
|
70
76
|
onIframeLoad: () => void
|
|
71
77
|
stop: () => void
|
|
72
78
|
}
|
|
@@ -109,10 +115,11 @@ export function createInitializationController(
|
|
|
109
115
|
}
|
|
110
116
|
}
|
|
111
117
|
|
|
112
|
-
function sendInitError(
|
|
113
|
-
initializationId: string
|
|
114
|
-
error: CustomBlockInitErrorInfo
|
|
115
|
-
) {
|
|
118
|
+
function sendInitError(args: {
|
|
119
|
+
initializationId: string
|
|
120
|
+
error: CustomBlockInitErrorInfo
|
|
121
|
+
}) {
|
|
122
|
+
const { initializationId, error } = args
|
|
116
123
|
if (initStatus !== "waitingForConnect") {
|
|
117
124
|
return
|
|
118
125
|
}
|
|
@@ -134,7 +141,10 @@ export function createInitializationController(
|
|
|
134
141
|
}
|
|
135
142
|
const preparation = prepareInit(connect)
|
|
136
143
|
if (preparation.status === "error") {
|
|
137
|
-
sendInitError(
|
|
144
|
+
sendInitError({
|
|
145
|
+
initializationId: connect.initializationId,
|
|
146
|
+
error: preparation.error,
|
|
147
|
+
})
|
|
138
148
|
return false
|
|
139
149
|
}
|
|
140
150
|
initStatus = "waitingForInitResult"
|
|
@@ -191,7 +201,10 @@ export function createInitializationController(
|
|
|
191
201
|
const initError = initErrorForFailureReason("invalid_protocol_version", {
|
|
192
202
|
currentBridgeProtocolVersion: message.bridgeProtocolVersion,
|
|
193
203
|
})
|
|
194
|
-
sendInitError(
|
|
204
|
+
sendInitError({
|
|
205
|
+
initializationId: message.initializationId,
|
|
206
|
+
error: initError,
|
|
207
|
+
})
|
|
195
208
|
return
|
|
196
209
|
}
|
|
197
210
|
if (message.bridgeProtocolVersion < minBridgeProtocolVersion) {
|
|
@@ -202,13 +215,19 @@ export function createInitializationController(
|
|
|
202
215
|
minBridgeProtocolVersion,
|
|
203
216
|
},
|
|
204
217
|
)
|
|
205
|
-
sendInitError(
|
|
218
|
+
sendInitError({
|
|
219
|
+
initializationId: message.initializationId,
|
|
220
|
+
error: initError,
|
|
221
|
+
})
|
|
206
222
|
return
|
|
207
223
|
}
|
|
208
224
|
|
|
209
225
|
// If the sandbox reported an error during `connect`, return it as an `init` error.
|
|
210
226
|
if (message.status === "error") {
|
|
211
|
-
sendInitError(
|
|
227
|
+
sendInitError({
|
|
228
|
+
initializationId: message.initializationId,
|
|
229
|
+
error: message.error,
|
|
230
|
+
})
|
|
212
231
|
return
|
|
213
232
|
}
|
|
214
233
|
|
|
@@ -217,32 +236,37 @@ export function createInitializationController(
|
|
|
217
236
|
}
|
|
218
237
|
}
|
|
219
238
|
|
|
220
|
-
function handleInvalidConnect(
|
|
239
|
+
function handleInvalidConnect(args: {
|
|
240
|
+
initializationId: string
|
|
241
|
+
error: CustomBlockInitErrorInfo
|
|
242
|
+
}): "initErrorSent" | "nack" {
|
|
243
|
+
const { initializationId, error } = args
|
|
221
244
|
if (initStatus !== "waitingForConnect") {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const error = initErrorForFailureReason("invalid_connect_payload")
|
|
225
|
-
if (initializationId === undefined) {
|
|
226
|
-
initStatus = "error"
|
|
227
|
-
clearNoConnectTimeout()
|
|
228
|
-
warn(error)
|
|
229
|
-
onInitializationFailure?.(error)
|
|
230
|
-
} else {
|
|
231
|
-
sendInitError(initializationId, error)
|
|
245
|
+
// `connect` messages received when not waiting for one are NACKed like generic invalid messages.
|
|
246
|
+
return "nack"
|
|
232
247
|
}
|
|
233
|
-
|
|
248
|
+
// The sandbox awaits `init`. Reply with `init.error` using its initialization ID.
|
|
249
|
+
sendInitError({ initializationId, error })
|
|
250
|
+
return "initErrorSent"
|
|
234
251
|
}
|
|
235
252
|
|
|
236
|
-
function handleInvalidInitResult(
|
|
237
|
-
|
|
238
|
-
|
|
253
|
+
function handleInvalidInitResult(args: {
|
|
254
|
+
initializationId: string | undefined
|
|
255
|
+
error: CustomBlockInitErrorInfo
|
|
256
|
+
}): void {
|
|
257
|
+
const { initializationId, error } = args
|
|
258
|
+
if (
|
|
259
|
+
initStatus !== "waitingForInitResult" ||
|
|
260
|
+
initializationId === undefined ||
|
|
261
|
+
initializationId !== activeInitializationId
|
|
262
|
+
) {
|
|
263
|
+
return
|
|
239
264
|
}
|
|
265
|
+
clearNoConnectTimeout()
|
|
240
266
|
clearNoInitResultTimeout()
|
|
241
267
|
initStatus = "error"
|
|
242
|
-
const error = initErrorForFailureReason("invalid_init_result_payload")
|
|
243
268
|
warn(error)
|
|
244
269
|
onInitializationFailure?.(error)
|
|
245
|
-
return true
|
|
246
270
|
}
|
|
247
271
|
|
|
248
272
|
function onIframeLoad() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readIncomingType } from "@notionhq/custom-blocks-protocol/incomingType.js"
|
|
1
|
+
import { readIncomingType } from "@notionhq/custom-blocks-protocol/messages/incomingType.js"
|
|
2
2
|
import type { InvalidSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/invalidSandboxMessage.js"
|
|
3
3
|
|
|
4
4
|
export type InvalidSandboxMessageResponse = {
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { ConnectMessage } from "@notionhq/custom-blocks-protocol/messages/connect.js"
|
|
2
|
+
import type { CreatePageMessage } from "@notionhq/custom-blocks-protocol/messages/createPage.js"
|
|
3
|
+
import type { GetPageMessage } from "@notionhq/custom-blocks-protocol/messages/getPage.js"
|
|
4
|
+
import type { GetUserMessage } from "@notionhq/custom-blocks-protocol/messages/getUser.js"
|
|
5
|
+
import type { HostToSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/hostToSandbox.js"
|
|
6
|
+
import type { InitResultMessage } from "@notionhq/custom-blocks-protocol/messages/initResult.js"
|
|
7
|
+
import { isInitHandshakeMessage } from "@notionhq/custom-blocks-protocol/messages/isInitHandshakeMessage.js"
|
|
8
|
+
import type { ListUsersMessage } from "@notionhq/custom-blocks-protocol/messages/listUsers.js"
|
|
9
|
+
import type { QueryDataSourceMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSource.js"
|
|
10
|
+
import type { ResizeMessage } from "@notionhq/custom-blocks-protocol/messages/resize.js"
|
|
11
|
+
import { sandboxToHostMessageSchema } from "@notionhq/custom-blocks-protocol/messages/sandboxToHost.js"
|
|
12
|
+
import type { UnsubscribeDataSourceQueryMessage } from "@notionhq/custom-blocks-protocol/messages/unsubscribeDataSourceQuery.js"
|
|
13
|
+
import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
|
|
14
|
+
import * as v from "valibot"
|
|
15
|
+
import { initErrorForFailureReason } from "../lifecycle/initErrors.js"
|
|
16
|
+
import type { InitializationController } from "../lifecycle/initializationController.js"
|
|
17
|
+
import type { InitStatus } from "../lifecycle/types.js"
|
|
18
|
+
import { unreachable } from "../utils.js"
|
|
19
|
+
import { getInvalidSandboxMessageResponse } from "./invalidSandboxMessage.js"
|
|
20
|
+
import type { CustomBlockHostLogDirection } from "./types.js"
|
|
21
|
+
|
|
22
|
+
const initializationIdentitySchema = v.object({
|
|
23
|
+
initializationId: v.string(),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export type SandboxMessageRouterOptions = {
|
|
27
|
+
iframe: HTMLIFrameElement
|
|
28
|
+
sandboxOrigin: string
|
|
29
|
+
getInitStatus: () => InitStatus
|
|
30
|
+
emit: (direction: CustomBlockHostLogDirection, payload: unknown) => void
|
|
31
|
+
post: (message: HostToSandboxMessage) => void
|
|
32
|
+
onInvalidConnect: InitializationController["handleInvalidConnect"]
|
|
33
|
+
onInvalidInitResult: InitializationController["handleInvalidInitResult"]
|
|
34
|
+
onConnect: (message: ConnectMessage) => void
|
|
35
|
+
onInitResult: (message: InitResultMessage) => void
|
|
36
|
+
onQueryDataSource: (message: QueryDataSourceMessage) => void | Promise<void>
|
|
37
|
+
onUnsubscribeDataSourceQuery: (
|
|
38
|
+
message: UnsubscribeDataSourceQueryMessage,
|
|
39
|
+
) => void
|
|
40
|
+
onCreatePage: (message: CreatePageMessage) => void | Promise<void>
|
|
41
|
+
onGetPage: (message: GetPageMessage) => void | Promise<void>
|
|
42
|
+
onGetUser: (message: GetUserMessage) => void | Promise<void>
|
|
43
|
+
onListUsers: (message: ListUsersMessage) => void | Promise<void>
|
|
44
|
+
onUpdatePage: (message: UpdatePageMessage) => void | Promise<void>
|
|
45
|
+
onResize: (message: ResizeMessage) => void
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createSandboxMessageRouter(
|
|
49
|
+
options: SandboxMessageRouterOptions,
|
|
50
|
+
): (event: MessageEvent) => void {
|
|
51
|
+
const {
|
|
52
|
+
iframe,
|
|
53
|
+
sandboxOrigin,
|
|
54
|
+
getInitStatus,
|
|
55
|
+
emit,
|
|
56
|
+
post,
|
|
57
|
+
onInvalidConnect,
|
|
58
|
+
onInvalidInitResult,
|
|
59
|
+
onConnect,
|
|
60
|
+
onInitResult,
|
|
61
|
+
onQueryDataSource,
|
|
62
|
+
onUnsubscribeDataSourceQuery,
|
|
63
|
+
onCreatePage,
|
|
64
|
+
onGetPage,
|
|
65
|
+
onGetUser,
|
|
66
|
+
onListUsers,
|
|
67
|
+
onUpdatePage,
|
|
68
|
+
onResize,
|
|
69
|
+
} = options
|
|
70
|
+
|
|
71
|
+
function onInvalidSandboxMessage(
|
|
72
|
+
data: unknown,
|
|
73
|
+
issues: readonly v.BaseIssue<unknown>[],
|
|
74
|
+
) {
|
|
75
|
+
emit("warn", {
|
|
76
|
+
message: "Ignored unsupported sandbox message",
|
|
77
|
+
payload: data,
|
|
78
|
+
issues,
|
|
79
|
+
})
|
|
80
|
+
const response = getInvalidSandboxMessageResponse(data)
|
|
81
|
+
|
|
82
|
+
if (response.incomingType === "connect") {
|
|
83
|
+
const parsedIdentity = v.safeParse(initializationIdentitySchema, data)
|
|
84
|
+
if (parsedIdentity.success) {
|
|
85
|
+
const responseType = onInvalidConnect({
|
|
86
|
+
initializationId: parsedIdentity.output.initializationId,
|
|
87
|
+
error: initErrorForFailureReason("invalid_connect_payload"),
|
|
88
|
+
})
|
|
89
|
+
if (responseType === "initErrorSent") {
|
|
90
|
+
// The controller already sent `init.error`, so no need to also send a NACK.
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (response.incomingType === "initResult") {
|
|
97
|
+
const parsedIdentity = v.safeParse(initializationIdentitySchema, data)
|
|
98
|
+
onInvalidInitResult({
|
|
99
|
+
initializationId: parsedIdentity.success
|
|
100
|
+
? parsedIdentity.output.initializationId
|
|
101
|
+
: undefined,
|
|
102
|
+
error: initErrorForFailureReason("invalid_init_result_payload"),
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Other messages get NACKed indicating they were invalid and skipped
|
|
107
|
+
if (response.nack !== undefined) {
|
|
108
|
+
post(response.nack)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return function onMessage(event: MessageEvent) {
|
|
113
|
+
// Verify the sender is this host's iframe, not another window with the same origin.
|
|
114
|
+
const isExpectedSource = event.source === iframe.contentWindow
|
|
115
|
+
// Verify the sender's origin, since the iframe can navigate to another origin.
|
|
116
|
+
const isExpectedOrigin = event.origin === sandboxOrigin
|
|
117
|
+
if (!isExpectedSource || !isExpectedOrigin) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Parse and validate the message from the sandbox.
|
|
122
|
+
const parsed = v.safeParse(sandboxToHostMessageSchema, event.data)
|
|
123
|
+
if (!parsed.success) {
|
|
124
|
+
onInvalidSandboxMessage(event.data, parsed.issues)
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const message = parsed.output
|
|
129
|
+
if (!isInitHandshakeMessage(message) && getInitStatus() !== "success") {
|
|
130
|
+
emit("warn", {
|
|
131
|
+
message: `Ignored ${message.type} before initialization completed`,
|
|
132
|
+
payload: message,
|
|
133
|
+
})
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
emit("in", message)
|
|
138
|
+
switch (message.type) {
|
|
139
|
+
case "connect":
|
|
140
|
+
onConnect(message)
|
|
141
|
+
return
|
|
142
|
+
case "initResult":
|
|
143
|
+
onInitResult(message)
|
|
144
|
+
return
|
|
145
|
+
case "queryDataSource":
|
|
146
|
+
void onQueryDataSource(message)
|
|
147
|
+
return
|
|
148
|
+
case "unsubscribeDataSourceQuery":
|
|
149
|
+
onUnsubscribeDataSourceQuery(message)
|
|
150
|
+
return
|
|
151
|
+
case "createPage":
|
|
152
|
+
void onCreatePage(message)
|
|
153
|
+
return
|
|
154
|
+
case "getPage":
|
|
155
|
+
void onGetPage(message)
|
|
156
|
+
return
|
|
157
|
+
case "getUser":
|
|
158
|
+
void onGetUser(message)
|
|
159
|
+
return
|
|
160
|
+
case "listUsers":
|
|
161
|
+
void onListUsers(message)
|
|
162
|
+
return
|
|
163
|
+
case "updatePage":
|
|
164
|
+
void onUpdatePage(message)
|
|
165
|
+
return
|
|
166
|
+
case "resize":
|
|
167
|
+
onResize(message)
|
|
168
|
+
return
|
|
169
|
+
case "invalidHostMessage":
|
|
170
|
+
// The inbound log records this rejection. Do not reply, to avoid an error-response loop.
|
|
171
|
+
return
|
|
172
|
+
default:
|
|
173
|
+
unreachable(message)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
package/src/messages/types.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messagePayload.js"
|
|
2
1
|
import type { CreatePageMessage } from "@notionhq/custom-blocks-protocol/messages/createPage.js"
|
|
3
2
|
import type {
|
|
4
3
|
CreatePageResultMessage,
|
|
@@ -21,6 +20,7 @@ import type {
|
|
|
21
20
|
ListUsersMessage,
|
|
22
21
|
ListUsersResultMessage,
|
|
23
22
|
} from "@notionhq/custom-blocks-protocol/messages/listUsers.js"
|
|
23
|
+
import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
|
|
24
24
|
import type { QueryDataSourceMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSource.js"
|
|
25
25
|
import type { ResizeMessage } from "@notionhq/custom-blocks-protocol/messages/resize.js"
|
|
26
26
|
import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
|
package/src/queries/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messagePayload.js"
|
|
1
|
+
import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
|
|
2
2
|
import type {
|
|
3
3
|
CustomBlockQueryDataSourceErrorInfo,
|
|
4
4
|
QueryDataSourceResultMessage,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|