@notionhq/custom-blocks-host 0.5.1 → 0.6.0
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 +9 -0
- package/dist/browser.js +1 -1
- package/dist/compatibility/normalizeHostToSandboxMessage.d.ts.map +1 -1
- package/dist/compatibility/normalizeHostToSandboxMessage.js +5 -1
- package/dist/compatibility/normalizeSandboxToHostMessage.d.ts +88 -1
- package/dist/compatibility/normalizeSandboxToHostMessage.d.ts.map +1 -1
- package/dist/compatibility/pages/toIconForProtocol3To8.d.ts +4 -0
- package/dist/compatibility/pages/toIconForProtocol3To8.d.ts.map +1 -0
- package/dist/compatibility/pages/toIconForProtocol3To8.js +13 -0
- package/dist/compatibility/protocol3To5/toPageForProtocol3To5.d.ts.map +1 -1
- package/dist/compatibility/protocol3To5/toPageForProtocol3To5.js +2 -1
- package/dist/compatibility/protocol3To5/toQueryPageForProtocol3To5.d.ts +8 -8
- package/dist/compatibility/protocol6/normalizePageResultsForProtocol6.d.ts.map +1 -1
- package/dist/compatibility/protocol6/normalizePageResultsForProtocol6.js +9 -2
- package/dist/compatibility/protocol7To8/normalizePageResultsForProtocol7To8.d.ts +4 -0
- package/dist/compatibility/protocol7To8/normalizePageResultsForProtocol7To8.d.ts.map +1 -0
- package/dist/compatibility/protocol7To8/normalizePageResultsForProtocol7To8.js +16 -0
- package/dist/createCustomBlockHost.d.ts.map +1 -1
- package/dist/createCustomBlockHost.js +50 -34
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/messages/createSandboxMessageRouter.d.ts +3 -2
- package/dist/messages/createSandboxMessageRouter.d.ts.map +1 -1
- package/dist/messages/createSandboxMessageRouter.js +7 -1
- package/dist/messages/getInvalidSandboxMessageResponse.d.ts.map +1 -1
- package/dist/messages/getInvalidSandboxMessageResponse.js +3 -0
- package/dist/messages/invalidNativeIconColor.d.ts +5 -0
- package/dist/messages/invalidNativeIconColor.d.ts.map +1 -0
- package/dist/messages/invalidNativeIconColor.js +34 -0
- package/dist/pages/types.d.ts +2 -0
- package/dist/pages/types.d.ts.map +1 -1
- package/dist/protocol/compatibility/protocol3To5/bridgePage.d.ts +7 -1
- package/dist/protocol/dataSources/messages/queryDataSource.d.ts +14 -2
- package/dist/protocol/icons.d.ts +17 -0
- package/dist/protocol/icons.js +27 -0
- package/dist/protocol/index.d.ts +5 -3
- package/dist/protocol/index.js +4 -2
- package/dist/protocol/messages/hostToSandbox.d.ts +79 -11
- package/dist/protocol/messages/invalidHostMessage.d.ts +2 -0
- package/dist/protocol/messages/invalidHostMessage.js +2 -0
- package/dist/protocol/messages/invalidSandboxMessage.d.ts +2 -0
- package/dist/protocol/messages/invalidSandboxMessage.js +2 -0
- package/dist/protocol/messages/sandboxToHost.d.ts +88 -1
- package/dist/protocol/navigation/openExternalUrl.d.ts +2 -2
- package/dist/protocol/pages/bridgePage.d.ts +7 -1
- package/dist/protocol/pages/messages/createPage.d.ts +103 -5
- package/dist/protocol/pages/messages/createPage.js +3 -1
- package/dist/protocol/pages/messages/getPage.d.ts +23 -5
- package/dist/protocol/pages/messages/openPage.d.ts +2 -2
- package/dist/protocol/pages/messages/updatePage.d.ts +30 -6
- package/dist/protocol/pages/pageAppearance.d.ts +36 -1
- package/dist/protocol/pages/pageAppearance.js +9 -0
- package/dist/protocol/users/messages/getUser.d.ts +2 -2
- package/dist/protocol/users/messages/listUsers.d.ts +2 -2
- package/dist/protocol/utils/errors.d.ts +2 -0
- package/dist/protocol/utils/protocolVersion.d.ts +2 -1
- package/dist/protocol/utils/protocolVersion.js +3 -1
- package/dist/protocol/utils/readRequestId.d.ts +2 -0
- package/dist/protocol/utils/readRequestId.js +7 -0
- package/docs/bridge/changelog.md +19 -0
- package/docs/bridge/protocol.md +30 -1
- package/docs/bridge/versioning.md +1 -0
- package/docs/compatibility.md +15 -7
- package/docs/handlers.md +6 -3
- package/package.json +1 -1
- package/src/compatibility/normalizeHostToSandboxMessage.ts +5 -0
- package/src/compatibility/pages/toIconForProtocol3To8.ts +17 -0
- package/src/compatibility/protocol3To5/toPageForProtocol3To5.ts +2 -1
- package/src/compatibility/protocol6/normalizePageResultsForProtocol6.ts +11 -2
- package/src/compatibility/protocol7To8/normalizePageResultsForProtocol7To8.ts +22 -0
- package/src/createCustomBlockHost.ts +57 -37
- package/src/index.ts +1 -0
- package/src/messages/createSandboxMessageRouter.ts +18 -2
- package/src/messages/getInvalidSandboxMessageResponse.ts +3 -0
- package/src/messages/invalidNativeIconColor.ts +43 -0
- package/src/pages/types.ts +3 -0
|
@@ -148,6 +148,8 @@ export type CustomBlockHostHandle = {
|
|
|
148
148
|
*/
|
|
149
149
|
type OneShotRequest = Extract<SandboxToHostMessage, { requestId: string }>
|
|
150
150
|
|
|
151
|
+
type RequestError = { status: "error"; error: CustomBlockErrorInfo }
|
|
152
|
+
|
|
151
153
|
export function createCustomBlockHost(
|
|
152
154
|
options: CustomBlockHostOptions,
|
|
153
155
|
): CustomBlockHostHandle {
|
|
@@ -247,22 +249,39 @@ export function createCustomBlockHost(
|
|
|
247
249
|
* Invokes a one-shot handler and posts its result with the request's ID.
|
|
248
250
|
* Each result type is named `<request type>Result` by the bridge protocol.
|
|
249
251
|
*/
|
|
250
|
-
async function
|
|
252
|
+
async function handleRequest<
|
|
251
253
|
Request extends OneShotRequest,
|
|
252
254
|
Response extends object,
|
|
253
255
|
>(
|
|
254
256
|
message: Request,
|
|
255
257
|
handler: ((message: Request) => Response | Promise<Response>) | undefined,
|
|
256
258
|
) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
+
try {
|
|
260
|
+
const response =
|
|
261
|
+
handler === undefined
|
|
262
|
+
? unsupportedOperation(message.type)
|
|
263
|
+
: await handler(message)
|
|
264
|
+
sendInitializedMessage({
|
|
265
|
+
...response,
|
|
266
|
+
type: `${message.type}Result`,
|
|
267
|
+
requestId: message.requestId,
|
|
268
|
+
})
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (initializationController.status !== "initialized") {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
emit("warn", error)
|
|
274
|
+
sendInitializedMessage({
|
|
275
|
+
type: `${message.type}Result`,
|
|
276
|
+
requestId: message.requestId,
|
|
277
|
+
status: "error",
|
|
278
|
+
error: {
|
|
279
|
+
code: "unknown_error",
|
|
280
|
+
message: `The host could not complete ${message.type}.`,
|
|
281
|
+
isRetryable: false,
|
|
282
|
+
},
|
|
283
|
+
})
|
|
259
284
|
}
|
|
260
|
-
const response = await handler(message)
|
|
261
|
-
sendInitializedMessage({
|
|
262
|
-
type: `${message.type}Result` as const,
|
|
263
|
-
requestId: message.requestId,
|
|
264
|
-
...response,
|
|
265
|
-
})
|
|
266
285
|
}
|
|
267
286
|
|
|
268
287
|
function postQueryDataSourceResult(args: {
|
|
@@ -338,10 +357,12 @@ export function createCustomBlockHost(
|
|
|
338
357
|
}
|
|
339
358
|
|
|
340
359
|
async function handleOpenExternalUrl(message: OpenExternalUrlMessage) {
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
360
|
+
if (navigationAbortController.signal.aborted) {
|
|
361
|
+
return
|
|
362
|
+
}
|
|
363
|
+
const handler = handlers.openExternalUrl
|
|
364
|
+
if (handler === undefined) {
|
|
365
|
+
await handleRequest(message, undefined)
|
|
345
366
|
return
|
|
346
367
|
}
|
|
347
368
|
if (pendingOpenExternalUrlRequestId === message.requestId) {
|
|
@@ -380,25 +401,12 @@ export function createCustomBlockHost(
|
|
|
380
401
|
|
|
381
402
|
pendingOpenExternalUrlRequestId = message.requestId
|
|
382
403
|
try {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
signal: navigationAbortController.signal,
|
|
387
|
-
|
|
404
|
+
await handleRequest(message, () =>
|
|
405
|
+
handler(
|
|
406
|
+
{ ...message, url },
|
|
407
|
+
{ signal: navigationAbortController.signal },
|
|
408
|
+
),
|
|
388
409
|
)
|
|
389
|
-
if (navigationAbortController.signal.aborted) {
|
|
390
|
-
return
|
|
391
|
-
}
|
|
392
|
-
const result: OpenExternalUrlResultMessage = {
|
|
393
|
-
type: "openExternalUrlResult",
|
|
394
|
-
requestId: message.requestId,
|
|
395
|
-
...response,
|
|
396
|
-
}
|
|
397
|
-
sendInitializedMessage(result)
|
|
398
|
-
} catch (error) {
|
|
399
|
-
if (!navigationAbortController.signal.aborted) {
|
|
400
|
-
throw error
|
|
401
|
-
}
|
|
402
410
|
} finally {
|
|
403
411
|
if (pendingOpenExternalUrlRequestId === message.requestId) {
|
|
404
412
|
pendingOpenExternalUrlRequestId = undefined
|
|
@@ -595,6 +603,7 @@ export function createCustomBlockHost(
|
|
|
595
603
|
getInitStatus: () => initializationController.status,
|
|
596
604
|
emit,
|
|
597
605
|
sendNack,
|
|
606
|
+
sendPageMutationError: postToSandbox,
|
|
598
607
|
onInvalidConnect: initializationController.handleInvalidConnect,
|
|
599
608
|
onInvalidInitResult: initializationController.handleInvalidInitResult,
|
|
600
609
|
onConnect: initializationController.handleConnect,
|
|
@@ -603,12 +612,12 @@ export function createCustomBlockHost(
|
|
|
603
612
|
onUnsubscribeDataSourceQuery: message =>
|
|
604
613
|
querySubscriptions.unsubscribe(message.subscriptionId),
|
|
605
614
|
onOpenExternalUrl: handleOpenExternalUrl,
|
|
606
|
-
onCreatePage: message =>
|
|
607
|
-
onGetPage: message =>
|
|
608
|
-
onOpenPage: message =>
|
|
609
|
-
onGetUser: message =>
|
|
610
|
-
onListUsers: message =>
|
|
611
|
-
onUpdatePage: message =>
|
|
615
|
+
onCreatePage: message => handleRequest(message, handlers.createPage),
|
|
616
|
+
onGetPage: message => handleRequest(message, handlers.getPage),
|
|
617
|
+
onOpenPage: message => handleRequest(message, handlers.openPage),
|
|
618
|
+
onGetUser: message => handleRequest(message, handlers.getUser),
|
|
619
|
+
onListUsers: message => handleRequest(message, handlers.listUsers),
|
|
620
|
+
onUpdatePage: message => handleRequest(message, handlers.updatePage),
|
|
612
621
|
onResize: message => handlers.resize?.(message),
|
|
613
622
|
})
|
|
614
623
|
|
|
@@ -793,6 +802,17 @@ function getBindingError(
|
|
|
793
802
|
return undefined
|
|
794
803
|
}
|
|
795
804
|
|
|
805
|
+
function unsupportedOperation(type: string): RequestError {
|
|
806
|
+
return {
|
|
807
|
+
status: "error",
|
|
808
|
+
error: {
|
|
809
|
+
code: "unsupported_operation",
|
|
810
|
+
message: `The host does not support ${type}.`,
|
|
811
|
+
isRetryable: false,
|
|
812
|
+
},
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
796
816
|
function getQueryValidationError(
|
|
797
817
|
message: QueryDataSourceMessage,
|
|
798
818
|
collectionSchema: NotionCollectionSchema | undefined,
|
package/src/index.ts
CHANGED
|
@@ -6,10 +6,16 @@ import type { InitResultMessage } from "@notionhq/custom-blocks-protocol/handsha
|
|
|
6
6
|
import { isInitHandshakeMessage } from "@notionhq/custom-blocks-protocol/handshake/isInitHandshakeMessage.js"
|
|
7
7
|
import type { InvalidSandboxMessage } from "@notionhq/custom-blocks-protocol/messages/invalidSandboxMessage.js"
|
|
8
8
|
import type { OpenExternalUrlMessage } from "@notionhq/custom-blocks-protocol/navigation/openExternalUrl.js"
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
CreatePageMessage,
|
|
11
|
+
CreatePageResultMessage,
|
|
12
|
+
} from "@notionhq/custom-blocks-protocol/pages/messages/createPage.js"
|
|
10
13
|
import type { GetPageMessage } from "@notionhq/custom-blocks-protocol/pages/messages/getPage.js"
|
|
11
14
|
import type { OpenPageMessage } from "@notionhq/custom-blocks-protocol/pages/messages/openPage.js"
|
|
12
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
UpdatePageMessage,
|
|
17
|
+
UpdatePageResultMessage,
|
|
18
|
+
} from "@notionhq/custom-blocks-protocol/pages/messages/updatePage.js"
|
|
13
19
|
import type { GetUserMessage } from "@notionhq/custom-blocks-protocol/users/messages/getUser.js"
|
|
14
20
|
import type { ListUsersMessage } from "@notionhq/custom-blocks-protocol/users/messages/listUsers.js"
|
|
15
21
|
import * as v from "valibot"
|
|
@@ -20,6 +26,7 @@ import { invalidInitResultPayloadError } from "../lifecycle/errors/invalidInitRe
|
|
|
20
26
|
import type { InitStatus } from "../lifecycle/types.js"
|
|
21
27
|
import { unreachable } from "../utils/unreachable.js"
|
|
22
28
|
import { getInvalidSandboxMessageResponse } from "./getInvalidSandboxMessageResponse.js"
|
|
29
|
+
import { getInvalidNativeIconColorResponse } from "./invalidNativeIconColor.js"
|
|
23
30
|
import type { CustomBlockHostLogDirection } from "./logging.js"
|
|
24
31
|
|
|
25
32
|
const initializationIdentitySchema = v.object({
|
|
@@ -38,6 +45,9 @@ export type SandboxMessageRouterOptions = {
|
|
|
38
45
|
getInitStatus: () => InitStatus
|
|
39
46
|
emit: (direction: CustomBlockHostLogDirection, payload: unknown) => void
|
|
40
47
|
sendNack: (message: InvalidSandboxMessage) => void
|
|
48
|
+
sendPageMutationError: (
|
|
49
|
+
message: UpdatePageResultMessage | CreatePageResultMessage,
|
|
50
|
+
) => void
|
|
41
51
|
onInvalidConnect: InitializationController["handleInvalidConnect"]
|
|
42
52
|
onInvalidInitResult: InitializationController["handleInvalidInitResult"]
|
|
43
53
|
onConnect: (message: ConnectMessage) => void
|
|
@@ -65,6 +75,7 @@ export function createSandboxMessageRouter(
|
|
|
65
75
|
getInitStatus,
|
|
66
76
|
emit,
|
|
67
77
|
sendNack,
|
|
78
|
+
sendPageMutationError,
|
|
68
79
|
onInvalidConnect,
|
|
69
80
|
onInvalidInitResult,
|
|
70
81
|
onConnect,
|
|
@@ -85,6 +96,11 @@ export function createSandboxMessageRouter(
|
|
|
85
96
|
data: unknown,
|
|
86
97
|
issues: readonly v.BaseIssue<unknown>[],
|
|
87
98
|
) {
|
|
99
|
+
const iconError = getInvalidNativeIconColorResponse(data)
|
|
100
|
+
if (iconError !== undefined && getInitStatus() === "initialized") {
|
|
101
|
+
sendPageMutationError(iconError)
|
|
102
|
+
return
|
|
103
|
+
}
|
|
88
104
|
emit("warn", {
|
|
89
105
|
message: "Ignored unsupported sandbox message",
|
|
90
106
|
payload: redactExternalUrl(data),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
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
|
+
import { readRequestId } from "@notionhq/custom-blocks-protocol/utils/readRequestId.js"
|
|
3
4
|
|
|
4
5
|
export type InvalidSandboxMessageResponse = {
|
|
5
6
|
incomingType: string | undefined
|
|
@@ -16,10 +17,12 @@ export function getInvalidSandboxMessageResponse(
|
|
|
16
17
|
) {
|
|
17
18
|
return { incomingType }
|
|
18
19
|
}
|
|
20
|
+
const requestId = readRequestId(data)
|
|
19
21
|
return {
|
|
20
22
|
incomingType,
|
|
21
23
|
nack: {
|
|
22
24
|
type: "invalidSandboxMessage",
|
|
25
|
+
...(requestId !== undefined ? { requestId } : {}),
|
|
23
26
|
reason: nackReasonForInvalidSandboxMessage(incomingType),
|
|
24
27
|
},
|
|
25
28
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { notionIconColorSchema } from "@notionhq/custom-blocks-protocol/icons.js"
|
|
2
|
+
import type { CreatePageResultMessage } from "@notionhq/custom-blocks-protocol/pages/messages/createPage.js"
|
|
3
|
+
import type { UpdatePageResultMessage } from "@notionhq/custom-blocks-protocol/pages/messages/updatePage.js"
|
|
4
|
+
import * as v from "valibot"
|
|
5
|
+
|
|
6
|
+
const nativeIconMutationSchema = v.object({
|
|
7
|
+
type: v.picklist(["updatePage", "createPage"]),
|
|
8
|
+
requestId: v.string(),
|
|
9
|
+
icon: v.object({
|
|
10
|
+
type: v.literal("icon"),
|
|
11
|
+
icon: v.object({ color: v.unknown() }),
|
|
12
|
+
}),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
/** Reject malformed colors with a correlated result before invoking a page mutation handler. */
|
|
16
|
+
export function getInvalidNativeIconColorResponse(
|
|
17
|
+
data: unknown,
|
|
18
|
+
): UpdatePageResultMessage | CreatePageResultMessage | undefined {
|
|
19
|
+
const parsed = v.safeParse(nativeIconMutationSchema, data)
|
|
20
|
+
if (!parsed.success) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
const color = parsed.output.icon.icon.color
|
|
24
|
+
if (
|
|
25
|
+
color === undefined ||
|
|
26
|
+
v.safeParse(notionIconColorSchema, color).success
|
|
27
|
+
) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
type:
|
|
32
|
+
parsed.output.type === "createPage"
|
|
33
|
+
? "createPageResult"
|
|
34
|
+
: "updatePageResult",
|
|
35
|
+
requestId: parsed.output.requestId,
|
|
36
|
+
status: "error",
|
|
37
|
+
error: {
|
|
38
|
+
code: "invalid_icon_color",
|
|
39
|
+
message: "Use a supported Notion icon color.",
|
|
40
|
+
isRetryable: false,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/pages/types.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { createPageMessageSchema } from "@notionhq/custom-blocks-protocol/p
|
|
|
3
3
|
import type { getPageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/getPage.js"
|
|
4
4
|
import type { openPageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/openPage.js"
|
|
5
5
|
import type { updatePageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/updatePage.js"
|
|
6
|
+
import type { notionPageIconSchema } from "@notionhq/custom-blocks-protocol/pages/pageAppearance.js"
|
|
6
7
|
import type { InferInput } from "valibot"
|
|
7
8
|
import type { CustomBlockHostResult } from "../messages/result.js"
|
|
8
9
|
|
|
@@ -20,3 +21,5 @@ export type CustomBlockHostPageResult = CustomBlockHostResult<{
|
|
|
20
21
|
export type CustomBlockHostOpenPageResult = CustomBlockHostResult<{
|
|
21
22
|
pageId: string
|
|
22
23
|
}>
|
|
24
|
+
|
|
25
|
+
export type CustomBlockHostPageIcon = InferInput<typeof notionPageIconSchema>
|