@notionhq/custom-blocks-host 0.1.29 → 0.1.31
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 +0 -1
- package/dist/createCustomBlockHost.d.ts +0 -2
- package/dist/createCustomBlockHost.d.ts.map +1 -1
- package/dist/createCustomBlockHost.js +83 -107
- package/dist/lifecycle/initializationController.d.ts +2 -3
- package/dist/lifecycle/initializationController.d.ts.map +1 -1
- package/dist/lifecycle/initializationController.js +11 -6
- package/dist/lifecycle/types.d.ts +1 -1
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/messages/sandboxMessageRouter.d.ts +2 -2
- package/dist/messages/sandboxMessageRouter.d.ts.map +1 -1
- package/dist/messages/sandboxMessageRouter.js +5 -5
- package/package.json +1 -1
- package/src/createCustomBlockHost.ts +124 -134
- package/src/lifecycle/initializationController.ts +12 -8
- package/src/lifecycle/types.ts +1 -1
- package/src/messages/sandboxMessageRouter.ts +7 -7
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type NotionContrastMode } from "./protocol/contrast.js";
|
|
2
2
|
import type { NotionDataSourceId } from "./protocol/ids.js";
|
|
3
3
|
import type { CustomBlockManifest } from "./protocol/manifest.js";
|
|
4
|
-
import type { HostToSandboxMessage } from "./protocol/messages/hostToSandbox.js";
|
|
5
4
|
import type { CustomBlockPage } from "./protocol/pages/page.js";
|
|
6
5
|
import type { NotionParent } from "./protocol/parent.js";
|
|
7
6
|
import type { NotionTheme } from "./protocol/theme.js";
|
|
@@ -42,7 +41,6 @@ export type CustomBlockHostOptions = {
|
|
|
42
41
|
};
|
|
43
42
|
export type CustomBlockHostHandle = {
|
|
44
43
|
stop: () => void;
|
|
45
|
-
post: (message: HostToSandboxMessage) => void;
|
|
46
44
|
setTheme: (theme: NotionTheme) => void;
|
|
47
45
|
setContrastMode: (contrastMode: NotionContrastMode) => void;
|
|
48
46
|
setParent: (parent: NotionParent) => void;
|
|
@@ -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;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;
|
|
1
|
+
{"version":3,"file":"createCustomBlockHost.d.ts","sourceRoot":"","sources":["../src/createCustomBlockHost.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,8CAA8C,CAAA;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AAmBvF,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;AAIhF,OAAO,KAAK,EACX,iCAAiC,EACjC,2BAA2B,EAC3B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EACX,sBAAsB,EACtB,uBAAuB,EACvB,2BAA2B,EAC3B,MAAM,qBAAqB,CAAA;AAe5B,MAAM,MAAM,sBAAsB,GAAG;IACpC,MAAM,EAAE,iBAAiB,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE,2BAA2B,CAAA;IACzC,QAAQ,EAAE,uBAAuB,CAAA;IACjC;;;OAGG;IACH,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;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAA;IACnD,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,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;AAyBD,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,sBAAsB,GAC7B,qBAAqB,CA4ZvB"}
|
|
@@ -8,6 +8,7 @@ import { MIN_HOST_SUPPORTED_BRIDGE_PROTOCOL_VERSION } from "./protocolVersion.js
|
|
|
8
8
|
import { QuerySubscriptions, } from "./queries/querySubscriptions.js";
|
|
9
9
|
import { validateQueryDataSourceFilter } from "./queries/validateQueryDataSourceFilter.js";
|
|
10
10
|
import { validateQueryDataSourceSorts } from "./queries/validateQueryDataSourceSorts.js";
|
|
11
|
+
import { unreachable } from "./utils.js";
|
|
11
12
|
// Bridge protocol version that introduced page: { type: "unavailable" }.
|
|
12
13
|
// Earlier SDKs cannot represent this context, so the host reports context_unavailable.
|
|
13
14
|
const BRIDGE_PROTOCOL_VERSION_INTRODUCING_UNAVAILABLE_PAGE = 5;
|
|
@@ -36,15 +37,63 @@ export function createCustomBlockHost(options) {
|
|
|
36
37
|
function emit(direction, payload) {
|
|
37
38
|
onLog?.(direction, payload);
|
|
38
39
|
}
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
function postToSandbox(message) {
|
|
41
|
+
const status = initializationController.status;
|
|
42
|
+
switch (status) {
|
|
43
|
+
case "waitingForConnect":
|
|
44
|
+
case "waitingForInitResult":
|
|
45
|
+
case "initialized":
|
|
46
|
+
case "error":
|
|
47
|
+
break;
|
|
48
|
+
// A stopped host must not send messages, including pending responses.
|
|
49
|
+
// Return from the function to skip delivery below.
|
|
50
|
+
case "stopped":
|
|
51
|
+
return;
|
|
52
|
+
default:
|
|
53
|
+
return unreachable(status);
|
|
43
54
|
}
|
|
44
55
|
const sandboxMessage = normalizeHostToSandboxMessage(message, sandboxBridgeProtocolVersion);
|
|
45
56
|
emit("out", sandboxMessage);
|
|
46
57
|
iframe.contentWindow?.postMessage(sandboxMessage, sandboxOrigin);
|
|
47
58
|
}
|
|
59
|
+
function sendInitMessage(message) {
|
|
60
|
+
postToSandbox(message);
|
|
61
|
+
}
|
|
62
|
+
function sendNack(message) {
|
|
63
|
+
postToSandbox(message);
|
|
64
|
+
}
|
|
65
|
+
function sendInitializedMessage(message) {
|
|
66
|
+
const status = initializationController.status;
|
|
67
|
+
switch (status) {
|
|
68
|
+
case "initialized":
|
|
69
|
+
postToSandbox(message);
|
|
70
|
+
return;
|
|
71
|
+
// Send state updates and handler results only after initialization succeeds.
|
|
72
|
+
case "waitingForConnect":
|
|
73
|
+
case "waitingForInitResult":
|
|
74
|
+
case "error":
|
|
75
|
+
case "stopped":
|
|
76
|
+
return;
|
|
77
|
+
default:
|
|
78
|
+
unreachable(status);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Invokes a one-shot handler and posts its result with the request's ID.
|
|
83
|
+
* Each result type is named `<request type>Result` by the bridge protocol.
|
|
84
|
+
*/
|
|
85
|
+
async function respondToRequest(message, handler) {
|
|
86
|
+
if (handler === undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const response = await handler(message);
|
|
90
|
+
const result = {
|
|
91
|
+
type: `${message.type}Result`,
|
|
92
|
+
requestId: message.requestId,
|
|
93
|
+
...response,
|
|
94
|
+
};
|
|
95
|
+
sendInitializedMessage(result);
|
|
96
|
+
}
|
|
48
97
|
function postQueryDataSourceResult(args) {
|
|
49
98
|
const message = args.response.status === "error"
|
|
50
99
|
? {
|
|
@@ -60,7 +109,7 @@ export function createCustomBlockHost(options) {
|
|
|
60
109
|
items: args.response.items,
|
|
61
110
|
hasMore: args.response.hasMore,
|
|
62
111
|
};
|
|
63
|
-
|
|
112
|
+
sendInitializedMessage(message);
|
|
64
113
|
}
|
|
65
114
|
async function handleQuery(message, token = querySubscriptions.subscribe(message)) {
|
|
66
115
|
const collectionSchema = getCollectionSchema(activeDataSources, message.dataSourceId);
|
|
@@ -83,111 +132,39 @@ export function createCustomBlockHost(options) {
|
|
|
83
132
|
response,
|
|
84
133
|
});
|
|
85
134
|
}
|
|
86
|
-
async function handleCreatePage(message) {
|
|
87
|
-
if (handlers.createPage === undefined) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const response = await handlers.createPage(message);
|
|
91
|
-
const result = {
|
|
92
|
-
type: "createPageResult",
|
|
93
|
-
requestId: message.requestId,
|
|
94
|
-
...response,
|
|
95
|
-
};
|
|
96
|
-
post(result);
|
|
97
|
-
}
|
|
98
|
-
async function handleGetPage(message) {
|
|
99
|
-
if (handlers.getPage === undefined) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const response = await handlers.getPage(message);
|
|
103
|
-
const result = {
|
|
104
|
-
type: "getPageResult",
|
|
105
|
-
requestId: message.requestId,
|
|
106
|
-
...response,
|
|
107
|
-
};
|
|
108
|
-
post(result);
|
|
109
|
-
}
|
|
110
|
-
async function handleGetUser(message) {
|
|
111
|
-
if (handlers.getUser === undefined) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const response = await handlers.getUser(message);
|
|
115
|
-
const result = {
|
|
116
|
-
type: "getUserResult",
|
|
117
|
-
requestId: message.requestId,
|
|
118
|
-
...response,
|
|
119
|
-
};
|
|
120
|
-
post(result);
|
|
121
|
-
}
|
|
122
|
-
async function handleListUsers(message) {
|
|
123
|
-
if (handlers.listUsers === undefined) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const response = await handlers.listUsers(message);
|
|
127
|
-
const result = {
|
|
128
|
-
type: "listUsersResult",
|
|
129
|
-
requestId: message.requestId,
|
|
130
|
-
...response,
|
|
131
|
-
};
|
|
132
|
-
post(result);
|
|
133
|
-
}
|
|
134
|
-
async function handleOpenPage(message) {
|
|
135
|
-
if (handlers.openPage === undefined) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const response = await handlers.openPage(message);
|
|
139
|
-
const result = {
|
|
140
|
-
type: "openPageResult",
|
|
141
|
-
requestId: message.requestId,
|
|
142
|
-
...response,
|
|
143
|
-
};
|
|
144
|
-
post(result);
|
|
145
|
-
}
|
|
146
|
-
async function handleUpdatePage(message) {
|
|
147
|
-
if (handlers.updatePage === undefined) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const response = await handlers.updatePage(message);
|
|
151
|
-
const result = {
|
|
152
|
-
type: "updatePageResult",
|
|
153
|
-
requestId: message.requestId,
|
|
154
|
-
...response,
|
|
155
|
-
};
|
|
156
|
-
post(result);
|
|
157
|
-
}
|
|
158
135
|
/**
|
|
159
136
|
* Sends any pending host state changes to the sandbox. It is possible for these to change
|
|
160
137
|
* between when the host sends `init` and when the sandbox responds with `initResult`. The host
|
|
161
|
-
* does send
|
|
138
|
+
* does not send pending state changes until the sandbox responds.
|
|
162
139
|
*/
|
|
163
140
|
function flushPendingHostStateChanges() {
|
|
164
141
|
if (pendingThemeChange) {
|
|
165
142
|
pendingThemeChange = false;
|
|
166
|
-
|
|
143
|
+
sendInitializedMessage({ type: "themeChanged", theme });
|
|
167
144
|
}
|
|
168
145
|
if (pendingContrastModeChange) {
|
|
169
146
|
pendingContrastModeChange = false;
|
|
170
|
-
|
|
147
|
+
sendInitializedMessage({ type: "contrastModeChanged", contrastMode });
|
|
171
148
|
}
|
|
172
149
|
if (pendingParentChange) {
|
|
173
150
|
pendingParentChange = false;
|
|
174
|
-
|
|
151
|
+
sendInitializedMessage({ type: "parentChanged", parent });
|
|
175
152
|
}
|
|
176
153
|
if (pendingPageChange) {
|
|
177
154
|
pendingPageChange = false;
|
|
178
|
-
|
|
155
|
+
sendInitializedMessage({ type: "pageChanged", page });
|
|
179
156
|
}
|
|
180
157
|
if (pendingDataSourcesChange !== undefined) {
|
|
181
158
|
const nextDataSources = pendingDataSourcesChange;
|
|
182
159
|
pendingDataSourcesChange = undefined;
|
|
183
|
-
|
|
160
|
+
sendInitializedMessage({
|
|
184
161
|
type: "dataSourcesChanged",
|
|
185
162
|
dataSources: nextDataSources,
|
|
186
163
|
});
|
|
187
164
|
}
|
|
188
165
|
if (pendingCurrentUserChange) {
|
|
189
166
|
pendingCurrentUserChange = false;
|
|
190
|
-
|
|
167
|
+
sendInitializedMessage({ type: "currentUserChanged", currentUser });
|
|
191
168
|
}
|
|
192
169
|
}
|
|
193
170
|
const initializationController = createInitializationController({
|
|
@@ -232,7 +209,7 @@ export function createCustomBlockHost(options) {
|
|
|
232
209
|
dataSources: resolvedDataSources,
|
|
233
210
|
};
|
|
234
211
|
},
|
|
235
|
-
|
|
212
|
+
sendInitMessage,
|
|
236
213
|
warn: payload => emit("warn", payload),
|
|
237
214
|
flushPendingHostStateChanges,
|
|
238
215
|
minBridgeProtocolVersion,
|
|
@@ -251,19 +228,19 @@ export function createCustomBlockHost(options) {
|
|
|
251
228
|
sandboxOrigin,
|
|
252
229
|
getInitStatus: () => initializationController.status,
|
|
253
230
|
emit,
|
|
254
|
-
|
|
231
|
+
sendNack,
|
|
255
232
|
onInvalidConnect: initializationController.handleInvalidConnect,
|
|
256
233
|
onInvalidInitResult: initializationController.handleInvalidInitResult,
|
|
257
234
|
onConnect: initializationController.handleConnect,
|
|
258
235
|
onInitResult: initializationController.handleInitResult,
|
|
259
236
|
onQueryDataSource: handleQuery,
|
|
260
237
|
onUnsubscribeDataSourceQuery: message => querySubscriptions.unsubscribe(message.subscriptionId),
|
|
261
|
-
onCreatePage:
|
|
262
|
-
onGetPage:
|
|
263
|
-
onOpenPage:
|
|
264
|
-
onGetUser:
|
|
265
|
-
onListUsers:
|
|
266
|
-
onUpdatePage:
|
|
238
|
+
onCreatePage: message => respondToRequest(message, handlers.createPage),
|
|
239
|
+
onGetPage: message => respondToRequest(message, handlers.getPage),
|
|
240
|
+
onOpenPage: message => respondToRequest(message, handlers.openPage),
|
|
241
|
+
onGetUser: message => respondToRequest(message, handlers.getUser),
|
|
242
|
+
onListUsers: message => respondToRequest(message, handlers.listUsers),
|
|
243
|
+
onUpdatePage: message => respondToRequest(message, handlers.updatePage),
|
|
267
244
|
onResize: message => handlers.resize?.(message),
|
|
268
245
|
});
|
|
269
246
|
window.addEventListener("message", onMessage);
|
|
@@ -281,21 +258,20 @@ export function createCustomBlockHost(options) {
|
|
|
281
258
|
}
|
|
282
259
|
return {
|
|
283
260
|
stop,
|
|
284
|
-
post,
|
|
285
261
|
setTheme(nextTheme) {
|
|
286
262
|
theme = nextTheme;
|
|
287
|
-
if (initializationController.status !== "
|
|
263
|
+
if (initializationController.status !== "initialized") {
|
|
288
264
|
if (initializationController.status === "waitingForInitResult") {
|
|
289
265
|
pendingThemeChange = true;
|
|
290
266
|
}
|
|
291
267
|
return;
|
|
292
268
|
}
|
|
293
269
|
const message = { type: "themeChanged", theme };
|
|
294
|
-
|
|
270
|
+
sendInitializedMessage(message);
|
|
295
271
|
},
|
|
296
272
|
setContrastMode(nextContrastMode) {
|
|
297
273
|
contrastMode = nextContrastMode;
|
|
298
|
-
if (initializationController.status !== "
|
|
274
|
+
if (initializationController.status !== "initialized") {
|
|
299
275
|
if (initializationController.status === "waitingForInitResult") {
|
|
300
276
|
pendingContrastModeChange = true;
|
|
301
277
|
}
|
|
@@ -305,18 +281,18 @@ export function createCustomBlockHost(options) {
|
|
|
305
281
|
type: "contrastModeChanged",
|
|
306
282
|
contrastMode,
|
|
307
283
|
};
|
|
308
|
-
|
|
284
|
+
sendInitializedMessage(message);
|
|
309
285
|
},
|
|
310
286
|
setParent(nextParent) {
|
|
311
287
|
parent = nextParent;
|
|
312
|
-
if (initializationController.status !== "
|
|
288
|
+
if (initializationController.status !== "initialized") {
|
|
313
289
|
if (initializationController.status === "waitingForInitResult") {
|
|
314
290
|
pendingParentChange = true;
|
|
315
291
|
}
|
|
316
292
|
return;
|
|
317
293
|
}
|
|
318
294
|
const message = { type: "parentChanged", parent };
|
|
319
|
-
|
|
295
|
+
sendInitializedMessage(message);
|
|
320
296
|
},
|
|
321
297
|
setPage(nextPage) {
|
|
322
298
|
page = nextPage;
|
|
@@ -324,18 +300,18 @@ export function createCustomBlockHost(options) {
|
|
|
324
300
|
sandboxBridgeProtocolVersion <
|
|
325
301
|
BRIDGE_PROTOCOL_VERSION_INTRODUCING_UNAVAILABLE_PAGE &&
|
|
326
302
|
(initializationController.status === "waitingForInitResult" ||
|
|
327
|
-
initializationController.status === "
|
|
303
|
+
initializationController.status === "initialized")) {
|
|
328
304
|
stopWithFailure(initErrorForFailureReason("context_unavailable"));
|
|
329
305
|
return;
|
|
330
306
|
}
|
|
331
|
-
if (initializationController.status !== "
|
|
307
|
+
if (initializationController.status !== "initialized") {
|
|
332
308
|
if (initializationController.status === "waitingForInitResult") {
|
|
333
309
|
pendingPageChange = true;
|
|
334
310
|
}
|
|
335
311
|
return;
|
|
336
312
|
}
|
|
337
313
|
const message = { type: "pageChanged", page };
|
|
338
|
-
|
|
314
|
+
sendInitializedMessage(message);
|
|
339
315
|
},
|
|
340
316
|
setDataSources(nextDataSources) {
|
|
341
317
|
if (initializationController.hasConnectedSandbox &&
|
|
@@ -349,7 +325,7 @@ export function createCustomBlockHost(options) {
|
|
|
349
325
|
}
|
|
350
326
|
dataSources = nextDataSources;
|
|
351
327
|
activeDataSources = nextDataSources;
|
|
352
|
-
if (initializationController.status !== "
|
|
328
|
+
if (initializationController.status !== "initialized") {
|
|
353
329
|
if (initializationController.status === "waitingForInitResult") {
|
|
354
330
|
pendingDataSourcesChange = nextDataSources;
|
|
355
331
|
}
|
|
@@ -359,20 +335,20 @@ export function createCustomBlockHost(options) {
|
|
|
359
335
|
type: "dataSourcesChanged",
|
|
360
336
|
dataSources: nextDataSources,
|
|
361
337
|
};
|
|
362
|
-
|
|
338
|
+
sendInitializedMessage(message);
|
|
363
339
|
},
|
|
364
340
|
setCurrentUser(nextCurrentUser) {
|
|
365
341
|
currentUser = nextCurrentUser;
|
|
366
|
-
if (initializationController.status !== "
|
|
342
|
+
if (initializationController.status !== "initialized") {
|
|
367
343
|
if (initializationController.status === "waitingForInitResult") {
|
|
368
344
|
pendingCurrentUserChange = true;
|
|
369
345
|
}
|
|
370
346
|
return;
|
|
371
347
|
}
|
|
372
|
-
|
|
348
|
+
sendInitializedMessage({ type: "currentUserChanged", currentUser });
|
|
373
349
|
},
|
|
374
350
|
refreshQuery({ dataSourceId }) {
|
|
375
|
-
if (initializationController.status !== "
|
|
351
|
+
if (initializationController.status !== "initialized") {
|
|
376
352
|
return;
|
|
377
353
|
}
|
|
378
354
|
const refreshes = querySubscriptions.refresh(dataSourceId);
|
|
@@ -2,8 +2,7 @@ import type { NotionContrastMode } from "../protocol/contrast.js";
|
|
|
2
2
|
import type { NotionBlockId } from "../protocol/ids.js";
|
|
3
3
|
import type { CustomBlockManifest } from "../protocol/manifest.js";
|
|
4
4
|
import type { ConnectMessage } from "../protocol/messages/connect.js";
|
|
5
|
-
import type {
|
|
6
|
-
import type { CustomBlockInitErrorInfo } from "../protocol/messages/init.js";
|
|
5
|
+
import type { CustomBlockInitErrorInfo, InitMessage } from "../protocol/messages/init.js";
|
|
7
6
|
import type { InitResultMessage } from "../protocol/messages/initResult.js";
|
|
8
7
|
import type { CustomBlockPage } from "../protocol/pages/page.js";
|
|
9
8
|
import type { NotionParent } from "../protocol/parent.js";
|
|
@@ -30,7 +29,7 @@ export type InitializationControllerOptions = {
|
|
|
30
29
|
blockId: NotionBlockId;
|
|
31
30
|
getState: () => InitializationState;
|
|
32
31
|
prepareInit: (connect: ConnectSuccessMessage) => InitializationPreparation;
|
|
33
|
-
|
|
32
|
+
sendInitMessage: (message: InitMessage) => void;
|
|
34
33
|
warn: (payload: unknown) => void;
|
|
35
34
|
flushPendingHostStateChanges: () => void;
|
|
36
35
|
minBridgeProtocolVersion: number;
|
|
@@ -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,
|
|
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,EACX,wBAAwB,EACxB,WAAW,EACX,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,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAGlE,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,eAAe,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAC/C,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,mBAAmB,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAA;IAC5D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACnD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAA;CACnD,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,GAAG,SAAS,CAAA;QACpC,KAAK,EAAE,wBAAwB,CAAA;QAC/B,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAA;KACzC,KAAK,SAAS,GAAG,MAAM,CAAA;IACxB,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,CAwR1B"}
|
|
@@ -3,7 +3,7 @@ import { isValidBridgeProtocolVersion } from "./protocolVersion.js";
|
|
|
3
3
|
const DEFAULT_NO_CONNECT_TIMEOUT_MS = 5_000;
|
|
4
4
|
const DEFAULT_NO_INIT_RESULT_TIMEOUT_MS = 5_000;
|
|
5
5
|
export function createInitializationController(options) {
|
|
6
|
-
const { blockId, getState, prepareInit,
|
|
6
|
+
const { blockId, getState, prepareInit, sendInitMessage, warn, flushPendingHostStateChanges, minBridgeProtocolVersion, noConnectTimeoutMs = DEFAULT_NO_CONNECT_TIMEOUT_MS, noInitResultTimeoutMs = DEFAULT_NO_INIT_RESULT_TIMEOUT_MS, stopHostWithFailure, onInitResult, onFailure, } = options;
|
|
7
7
|
let initStatus = "waitingForConnect";
|
|
8
8
|
let noConnectTimeoutId;
|
|
9
9
|
let noInitResultTimeoutId;
|
|
@@ -30,7 +30,7 @@ export function createInitializationController(options) {
|
|
|
30
30
|
initStatus = "error";
|
|
31
31
|
activeInitializationId = initializationId;
|
|
32
32
|
clearNoConnectTimeout();
|
|
33
|
-
|
|
33
|
+
sendInitMessage({
|
|
34
34
|
type: "init",
|
|
35
35
|
initializationId,
|
|
36
36
|
status: "error",
|
|
@@ -38,11 +38,16 @@ export function createInitializationController(options) {
|
|
|
38
38
|
});
|
|
39
39
|
onFailure?.(error);
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function prepareAndSendInit(connect) {
|
|
42
42
|
if (initStatus !== "waitingForConnect") {
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
45
|
const preparation = prepareInit(connect);
|
|
46
|
+
// The embedder can stop the host when it receives the manifest.
|
|
47
|
+
// If that happens, do not continue initialization or start its timer.
|
|
48
|
+
if (initStatus !== "waitingForConnect") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
46
51
|
if (preparation.status === "error") {
|
|
47
52
|
sendInitError({
|
|
48
53
|
initializationId: connect.initializationId,
|
|
@@ -67,7 +72,7 @@ export function createInitializationController(options) {
|
|
|
67
72
|
dataSources: preparation.dataSources,
|
|
68
73
|
currentUser: state.currentUser,
|
|
69
74
|
};
|
|
70
|
-
|
|
75
|
+
sendInitMessage(message);
|
|
71
76
|
noInitResultTimeoutId = window.setTimeout(() => {
|
|
72
77
|
if (initStatus !== "waitingForInitResult") {
|
|
73
78
|
return;
|
|
@@ -119,7 +124,7 @@ export function createInitializationController(options) {
|
|
|
119
124
|
});
|
|
120
125
|
return;
|
|
121
126
|
}
|
|
122
|
-
if (
|
|
127
|
+
if (prepareAndSendInit(message)) {
|
|
123
128
|
hasConnectedSandbox = true;
|
|
124
129
|
}
|
|
125
130
|
}
|
|
@@ -204,7 +209,7 @@ export function createInitializationController(options) {
|
|
|
204
209
|
}
|
|
205
210
|
clearNoInitResultTimeout();
|
|
206
211
|
if (message.status === "success") {
|
|
207
|
-
initStatus = "
|
|
212
|
+
initStatus = "initialized";
|
|
208
213
|
flushPendingHostStateChanges();
|
|
209
214
|
}
|
|
210
215
|
else {
|
|
@@ -17,7 +17,7 @@ export type InitStatus =
|
|
|
17
17
|
/** The host is waiting for a matching `initResult` after it sends `init`. */
|
|
18
18
|
| "waitingForInitResult"
|
|
19
19
|
/** The host is initialized and can send live updates. */
|
|
20
|
-
| "
|
|
20
|
+
| "initialized"
|
|
21
21
|
/** The host is in an error state after an initialization failure or timeout. */
|
|
22
22
|
| "error"
|
|
23
23
|
/** The host is stopped and no longer sends or accepts sandbox messages. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lifecycle/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4DAA4D,CAAA;AAC1G,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,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;AAEhF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAC1C,cAAc,EACd;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,UAAU;AACrB,qEAAqE;AACnE,mBAAmB;AACrB,6EAA6E;GAC3E,sBAAsB;AACxB,yDAAyD;GACvD,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lifecycle/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4DAA4D,CAAA;AAC1G,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,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;AAEhF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAC1C,cAAc,EACd;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,UAAU;AACrB,qEAAqE;AACnE,mBAAmB;AACrB,6EAA6E;GAC3E,sBAAsB;AACxB,yDAAyD;GACvD,aAAa;AACf,gFAAgF;GAC9E,OAAO;AACT,2EAA2E;GACzE,SAAS,CAAA;AAEZ,MAAM,MAAM,iCAAiC,GAAG;IAC/C,QAAQ,EAAE,wBAAwB,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,iCAAiC,GAC1C,iCAAiC,GACjC,CAAC,CAAC,OAAO,EAAE,qBAAqB,KAAK,iCAAiC,CAAC,CAAA;AAE1E,MAAM,MAAM,2BAA2B,GAAG;IACzC,KAAK,EAAE,WAAW,CAAA;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,WAAW,EAAE,iCAAiC,CAAA;IAC9C,WAAW,EAAE,UAAU,CAAA;CACvB,CAAA"}
|
|
@@ -2,8 +2,8 @@ import type { ConnectMessage } from "../protocol/messages/connect.js";
|
|
|
2
2
|
import type { CreatePageMessage } from "../protocol/messages/createPage.js";
|
|
3
3
|
import type { GetPageMessage } from "../protocol/messages/getPage.js";
|
|
4
4
|
import type { GetUserMessage } from "../protocol/messages/getUser.js";
|
|
5
|
-
import type { HostToSandboxMessage } from "../protocol/messages/hostToSandbox.js";
|
|
6
5
|
import type { InitResultMessage } from "../protocol/messages/initResult.js";
|
|
6
|
+
import type { InvalidSandboxMessage } from "../protocol/messages/invalidSandboxMessage.js";
|
|
7
7
|
import type { ListUsersMessage } from "../protocol/messages/listUsers.js";
|
|
8
8
|
import type { OpenPageMessage } from "../protocol/messages/openPage.js";
|
|
9
9
|
import type { QueryDataSourceMessage } from "../protocol/messages/queryDataSource.js";
|
|
@@ -18,7 +18,7 @@ export type SandboxMessageRouterOptions = {
|
|
|
18
18
|
sandboxOrigin: string;
|
|
19
19
|
getInitStatus: () => InitStatus;
|
|
20
20
|
emit: (direction: CustomBlockHostLogDirection, payload: unknown) => void;
|
|
21
|
-
|
|
21
|
+
sendNack: (message: InvalidSandboxMessage) => void;
|
|
22
22
|
onInvalidConnect: InitializationController["handleInvalidConnect"];
|
|
23
23
|
onInvalidInitResult: InitializationController["handleInvalidInitResult"];
|
|
24
24
|
onConnect: (message: ConnectMessage) => void;
|
|
@@ -1 +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,
|
|
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,iBAAiB,EAAE,MAAM,yDAAyD,CAAA;AAChG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oEAAoE,CAAA;AAE/G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wDAAwD,CAAA;AAC9F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AAC5F,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;AAY7D,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,QAAQ,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAA;IAClD,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,UAAU,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,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,CAsI/B"}
|
|
@@ -13,7 +13,7 @@ const bridgeProtocolVersionSchema = v.object({
|
|
|
13
13
|
bridgeProtocolVersion: v.union([v.number(), v.nan()]),
|
|
14
14
|
});
|
|
15
15
|
export function createSandboxMessageRouter(options) {
|
|
16
|
-
const { iframe, sandboxOrigin, getInitStatus, emit,
|
|
16
|
+
const { iframe, sandboxOrigin, getInitStatus, emit, sendNack, onInvalidConnect, onInvalidInitResult, onConnect, onInitResult, onQueryDataSource, onUnsubscribeDataSourceQuery, onCreatePage, onGetPage, onOpenPage, onGetUser, onListUsers, onUpdatePage, onResize, } = options;
|
|
17
17
|
function onInvalidSandboxMessage(data, issues) {
|
|
18
18
|
emit("warn", {
|
|
19
19
|
message: "Ignored unsupported sandbox message",
|
|
@@ -47,9 +47,9 @@ export function createSandboxMessageRouter(options) {
|
|
|
47
47
|
error: initErrorForFailureReason("invalid_init_result_payload"),
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
// Other messages get NACKed indicating they were invalid and skipped
|
|
51
|
-
if (response.nack !== undefined) {
|
|
52
|
-
|
|
50
|
+
// Other messages get NACKed indicating they were invalid and skipped.
|
|
51
|
+
if (response.nack !== undefined && getInitStatus() !== "stopped") {
|
|
52
|
+
sendNack(response.nack);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
return function onMessage(event) {
|
|
@@ -67,7 +67,7 @@ export function createSandboxMessageRouter(options) {
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
const message = parsed.output;
|
|
70
|
-
if (!isInitHandshakeMessage(message) && getInitStatus() !== "
|
|
70
|
+
if (!isInitHandshakeMessage(message) && getInitStatus() !== "initialized") {
|
|
71
71
|
emit("warn", {
|
|
72
72
|
message: `Ignored ${message.type} before initialization completed`,
|
|
73
73
|
payload: message,
|
package/package.json
CHANGED
|
@@ -6,27 +6,14 @@ import type { NotionCollectionSchema } from "@notionhq/custom-blocks-protocol/da
|
|
|
6
6
|
import type { NotionDataSourceId } from "@notionhq/custom-blocks-protocol/ids.js"
|
|
7
7
|
import type { CustomBlockManifest } from "@notionhq/custom-blocks-protocol/manifest.js"
|
|
8
8
|
import type { ContrastModeChangedMessage } from "@notionhq/custom-blocks-protocol/messages/contrastModeChanged.js"
|
|
9
|
-
import type { CreatePageMessage } from "@notionhq/custom-blocks-protocol/messages/createPage.js"
|
|
10
|
-
import type { CreatePageResultMessage } from "@notionhq/custom-blocks-protocol/messages/createPageResult.js"
|
|
11
9
|
import type { DataSourcesChangedMessage } from "@notionhq/custom-blocks-protocol/messages/dataSourcesChanged.js"
|
|
12
|
-
import type {
|
|
13
|
-
GetPageMessage,
|
|
14
|
-
GetPageResultMessage,
|
|
15
|
-
} from "@notionhq/custom-blocks-protocol/messages/getPage.js"
|
|
16
|
-
import type {
|
|
17
|
-
GetUserMessage,
|
|
18
|
-
GetUserResultMessage,
|
|
19
|
-
} from "@notionhq/custom-blocks-protocol/messages/getUser.js"
|
|
20
10
|
import type { HostToSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/hostToSandbox.js"
|
|
21
|
-
import type { CustomBlockInitErrorCode } from "@notionhq/custom-blocks-protocol/messages/init.js"
|
|
22
|
-
import type {
|
|
23
|
-
ListUsersMessage,
|
|
24
|
-
ListUsersResultMessage,
|
|
25
|
-
} from "@notionhq/custom-blocks-protocol/messages/listUsers.js"
|
|
26
11
|
import type {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from "@notionhq/custom-blocks-protocol/messages/
|
|
12
|
+
CustomBlockInitErrorCode,
|
|
13
|
+
InitMessage,
|
|
14
|
+
} from "@notionhq/custom-blocks-protocol/messages/init.js"
|
|
15
|
+
import type { InvalidSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/invalidSandboxMessage.js"
|
|
16
|
+
import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
|
|
30
17
|
import type { PageChangedMessage } from "@notionhq/custom-blocks-protocol/messages/pageChanged.js"
|
|
31
18
|
import type { ParentChangedMessage } from "@notionhq/custom-blocks-protocol/messages/parentChanged.js"
|
|
32
19
|
import type { QueryDataSourceMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSource.js"
|
|
@@ -34,9 +21,8 @@ import type {
|
|
|
34
21
|
CustomBlockQueryDataSourceErrorInfo,
|
|
35
22
|
QueryDataSourceResultMessage,
|
|
36
23
|
} from "@notionhq/custom-blocks-protocol/messages/queryDataSourceResult.js"
|
|
24
|
+
import type { SandboxToHostMessage } from "@notionhq/custom-blocks-protocol/messages/sandboxToHost.js"
|
|
37
25
|
import type { ThemeChangedMessage } from "@notionhq/custom-blocks-protocol/messages/themeChanged.js"
|
|
38
|
-
import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
|
|
39
|
-
import type { UpdatePageResultMessage } from "@notionhq/custom-blocks-protocol/messages/updatePageResult.js"
|
|
40
26
|
import type { CustomBlockPage } from "@notionhq/custom-blocks-protocol/pages/page.js"
|
|
41
27
|
import type { NotionParent } from "@notionhq/custom-blocks-protocol/parent.js"
|
|
42
28
|
import { LATEST_BRIDGE_PROTOCOL_VERSION } from "@notionhq/custom-blocks-protocol/protocolVersion.js"
|
|
@@ -63,6 +49,7 @@ import {
|
|
|
63
49
|
import type { CustomBlockHostQueryDataSourceResult } from "./queries/types.js"
|
|
64
50
|
import { validateQueryDataSourceFilter } from "./queries/validateQueryDataSourceFilter.js"
|
|
65
51
|
import { validateQueryDataSourceSorts } from "./queries/validateQueryDataSourceSorts.js"
|
|
52
|
+
import { unreachable } from "./utils.js"
|
|
66
53
|
|
|
67
54
|
// Bridge protocol version that introduced page: { type: "unavailable" }.
|
|
68
55
|
// Earlier SDKs cannot represent this context, so the host reports context_unavailable.
|
|
@@ -103,7 +90,6 @@ export type CustomBlockHostOptions = {
|
|
|
103
90
|
|
|
104
91
|
export type CustomBlockHostHandle = {
|
|
105
92
|
stop: () => void
|
|
106
|
-
post: (message: HostToSandboxMessage) => void
|
|
107
93
|
setTheme: (theme: NotionTheme) => void
|
|
108
94
|
setContrastMode: (contrastMode: NotionContrastMode) => void
|
|
109
95
|
setParent: (parent: NotionParent) => void
|
|
@@ -113,6 +99,29 @@ export type CustomBlockHostHandle = {
|
|
|
113
99
|
refreshQuery: (args: { dataSourceId: NotionDataSourceId }) => void
|
|
114
100
|
}
|
|
115
101
|
|
|
102
|
+
/**
|
|
103
|
+
* A request that expects one result correlated by `requestId`.
|
|
104
|
+
* Query subscriptions use `subscriptionId` and can receive repeated results.
|
|
105
|
+
*/
|
|
106
|
+
type OneShotRequest = Extract<SandboxToHostMessage, { requestId: string }>
|
|
107
|
+
|
|
108
|
+
/** The matching host result message, named `<request type>Result` by the protocol. */
|
|
109
|
+
type ResultForRequest<Request extends OneShotRequest> = Extract<
|
|
110
|
+
HostToSandboxMessage,
|
|
111
|
+
{ type: `${Request["type"]}Result` }
|
|
112
|
+
>
|
|
113
|
+
|
|
114
|
+
/** The result's success or error payload, without the bridge envelope fields. */
|
|
115
|
+
type ResultPayloadForRequest<Request extends OneShotRequest> =
|
|
116
|
+
BridgeMessagePayload<ResultForRequest<Request>>
|
|
117
|
+
|
|
118
|
+
/** Returns one result payload. `respondToRequest` adds the message type and request ID. */
|
|
119
|
+
type OneShotHandler<Request extends OneShotRequest> = (
|
|
120
|
+
message: Request,
|
|
121
|
+
) =>
|
|
122
|
+
| ResultPayloadForRequest<Request>
|
|
123
|
+
| Promise<ResultPayloadForRequest<Request>>
|
|
124
|
+
|
|
116
125
|
export function createCustomBlockHost(
|
|
117
126
|
options: CustomBlockHostOptions,
|
|
118
127
|
): CustomBlockHostHandle {
|
|
@@ -158,10 +167,20 @@ export function createCustomBlockHost(
|
|
|
158
167
|
onLog?.(direction, payload)
|
|
159
168
|
}
|
|
160
169
|
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
170
|
+
function postToSandbox(message: HostToSandboxMessage) {
|
|
171
|
+
const status = initializationController.status
|
|
172
|
+
switch (status) {
|
|
173
|
+
case "waitingForConnect":
|
|
174
|
+
case "waitingForInitResult":
|
|
175
|
+
case "initialized":
|
|
176
|
+
case "error":
|
|
177
|
+
break
|
|
178
|
+
// A stopped host must not send messages, including pending responses.
|
|
179
|
+
// Return from the function to skip delivery below.
|
|
180
|
+
case "stopped":
|
|
181
|
+
return
|
|
182
|
+
default:
|
|
183
|
+
return unreachable(status)
|
|
165
184
|
}
|
|
166
185
|
const sandboxMessage = normalizeHostToSandboxMessage(
|
|
167
186
|
message,
|
|
@@ -171,6 +190,56 @@ export function createCustomBlockHost(
|
|
|
171
190
|
iframe.contentWindow?.postMessage(sandboxMessage, sandboxOrigin)
|
|
172
191
|
}
|
|
173
192
|
|
|
193
|
+
function sendInitMessage(message: InitMessage) {
|
|
194
|
+
postToSandbox(message)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function sendNack(message: InvalidSandboxMessage) {
|
|
198
|
+
postToSandbox(message)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function sendInitializedMessage(
|
|
202
|
+
message: Exclude<
|
|
203
|
+
HostToSandboxMessage,
|
|
204
|
+
{ type: "init" | "invalidSandboxMessage" }
|
|
205
|
+
>,
|
|
206
|
+
) {
|
|
207
|
+
const status = initializationController.status
|
|
208
|
+
switch (status) {
|
|
209
|
+
case "initialized":
|
|
210
|
+
postToSandbox(message)
|
|
211
|
+
return
|
|
212
|
+
// Send state updates and handler results only after initialization succeeds.
|
|
213
|
+
case "waitingForConnect":
|
|
214
|
+
case "waitingForInitResult":
|
|
215
|
+
case "error":
|
|
216
|
+
case "stopped":
|
|
217
|
+
return
|
|
218
|
+
default:
|
|
219
|
+
unreachable(status)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Invokes a one-shot handler and posts its result with the request's ID.
|
|
225
|
+
* Each result type is named `<request type>Result` by the bridge protocol.
|
|
226
|
+
*/
|
|
227
|
+
async function respondToRequest<Request extends OneShotRequest>(
|
|
228
|
+
message: Request,
|
|
229
|
+
handler: OneShotHandler<Request> | undefined,
|
|
230
|
+
) {
|
|
231
|
+
if (handler === undefined) {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
const response = await handler(message)
|
|
235
|
+
const result = {
|
|
236
|
+
type: `${message.type}Result` as const,
|
|
237
|
+
requestId: message.requestId,
|
|
238
|
+
...response,
|
|
239
|
+
} as ResultForRequest<OneShotRequest>
|
|
240
|
+
sendInitializedMessage(result)
|
|
241
|
+
}
|
|
242
|
+
|
|
174
243
|
function postQueryDataSourceResult(args: {
|
|
175
244
|
subscriptionId: string
|
|
176
245
|
response: CustomBlockHostQueryDataSourceResult
|
|
@@ -190,7 +259,7 @@ export function createCustomBlockHost(
|
|
|
190
259
|
items: args.response.items,
|
|
191
260
|
hasMore: args.response.hasMore,
|
|
192
261
|
}
|
|
193
|
-
|
|
262
|
+
sendInitializedMessage(message)
|
|
194
263
|
}
|
|
195
264
|
|
|
196
265
|
async function handleQuery(
|
|
@@ -221,117 +290,39 @@ export function createCustomBlockHost(
|
|
|
221
290
|
})
|
|
222
291
|
}
|
|
223
292
|
|
|
224
|
-
async function handleCreatePage(message: CreatePageMessage) {
|
|
225
|
-
if (handlers.createPage === undefined) {
|
|
226
|
-
return
|
|
227
|
-
}
|
|
228
|
-
const response = await handlers.createPage(message)
|
|
229
|
-
const result: CreatePageResultMessage = {
|
|
230
|
-
type: "createPageResult",
|
|
231
|
-
requestId: message.requestId,
|
|
232
|
-
...response,
|
|
233
|
-
}
|
|
234
|
-
post(result)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async function handleGetPage(message: GetPageMessage) {
|
|
238
|
-
if (handlers.getPage === undefined) {
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
const response = await handlers.getPage(message)
|
|
242
|
-
const result: GetPageResultMessage = {
|
|
243
|
-
type: "getPageResult",
|
|
244
|
-
requestId: message.requestId,
|
|
245
|
-
...response,
|
|
246
|
-
}
|
|
247
|
-
post(result)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async function handleGetUser(message: GetUserMessage) {
|
|
251
|
-
if (handlers.getUser === undefined) {
|
|
252
|
-
return
|
|
253
|
-
}
|
|
254
|
-
const response = await handlers.getUser(message)
|
|
255
|
-
const result: GetUserResultMessage = {
|
|
256
|
-
type: "getUserResult",
|
|
257
|
-
requestId: message.requestId,
|
|
258
|
-
...response,
|
|
259
|
-
}
|
|
260
|
-
post(result)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function handleListUsers(message: ListUsersMessage) {
|
|
264
|
-
if (handlers.listUsers === undefined) {
|
|
265
|
-
return
|
|
266
|
-
}
|
|
267
|
-
const response = await handlers.listUsers(message)
|
|
268
|
-
const result: ListUsersResultMessage = {
|
|
269
|
-
type: "listUsersResult",
|
|
270
|
-
requestId: message.requestId,
|
|
271
|
-
...response,
|
|
272
|
-
}
|
|
273
|
-
post(result)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
async function handleOpenPage(message: OpenPageMessage) {
|
|
277
|
-
if (handlers.openPage === undefined) {
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
const response = await handlers.openPage(message)
|
|
281
|
-
const result: OpenPageResultMessage = {
|
|
282
|
-
type: "openPageResult",
|
|
283
|
-
requestId: message.requestId,
|
|
284
|
-
...response,
|
|
285
|
-
}
|
|
286
|
-
post(result)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async function handleUpdatePage(message: UpdatePageMessage) {
|
|
290
|
-
if (handlers.updatePage === undefined) {
|
|
291
|
-
return
|
|
292
|
-
}
|
|
293
|
-
const response = await handlers.updatePage(message)
|
|
294
|
-
const result: UpdatePageResultMessage = {
|
|
295
|
-
type: "updatePageResult",
|
|
296
|
-
requestId: message.requestId,
|
|
297
|
-
...response,
|
|
298
|
-
}
|
|
299
|
-
post(result)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
293
|
/**
|
|
303
294
|
* Sends any pending host state changes to the sandbox. It is possible for these to change
|
|
304
295
|
* between when the host sends `init` and when the sandbox responds with `initResult`. The host
|
|
305
|
-
* does send
|
|
296
|
+
* does not send pending state changes until the sandbox responds.
|
|
306
297
|
*/
|
|
307
298
|
function flushPendingHostStateChanges() {
|
|
308
299
|
if (pendingThemeChange) {
|
|
309
300
|
pendingThemeChange = false
|
|
310
|
-
|
|
301
|
+
sendInitializedMessage({ type: "themeChanged", theme })
|
|
311
302
|
}
|
|
312
303
|
if (pendingContrastModeChange) {
|
|
313
304
|
pendingContrastModeChange = false
|
|
314
|
-
|
|
305
|
+
sendInitializedMessage({ type: "contrastModeChanged", contrastMode })
|
|
315
306
|
}
|
|
316
307
|
if (pendingParentChange) {
|
|
317
308
|
pendingParentChange = false
|
|
318
|
-
|
|
309
|
+
sendInitializedMessage({ type: "parentChanged", parent })
|
|
319
310
|
}
|
|
320
311
|
if (pendingPageChange) {
|
|
321
312
|
pendingPageChange = false
|
|
322
|
-
|
|
313
|
+
sendInitializedMessage({ type: "pageChanged", page })
|
|
323
314
|
}
|
|
324
315
|
if (pendingDataSourcesChange !== undefined) {
|
|
325
316
|
const nextDataSources = pendingDataSourcesChange
|
|
326
317
|
pendingDataSourcesChange = undefined
|
|
327
|
-
|
|
318
|
+
sendInitializedMessage({
|
|
328
319
|
type: "dataSourcesChanged",
|
|
329
320
|
dataSources: nextDataSources,
|
|
330
321
|
})
|
|
331
322
|
}
|
|
332
323
|
if (pendingCurrentUserChange) {
|
|
333
324
|
pendingCurrentUserChange = false
|
|
334
|
-
|
|
325
|
+
sendInitializedMessage({ type: "currentUserChanged", currentUser })
|
|
335
326
|
}
|
|
336
327
|
}
|
|
337
328
|
|
|
@@ -383,7 +374,7 @@ export function createCustomBlockHost(
|
|
|
383
374
|
dataSources: resolvedDataSources,
|
|
384
375
|
}
|
|
385
376
|
},
|
|
386
|
-
|
|
377
|
+
sendInitMessage,
|
|
387
378
|
warn: payload => emit("warn", payload),
|
|
388
379
|
flushPendingHostStateChanges,
|
|
389
380
|
minBridgeProtocolVersion,
|
|
@@ -403,7 +394,7 @@ export function createCustomBlockHost(
|
|
|
403
394
|
sandboxOrigin,
|
|
404
395
|
getInitStatus: () => initializationController.status,
|
|
405
396
|
emit,
|
|
406
|
-
|
|
397
|
+
sendNack,
|
|
407
398
|
onInvalidConnect: initializationController.handleInvalidConnect,
|
|
408
399
|
onInvalidInitResult: initializationController.handleInvalidInitResult,
|
|
409
400
|
onConnect: initializationController.handleConnect,
|
|
@@ -411,12 +402,12 @@ export function createCustomBlockHost(
|
|
|
411
402
|
onQueryDataSource: handleQuery,
|
|
412
403
|
onUnsubscribeDataSourceQuery: message =>
|
|
413
404
|
querySubscriptions.unsubscribe(message.subscriptionId),
|
|
414
|
-
onCreatePage:
|
|
415
|
-
onGetPage:
|
|
416
|
-
onOpenPage:
|
|
417
|
-
onGetUser:
|
|
418
|
-
onListUsers:
|
|
419
|
-
onUpdatePage:
|
|
405
|
+
onCreatePage: message => respondToRequest(message, handlers.createPage),
|
|
406
|
+
onGetPage: message => respondToRequest(message, handlers.getPage),
|
|
407
|
+
onOpenPage: message => respondToRequest(message, handlers.openPage),
|
|
408
|
+
onGetUser: message => respondToRequest(message, handlers.getUser),
|
|
409
|
+
onListUsers: message => respondToRequest(message, handlers.listUsers),
|
|
410
|
+
onUpdatePage: message => respondToRequest(message, handlers.updatePage),
|
|
420
411
|
onResize: message => handlers.resize?.(message),
|
|
421
412
|
})
|
|
422
413
|
|
|
@@ -438,21 +429,20 @@ export function createCustomBlockHost(
|
|
|
438
429
|
|
|
439
430
|
return {
|
|
440
431
|
stop,
|
|
441
|
-
post,
|
|
442
432
|
setTheme(nextTheme) {
|
|
443
433
|
theme = nextTheme
|
|
444
|
-
if (initializationController.status !== "
|
|
434
|
+
if (initializationController.status !== "initialized") {
|
|
445
435
|
if (initializationController.status === "waitingForInitResult") {
|
|
446
436
|
pendingThemeChange = true
|
|
447
437
|
}
|
|
448
438
|
return
|
|
449
439
|
}
|
|
450
440
|
const message: ThemeChangedMessage = { type: "themeChanged", theme }
|
|
451
|
-
|
|
441
|
+
sendInitializedMessage(message)
|
|
452
442
|
},
|
|
453
443
|
setContrastMode(nextContrastMode) {
|
|
454
444
|
contrastMode = nextContrastMode
|
|
455
|
-
if (initializationController.status !== "
|
|
445
|
+
if (initializationController.status !== "initialized") {
|
|
456
446
|
if (initializationController.status === "waitingForInitResult") {
|
|
457
447
|
pendingContrastModeChange = true
|
|
458
448
|
}
|
|
@@ -462,18 +452,18 @@ export function createCustomBlockHost(
|
|
|
462
452
|
type: "contrastModeChanged",
|
|
463
453
|
contrastMode,
|
|
464
454
|
}
|
|
465
|
-
|
|
455
|
+
sendInitializedMessage(message)
|
|
466
456
|
},
|
|
467
457
|
setParent(nextParent) {
|
|
468
458
|
parent = nextParent
|
|
469
|
-
if (initializationController.status !== "
|
|
459
|
+
if (initializationController.status !== "initialized") {
|
|
470
460
|
if (initializationController.status === "waitingForInitResult") {
|
|
471
461
|
pendingParentChange = true
|
|
472
462
|
}
|
|
473
463
|
return
|
|
474
464
|
}
|
|
475
465
|
const message: ParentChangedMessage = { type: "parentChanged", parent }
|
|
476
|
-
|
|
466
|
+
sendInitializedMessage(message)
|
|
477
467
|
},
|
|
478
468
|
setPage(nextPage) {
|
|
479
469
|
page = nextPage
|
|
@@ -482,19 +472,19 @@ export function createCustomBlockHost(
|
|
|
482
472
|
sandboxBridgeProtocolVersion <
|
|
483
473
|
BRIDGE_PROTOCOL_VERSION_INTRODUCING_UNAVAILABLE_PAGE &&
|
|
484
474
|
(initializationController.status === "waitingForInitResult" ||
|
|
485
|
-
initializationController.status === "
|
|
475
|
+
initializationController.status === "initialized")
|
|
486
476
|
) {
|
|
487
477
|
stopWithFailure(initErrorForFailureReason("context_unavailable"))
|
|
488
478
|
return
|
|
489
479
|
}
|
|
490
|
-
if (initializationController.status !== "
|
|
480
|
+
if (initializationController.status !== "initialized") {
|
|
491
481
|
if (initializationController.status === "waitingForInitResult") {
|
|
492
482
|
pendingPageChange = true
|
|
493
483
|
}
|
|
494
484
|
return
|
|
495
485
|
}
|
|
496
486
|
const message: PageChangedMessage = { type: "pageChanged", page }
|
|
497
|
-
|
|
487
|
+
sendInitializedMessage(message)
|
|
498
488
|
},
|
|
499
489
|
setDataSources(nextDataSources) {
|
|
500
490
|
if (
|
|
@@ -510,7 +500,7 @@ export function createCustomBlockHost(
|
|
|
510
500
|
}
|
|
511
501
|
dataSources = nextDataSources
|
|
512
502
|
activeDataSources = nextDataSources
|
|
513
|
-
if (initializationController.status !== "
|
|
503
|
+
if (initializationController.status !== "initialized") {
|
|
514
504
|
if (initializationController.status === "waitingForInitResult") {
|
|
515
505
|
pendingDataSourcesChange = nextDataSources
|
|
516
506
|
}
|
|
@@ -520,20 +510,20 @@ export function createCustomBlockHost(
|
|
|
520
510
|
type: "dataSourcesChanged",
|
|
521
511
|
dataSources: nextDataSources,
|
|
522
512
|
}
|
|
523
|
-
|
|
513
|
+
sendInitializedMessage(message)
|
|
524
514
|
},
|
|
525
515
|
setCurrentUser(nextCurrentUser) {
|
|
526
516
|
currentUser = nextCurrentUser
|
|
527
|
-
if (initializationController.status !== "
|
|
517
|
+
if (initializationController.status !== "initialized") {
|
|
528
518
|
if (initializationController.status === "waitingForInitResult") {
|
|
529
519
|
pendingCurrentUserChange = true
|
|
530
520
|
}
|
|
531
521
|
return
|
|
532
522
|
}
|
|
533
|
-
|
|
523
|
+
sendInitializedMessage({ type: "currentUserChanged", currentUser })
|
|
534
524
|
},
|
|
535
525
|
refreshQuery({ dataSourceId }) {
|
|
536
|
-
if (initializationController.status !== "
|
|
526
|
+
if (initializationController.status !== "initialized") {
|
|
537
527
|
return
|
|
538
528
|
}
|
|
539
529
|
const refreshes = querySubscriptions.refresh(dataSourceId)
|
|
@@ -2,7 +2,6 @@ import type { NotionContrastMode } from "@notionhq/custom-blocks-protocol/contra
|
|
|
2
2
|
import type { NotionBlockId } from "@notionhq/custom-blocks-protocol/ids.js"
|
|
3
3
|
import type { CustomBlockManifest } from "@notionhq/custom-blocks-protocol/manifest.js"
|
|
4
4
|
import type { ConnectMessage } from "@notionhq/custom-blocks-protocol/messages/connect.js"
|
|
5
|
-
import type { HostToSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/hostToSandbox.js"
|
|
6
5
|
import type {
|
|
7
6
|
CustomBlockInitErrorInfo,
|
|
8
7
|
InitMessage,
|
|
@@ -47,7 +46,7 @@ export type InitializationControllerOptions = {
|
|
|
47
46
|
blockId: NotionBlockId
|
|
48
47
|
getState: () => InitializationState
|
|
49
48
|
prepareInit: (connect: ConnectSuccessMessage) => InitializationPreparation
|
|
50
|
-
|
|
49
|
+
sendInitMessage: (message: InitMessage) => void
|
|
51
50
|
warn: (payload: unknown) => void
|
|
52
51
|
flushPendingHostStateChanges: () => void
|
|
53
52
|
minBridgeProtocolVersion: number
|
|
@@ -83,7 +82,7 @@ export function createInitializationController(
|
|
|
83
82
|
blockId,
|
|
84
83
|
getState,
|
|
85
84
|
prepareInit,
|
|
86
|
-
|
|
85
|
+
sendInitMessage,
|
|
87
86
|
warn,
|
|
88
87
|
flushPendingHostStateChanges,
|
|
89
88
|
minBridgeProtocolVersion,
|
|
@@ -126,7 +125,7 @@ export function createInitializationController(
|
|
|
126
125
|
initStatus = "error"
|
|
127
126
|
activeInitializationId = initializationId
|
|
128
127
|
clearNoConnectTimeout()
|
|
129
|
-
|
|
128
|
+
sendInitMessage({
|
|
130
129
|
type: "init",
|
|
131
130
|
initializationId,
|
|
132
131
|
status: "error",
|
|
@@ -135,11 +134,16 @@ export function createInitializationController(
|
|
|
135
134
|
onFailure?.(error)
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
function
|
|
137
|
+
function prepareAndSendInit(connect: ConnectSuccessMessage): boolean {
|
|
139
138
|
if (initStatus !== "waitingForConnect") {
|
|
140
139
|
return false
|
|
141
140
|
}
|
|
142
141
|
const preparation = prepareInit(connect)
|
|
142
|
+
// The embedder can stop the host when it receives the manifest.
|
|
143
|
+
// If that happens, do not continue initialization or start its timer.
|
|
144
|
+
if (initStatus !== "waitingForConnect") {
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
143
147
|
if (preparation.status === "error") {
|
|
144
148
|
sendInitError({
|
|
145
149
|
initializationId: connect.initializationId,
|
|
@@ -164,7 +168,7 @@ export function createInitializationController(
|
|
|
164
168
|
dataSources: preparation.dataSources,
|
|
165
169
|
currentUser: state.currentUser,
|
|
166
170
|
}
|
|
167
|
-
|
|
171
|
+
sendInitMessage(message)
|
|
168
172
|
noInitResultTimeoutId = window.setTimeout(() => {
|
|
169
173
|
if (initStatus !== "waitingForInitResult") {
|
|
170
174
|
return
|
|
@@ -223,7 +227,7 @@ export function createInitializationController(
|
|
|
223
227
|
return
|
|
224
228
|
}
|
|
225
229
|
|
|
226
|
-
if (
|
|
230
|
+
if (prepareAndSendInit(message)) {
|
|
227
231
|
hasConnectedSandbox = true
|
|
228
232
|
}
|
|
229
233
|
}
|
|
@@ -324,7 +328,7 @@ export function createInitializationController(
|
|
|
324
328
|
}
|
|
325
329
|
clearNoInitResultTimeout()
|
|
326
330
|
if (message.status === "success") {
|
|
327
|
-
initStatus = "
|
|
331
|
+
initStatus = "initialized"
|
|
328
332
|
flushPendingHostStateChanges()
|
|
329
333
|
} else {
|
|
330
334
|
initStatus = "error"
|
package/src/lifecycle/types.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type InitStatus =
|
|
|
20
20
|
/** The host is waiting for a matching `initResult` after it sends `init`. */
|
|
21
21
|
| "waitingForInitResult"
|
|
22
22
|
/** The host is initialized and can send live updates. */
|
|
23
|
-
| "
|
|
23
|
+
| "initialized"
|
|
24
24
|
/** The host is in an error state after an initialization failure or timeout. */
|
|
25
25
|
| "error"
|
|
26
26
|
/** The host is stopped and no longer sends or accepts sandbox messages. */
|
|
@@ -2,8 +2,8 @@ import type { ConnectMessage } from "@notionhq/custom-blocks-protocol/messages/c
|
|
|
2
2
|
import type { CreatePageMessage } from "@notionhq/custom-blocks-protocol/messages/createPage.js"
|
|
3
3
|
import type { GetPageMessage } from "@notionhq/custom-blocks-protocol/messages/getPage.js"
|
|
4
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
5
|
import type { InitResultMessage } from "@notionhq/custom-blocks-protocol/messages/initResult.js"
|
|
6
|
+
import type { InvalidSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/invalidSandboxMessage.js"
|
|
7
7
|
import { isInitHandshakeMessage } from "@notionhq/custom-blocks-protocol/messages/isInitHandshakeMessage.js"
|
|
8
8
|
import type { ListUsersMessage } from "@notionhq/custom-blocks-protocol/messages/listUsers.js"
|
|
9
9
|
import type { OpenPageMessage } from "@notionhq/custom-blocks-protocol/messages/openPage.js"
|
|
@@ -35,7 +35,7 @@ export type SandboxMessageRouterOptions = {
|
|
|
35
35
|
sandboxOrigin: string
|
|
36
36
|
getInitStatus: () => InitStatus
|
|
37
37
|
emit: (direction: CustomBlockHostLogDirection, payload: unknown) => void
|
|
38
|
-
|
|
38
|
+
sendNack: (message: InvalidSandboxMessage) => void
|
|
39
39
|
onInvalidConnect: InitializationController["handleInvalidConnect"]
|
|
40
40
|
onInvalidInitResult: InitializationController["handleInvalidInitResult"]
|
|
41
41
|
onConnect: (message: ConnectMessage) => void
|
|
@@ -61,7 +61,7 @@ export function createSandboxMessageRouter(
|
|
|
61
61
|
sandboxOrigin,
|
|
62
62
|
getInitStatus,
|
|
63
63
|
emit,
|
|
64
|
-
|
|
64
|
+
sendNack,
|
|
65
65
|
onInvalidConnect,
|
|
66
66
|
onInvalidInitResult,
|
|
67
67
|
onConnect,
|
|
@@ -116,9 +116,9 @@ export function createSandboxMessageRouter(
|
|
|
116
116
|
})
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
// Other messages get NACKed indicating they were invalid and skipped
|
|
120
|
-
if (response.nack !== undefined) {
|
|
121
|
-
|
|
119
|
+
// Other messages get NACKed indicating they were invalid and skipped.
|
|
120
|
+
if (response.nack !== undefined && getInitStatus() !== "stopped") {
|
|
121
|
+
sendNack(response.nack)
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -139,7 +139,7 @@ export function createSandboxMessageRouter(
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
const message = parsed.output
|
|
142
|
-
if (!isInitHandshakeMessage(message) && getInitStatus() !== "
|
|
142
|
+
if (!isInitHandshakeMessage(message) && getInitStatus() !== "initialized") {
|
|
143
143
|
emit("warn", {
|
|
144
144
|
message: `Ignored ${message.type} before initialization completed`,
|
|
145
145
|
payload: message,
|