@notionhq/custom-blocks-host 0.4.3 → 0.5.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.
Files changed (39) hide show
  1. package/README.md +4 -0
  2. package/dist/browser.js +1 -1
  3. package/dist/context/initialState.d.ts +5 -13
  4. package/dist/context/initialState.d.ts.map +1 -1
  5. package/dist/createCustomBlockHost.d.ts +20 -9
  6. package/dist/createCustomBlockHost.d.ts.map +1 -1
  7. package/dist/createCustomBlockHost.js +9 -4
  8. package/dist/dataSources/types.d.ts +7 -3
  9. package/dist/dataSources/types.d.ts.map +1 -1
  10. package/dist/index.d.ts +5 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/manifest/types.d.ts +3 -7
  13. package/dist/manifest/types.d.ts.map +1 -1
  14. package/dist/messages/handlers.d.ts +10 -9
  15. package/dist/messages/handlers.d.ts.map +1 -1
  16. package/dist/messages/result.d.ts +12 -0
  17. package/dist/messages/result.d.ts.map +1 -0
  18. package/dist/messages/result.js +1 -0
  19. package/dist/navigation/types.d.ts +1 -3
  20. package/dist/navigation/types.d.ts.map +1 -1
  21. package/dist/pages/types.d.ts +12 -14
  22. package/dist/pages/types.d.ts.map +1 -1
  23. package/dist/protocol/pages/makeBridgePage.d.ts +3 -1
  24. package/dist/protocol/users/makeBridgeUser.d.ts +3 -1
  25. package/dist/users/types.d.ts +11 -5
  26. package/dist/users/types.d.ts.map +1 -1
  27. package/docs/handlers.md +15 -7
  28. package/docs/lifecycle.md +14 -0
  29. package/package.json +1 -1
  30. package/src/context/initialState.ts +7 -16
  31. package/src/createCustomBlockHost.ts +38 -19
  32. package/src/dataSources/types.ts +8 -11
  33. package/src/index.ts +5 -6
  34. package/src/manifest/types.ts +4 -4
  35. package/src/messages/handlers.ts +11 -19
  36. package/src/messages/result.ts +11 -0
  37. package/src/navigation/types.ts +1 -11
  38. package/src/pages/types.ts +13 -46
  39. package/src/users/types.ts +12 -21
@@ -0,0 +1,12 @@
1
+ import type { CustomBlockErrorInfo } from "../protocol/utils/errors.js";
2
+ /**
3
+ * The outcome of a handler operation: success with its data, or failure with an error.
4
+ * The host turns the result into a response message.
5
+ */
6
+ export type CustomBlockHostResult<Payload extends object = Record<never, never>> = ({
7
+ status: "success";
8
+ } & Payload) | {
9
+ status: "error";
10
+ error: CustomBlockErrorInfo;
11
+ };
12
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/messages/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAA;AAE5F;;;GAGG;AACH,MAAM,MAAM,qBAAqB,CAChC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAE3C,CAAC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG,OAAO,CAAC,GACjC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,5 @@
1
- import type { BridgeMessagePayload } from "../protocol/messages/messagePayload.js";
2
- import type { CustomBlockOpenExternalUrlErrorInfo, OpenExternalUrlResultMessage, openExternalUrlMessageSchema } from "../protocol/navigation/openExternalUrl.js";
1
+ import type { openExternalUrlMessageSchema } from "../protocol/navigation/openExternalUrl.js";
3
2
  import type { InferInput } from "valibot";
4
- export type CustomBlockHostOpenExternalUrlResult = BridgeMessagePayload<OpenExternalUrlResultMessage, CustomBlockOpenExternalUrlErrorInfo>;
5
3
  export type CustomBlockHostNavigationContext = {
6
4
  signal: AbortSignal;
7
5
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/navigation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AACvG,OAAO,KAAK,EACX,mCAAmC,EACnC,4BAA4B,EAC5B,4BAA4B,EAC5B,MAAM,gEAAgE,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,MAAM,MAAM,oCAAoC,GAAG,oBAAoB,CACtE,4BAA4B,EAC5B,mCAAmC,CACnC,CAAA;AAED,MAAM,MAAM,gCAAgC,GAAG;IAC9C,MAAM,EAAE,WAAW,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,UAAU,CACnD,OAAO,4BAA4B,CACnC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/navigation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gEAAgE,CAAA;AAClH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,MAAM,MAAM,gCAAgC,GAAG;IAC9C,MAAM,EAAE,WAAW,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,UAAU,CACnD,OAAO,4BAA4B,CACnC,CAAA"}
@@ -1,20 +1,18 @@
1
- import type { BridgeMessagePayload } from "../protocol/messages/messagePayload.js";
2
- import type { CustomBlockCreatePageErrorInfo, createPageMessageSchema, createPageResultMessageSchema } from "../protocol/pages/messages/createPage.js";
3
- import type { CustomBlockGetPageErrorInfo, getPageMessageSchema, getPageResultMessageSchema } from "../protocol/pages/messages/getPage.js";
4
- import type { CustomBlockOpenPageErrorInfo, openPageMessageSchema, openPageResultMessageSchema } from "../protocol/pages/messages/openPage.js";
5
- import type { CustomBlockUpdatePageErrorInfo, updatePageMessageSchema, updatePageResultMessageSchema } from "../protocol/pages/messages/updatePage.js";
1
+ import type { BridgePage } from "../protocol/pages/bridgePage.js";
2
+ import type { createPageMessageSchema } from "../protocol/pages/messages/createPage.js";
3
+ import type { getPageMessageSchema } from "../protocol/pages/messages/getPage.js";
4
+ import type { openPageMessageSchema } from "../protocol/pages/messages/openPage.js";
5
+ import type { updatePageMessageSchema } from "../protocol/pages/messages/updatePage.js";
6
6
  import type { InferInput } from "valibot";
7
- /**
8
- * Host results use InferInput so adapters can return plain string IDs.
9
- * The runtime validates results before sending them and assigns protocol ID brands.
10
- * Handler requests use parsed protocol types, whose IDs are already branded.
11
- */
12
- export type CustomBlockHostCreatePageResult = BridgeMessagePayload<InferInput<typeof createPageResultMessageSchema>, CustomBlockCreatePageErrorInfo>;
13
- export type CustomBlockHostGetPageResult = BridgeMessagePayload<InferInput<typeof getPageResultMessageSchema>, CustomBlockGetPageErrorInfo>;
14
- export type CustomBlockHostUpdatePageResult = BridgeMessagePayload<InferInput<typeof updatePageResultMessageSchema>, CustomBlockUpdatePageErrorInfo>;
15
- export type CustomBlockHostOpenPageResult = BridgeMessagePayload<InferInput<typeof openPageResultMessageSchema>, CustomBlockOpenPageErrorInfo>;
7
+ import type { CustomBlockHostResult } from "../messages/result.js";
16
8
  export type CreatePageMessageInput = InferInput<typeof createPageMessageSchema>;
17
9
  export type GetPageMessageInput = InferInput<typeof getPageMessageSchema>;
18
10
  export type OpenPageMessageInput = InferInput<typeof openPageMessageSchema>;
19
11
  export type UpdatePageMessageInput = InferInput<typeof updatePageMessageSchema>;
12
+ export type CustomBlockHostPageResult = CustomBlockHostResult<{
13
+ page: BridgePage;
14
+ }>;
15
+ export type CustomBlockHostOpenPageResult = CustomBlockHostResult<{
16
+ pageId: string;
17
+ }>;
20
18
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AACvG,OAAO,KAAK,EACX,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,MAAM,+DAA+D,CAAA;AACtE,OAAO,KAAK,EACX,2BAA2B,EAC3B,oBAAoB,EACpB,0BAA0B,EAC1B,MAAM,4DAA4D,CAAA;AACnE,OAAO,KAAK,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,2BAA2B,EAC3B,MAAM,6DAA6D,CAAA;AACpE,OAAO,KAAK,EACX,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,MAAM,+DAA+D,CAAA;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC;;;;GAIG;AACH,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CACjE,UAAU,CAAC,OAAO,6BAA6B,CAAC,EAChD,8BAA8B,CAC9B,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,CAC9D,UAAU,CAAC,OAAO,0BAA0B,CAAC,EAC7C,2BAA2B,CAC3B,CAAA;AAED,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CACjE,UAAU,CAAC,OAAO,6BAA6B,CAAC,EAChD,8BAA8B,CAC9B,CAAA;AAED,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAC/D,UAAU,CAAC,OAAO,2BAA2B,CAAC,EAC9C,4BAA4B,CAC5B,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAE/E,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEzE,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAE3E,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sDAAsD,CAAA;AACtF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+DAA+D,CAAA;AAC5G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AACtG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6DAA6D,CAAA;AACxG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+DAA+D,CAAA;AAC5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAElE,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAE/E,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEzE,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAE3E,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAE/E,MAAM,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;IAC7D,IAAI,EAAE,UAAU,CAAA;CAChB,CAAC,CAAA;AACF,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;IACjE,MAAM,EAAE,MAAM,CAAA;CACd,CAAC,CAAA"}
@@ -1,4 +1,6 @@
1
+ import * as v from "valibot";
1
2
  import type { BridgePage } from "./bridgePage.js";
2
- export type MakeBridgePageArgs = Pick<BridgePage, "id" | "parent"> & Partial<Omit<BridgePage, "object" | "id" | "parent">>;
3
+ import { bridgePageSchema } from "./bridgePage.js";
4
+ export type MakeBridgePageArgs = Pick<v.InferInput<typeof bridgePageSchema>, "id" | "parent"> & Partial<Omit<v.InferInput<typeof bridgePageSchema>, "object" | "id" | "parent">>;
3
5
  /** Builds a complete bridge page without inventing identity or Notion data. */
4
6
  export declare function makeBridgePage(args: MakeBridgePageArgs): BridgePage;
@@ -1,4 +1,6 @@
1
+ import * as v from "valibot";
1
2
  import type { BridgeUser } from "./bridgeUser.js";
2
- export type MakeBridgeUserArgs = Pick<BridgeUser, "id" | "person"> & Partial<Omit<BridgeUser, "object" | "type" | "id" | "person">>;
3
+ import { bridgeUserSchema } from "./bridgeUser.js";
4
+ export type MakeBridgeUserArgs = Pick<v.InferInput<typeof bridgeUserSchema>, "id" | "person"> & Partial<Omit<v.InferInput<typeof bridgeUserSchema>, "object" | "type" | "id" | "person">>;
3
5
  /** Builds the shared person-user payload; callers supply identity and profile data. */
4
6
  export declare function makeBridgeUser(args: MakeBridgeUserArgs): BridgeUser;
@@ -1,9 +1,15 @@
1
- import type { BridgeMessagePayload } from "../protocol/messages/messagePayload.js";
2
- import type { CustomBlockGetUserErrorInfo, getUserMessageSchema, getUserResultMessageSchema } from "../protocol/users/messages/getUser.js";
3
- import type { CustomBlockListUsersErrorInfo, listUsersMessageSchema, listUsersResultMessageSchema } from "../protocol/users/messages/listUsers.js";
1
+ import type { BridgeUser } from "../protocol/users/bridgeUser.js";
2
+ import type { BridgeUserList } from "../protocol/users/bridgeUserList.js";
3
+ import type { getUserMessageSchema } from "../protocol/users/messages/getUser.js";
4
+ import type { listUsersMessageSchema } from "../protocol/users/messages/listUsers.js";
4
5
  import type { InferInput } from "valibot";
5
- export type CustomBlockHostGetUserResult = BridgeMessagePayload<InferInput<typeof getUserResultMessageSchema>, CustomBlockGetUserErrorInfo>;
6
- export type CustomBlockHostListUsersResult = BridgeMessagePayload<InferInput<typeof listUsersResultMessageSchema>, CustomBlockListUsersErrorInfo>;
6
+ import type { CustomBlockHostResult } from "../messages/result.js";
7
7
  export type GetUserMessageInput = InferInput<typeof getUserMessageSchema>;
8
8
  export type ListUsersMessageInput = InferInput<typeof listUsersMessageSchema>;
9
+ export type CustomBlockHostUserResult = CustomBlockHostResult<{
10
+ user: BridgeUser;
11
+ }>;
12
+ export type CustomBlockHostUserListResult = CustomBlockHostResult<{
13
+ list: BridgeUserList;
14
+ }>;
9
15
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/users/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AACvG,OAAO,KAAK,EACX,2BAA2B,EAC3B,oBAAoB,EACpB,0BAA0B,EAC1B,MAAM,4DAA4D,CAAA;AACnE,OAAO,KAAK,EACX,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,EAC5B,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,CAC9D,UAAU,CAAC,OAAO,0BAA0B,CAAC,EAC7C,2BAA2B,CAC3B,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,oBAAoB,CAChE,UAAU,CAAC,OAAO,4BAA4B,CAAC,EAC/C,6BAA6B,CAC7B,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEzE,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/users/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sDAAsD,CAAA;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAA;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4DAA4D,CAAA;AACtG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAA;AAC1G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAElE,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEzE,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAE7E,MAAM,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;IAC7D,IAAI,EAAE,UAAU,CAAA;CAChB,CAAC,CAAA;AACF,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;IACjE,IAAI,EAAE,cAAc,CAAA;CACpB,CAAC,CAAA"}
package/docs/handlers.md CHANGED
@@ -15,9 +15,14 @@ hosts must provide their own permissions, data access, and persistence.
15
15
  sends no response to that request. A handler returns a result synchronously or as a promise. Errors
16
16
  carry `{ code, message, isRetryable }`, with open string codes.
17
17
 
18
- Handler requests are validated messages with branded IDs. Initial state, setters, handler results,
19
- and `*MessageInput` types accept plain string IDs. The runtime validates these inputs and applies
20
- schema defaults. ID brands do not check record existence or access.
18
+ ### Return bridge data
19
+
20
+ Handlers return data in the bridge's shared types. Use bridge builders to construct complete objects
21
+ from application records.
22
+
23
+ The host validates result shapes, matches responses to requests, and converts responses for the
24
+ block's protocol version. Your application checks that records exist and that the viewer may perform
25
+ the requested operation.
21
26
 
22
27
  Query filters and sorts are validated against the actual bound database schema before
23
28
  `queryDataSource` runs. See the [wire reference](bridge/protocol.md#data-sources) for
@@ -42,7 +47,11 @@ import type {
42
47
  CustomBlockHostDataSourcesPayload,
43
48
  CustomBlockHostHandlers,
44
49
  } from "@notionhq/custom-blocks-host"
45
- import type { BridgeCustomBlockManifest, BridgePage } from "@notionhq/custom-blocks-host/protocol"
50
+ import {
51
+ makeBridgePage,
52
+ type BridgeCustomBlockManifest,
53
+ type BridgePage,
54
+ } from "@notionhq/custom-blocks-host/protocol"
46
55
 
47
56
  const tasksId = "44444444-4444-4444-8444-444444444444"
48
57
 
@@ -110,8 +119,7 @@ const handlers: CustomBlockHostHandlers = {
110
119
  }
111
120
 
112
121
  const items: BridgePage[] = [
113
- {
114
- object: "page",
122
+ makeBridgePage({
115
123
  id: "55555555-5555-4555-8555-555555555555",
116
124
  parent: { type: "data_source_id", data_source_id: tasksId },
117
125
  is_archived: false,
@@ -119,7 +127,7 @@ const handlers: CustomBlockHostHandlers = {
119
127
  properties: {
120
128
  Estimate: { id: "estimate-id", type: "number", number: estimate },
121
129
  },
122
- },
130
+ }),
123
131
  ]
124
132
 
125
133
  return {
package/docs/lifecycle.md CHANGED
@@ -60,6 +60,20 @@ late results. Manifest and state preparation providers must respect their `signa
60
60
  `setCurrentUser()` hold updates during initialization and send them after `initResult.success`. For
61
61
  data-source query refreshes, see [Handlers and data](handlers.md#refresh-active-queries).
62
62
 
63
+ `setDataSources()` returns a synchronous `CustomBlockHostSetDataSourcesResult`. Success means local
64
+ acceptance only; it does not guarantee sandbox delivery or successful initialization. Existing
65
+ callers can ignore the return value. Malformed bindings can throw during schema parsing.
66
+
67
+ - `{ status: "success" }`: accepts the bindings into local state.
68
+ - `{ status: "error", error: { code, message, isRetryable } }`: logs a warning, keeps the last
69
+ accepted bindings and pending update, and sends no update. Codes are
70
+ `missing_data_source_binding`, `missing_property_binding`, and `invalid_property_binding`. All
71
+ have `isRetryable: false`; correct the bindings before resubmitting.
72
+
73
+ Pre-connect updates are checked against the selected manifest during initialization. Later updates
74
+ are validated once that manifest is available. Accepted updates wait for `initResult.success` before
75
+ sending; after failed initialization, they only change local state and do not restart it.
76
+
63
77
  ## Callbacks
64
78
 
65
79
  The required `onStatusChange(state)` callback receives the `CustomBlockHostStatus` union:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/custom-blocks-host",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "Reusable host runtime for Notion custom blocks.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -3,13 +3,13 @@ import { notionContrastModeSchema } from "@notionhq/custom-blocks-protocol/conte
3
3
  import { notionParentSchema } from "@notionhq/custom-blocks-protocol/context/parent.js"
4
4
  import { notionThemeSchema } from "@notionhq/custom-blocks-protocol/context/theme.js"
5
5
  import { bridgeDataSourceBindingsSchema } from "@notionhq/custom-blocks-protocol/dataSources/bridgeDataSourceBindings.js"
6
- import type { CustomBlockInitErrorInfo } from "@notionhq/custom-blocks-protocol/handshake/init.js"
7
6
  import { customBlockInitErrorInfoSchema } from "@notionhq/custom-blocks-protocol/handshake/init.js"
8
7
  import type { BridgeCustomBlockManifest } from "@notionhq/custom-blocks-protocol/manifest/manifest.js"
9
8
  import { manifestSchema } from "@notionhq/custom-blocks-protocol/manifest/manifest.js"
10
9
  import { bridgeUserSchema } from "@notionhq/custom-blocks-protocol/users/bridgeUser.js"
11
10
  import { notionBlockIdSchema } from "@notionhq/custom-blocks-protocol/utils/ids.js"
12
11
  import * as v from "valibot"
12
+ import type { CustomBlockHostResult } from "../messages/result.js"
13
13
 
14
14
  export const customBlockHostInitialStateSchema = v.object({
15
15
  theme: notionThemeSchema,
@@ -30,15 +30,9 @@ export type CustomBlockHostInitialState = v.InferInput<
30
30
  typeof customBlockHostInitialStateSchema
31
31
  >
32
32
 
33
- export type CustomBlockHostInitialStateResult =
34
- | {
35
- status: "success"
36
- initialState: CustomBlockHostInitialState
37
- }
38
- | {
39
- status: "error"
40
- error: CustomBlockInitErrorInfo
41
- }
33
+ export type CustomBlockHostInitialStateResult = CustomBlockHostResult<{
34
+ initialState: CustomBlockHostInitialState
35
+ }>
42
36
 
43
37
  export const customBlockHostPreparedStateResultSchema = v.variant("status", [
44
38
  v.object({
@@ -52,12 +46,9 @@ export const customBlockHostPreparedStateResultSchema = v.variant("status", [
52
46
  ])
53
47
 
54
48
  /** Adapter-owned state or an explicit preparation error. The host adds the manifest to init. */
55
- export type CustomBlockHostPreparedStateResult =
56
- | {
57
- status: "success"
58
- initialState: Omit<CustomBlockHostInitialState, "manifest">
59
- }
60
- | { status: "error"; error: CustomBlockInitErrorInfo }
49
+ export type CustomBlockHostPreparedStateResult = CustomBlockHostResult<{
50
+ initialState: Omit<CustomBlockHostInitialState, "manifest">
51
+ }>
61
52
 
62
53
  export type CustomBlockHostPrepareInitialState = (args: {
63
54
  manifest: BridgeCustomBlockManifest
@@ -1,7 +1,7 @@
1
1
  import type { customBlockPageSchema } from "@notionhq/custom-blocks-protocol/context/containingPage.js"
2
- import type { notionContrastModeSchema } from "@notionhq/custom-blocks-protocol/context/contrast.js"
2
+ import type { NotionContrastMode } from "@notionhq/custom-blocks-protocol/context/contrast.js"
3
3
  import type { notionParentSchema } from "@notionhq/custom-blocks-protocol/context/parent.js"
4
- import type { notionThemeSchema } from "@notionhq/custom-blocks-protocol/context/theme.js"
4
+ import type { NotionTheme } from "@notionhq/custom-blocks-protocol/context/theme.js"
5
5
  import { bridgeDataSourceBindingsSchema } from "@notionhq/custom-blocks-protocol/dataSources/bridgeDataSourceBindings.js"
6
6
  import type { NotionCollectionSchema } from "@notionhq/custom-blocks-protocol/dataSources/collectionSchema.js"
7
7
  import type {
@@ -24,7 +24,8 @@ import type {
24
24
  OpenExternalUrlMessage,
25
25
  OpenExternalUrlResultMessage,
26
26
  } from "@notionhq/custom-blocks-protocol/navigation/openExternalUrl.js"
27
- import type { bridgeUserSchema } from "@notionhq/custom-blocks-protocol/users/bridgeUser.js"
27
+ import type { BridgeUser } from "@notionhq/custom-blocks-protocol/users/bridgeUser.js"
28
+ import type { CustomBlockErrorInfo } from "@notionhq/custom-blocks-protocol/utils/errors.js"
28
29
  import type { NotionDataSourceId } from "@notionhq/custom-blocks-protocol/utils/ids.js"
29
30
  import { notionDataSourceIdSchema } from "@notionhq/custom-blocks-protocol/utils/ids.js"
30
31
  import { LATEST_BRIDGE_PROTOCOL_VERSION } from "@notionhq/custom-blocks-protocol/utils/protocolVersion.js"
@@ -112,19 +113,33 @@ export type CustomBlockHostOptions = {
112
113
  initialStateTimeoutMs?: number
113
114
  }
114
115
 
116
+ /** Reports local acceptance, not sandbox delivery or initialization success. */
117
+ export type CustomBlockHostSetDataSourcesResult =
118
+ | { status: "success" }
119
+ | {
120
+ status: "error"
121
+ error: CustomBlockErrorInfo<
122
+ | "missing_data_source_binding"
123
+ | "missing_property_binding"
124
+ | "invalid_property_binding"
125
+ >
126
+ }
127
+
115
128
  export type CustomBlockHostHandle = {
116
129
  stop: () => void
117
- setTheme: (theme: InferInput<typeof notionThemeSchema>) => void
118
- setContrastMode: (
119
- contrastMode: InferInput<typeof notionContrastModeSchema>,
120
- ) => void
130
+ setTheme: (theme: NotionTheme) => void
131
+ setContrastMode: (contrastMode: NotionContrastMode) => void
121
132
  setParent: (parent: InferInput<typeof notionParentSchema>) => void
122
133
  setPage: (page: InferInput<typeof customBlockPageSchema>) => void
123
- setDataSources: (dataSources: CustomBlockHostDataSourcesPayload) => void
124
- setCurrentUser: (currentUser: InferInput<typeof bridgeUserSchema>) => void
125
- refreshQuery: (args: {
126
- dataSourceId: InferInput<typeof notionDataSourceIdSchema>
127
- }) => void
134
+ /**
135
+ * Reports synchronous local acceptance, not sandbox delivery or initialization success.
136
+ * Malformed bindings can throw during schema parsing.
137
+ */
138
+ setDataSources: (
139
+ dataSources: CustomBlockHostDataSourcesPayload,
140
+ ) => CustomBlockHostSetDataSourcesResult
141
+ setCurrentUser: (currentUser: BridgeUser) => void
142
+ refreshQuery: (args: { dataSourceId: string }) => void
128
143
  }
129
144
 
130
145
  /**
@@ -672,19 +687,23 @@ export function createCustomBlockHost(
672
687
  dataSources.bindings,
673
688
  ),
674
689
  }
675
- if (
676
- initializationController.hasConnectedSandbox &&
677
- manifest !== undefined &&
678
- getBindingError(manifest, normalizedDataSources) !== undefined
679
- ) {
690
+ const bindingError =
691
+ initializationController.hasConnectedSandbox && manifest !== undefined
692
+ ? getBindingError(manifest, normalizedDataSources)
693
+ : undefined
694
+ if (bindingError !== undefined) {
680
695
  emit("warn", {
681
696
  message: "Ignored invalid data source bindings update",
682
697
  payload: normalizedDataSources,
683
698
  })
684
- return
699
+ return {
700
+ status: "error",
701
+ error: bindingError,
702
+ }
685
703
  }
686
704
  activeDataSources = normalizedDataSources
687
705
  updateHostState({ dataSources: normalizedDataSources })
706
+ return { status: "success" }
688
707
  },
689
708
  refreshQuery({ dataSourceId }) {
690
709
  if (initializationController.status !== "initialized") {
@@ -743,7 +762,7 @@ function getCollectionSchema(
743
762
  function getBindingError(
744
763
  manifest: BridgeCustomBlockManifest,
745
764
  dataSources: CustomBlockHostDataSourcesPayload,
746
- ): CustomBlockInitErrorInfo | undefined {
765
+ ) {
747
766
  for (const [dataSourceKey, manifestDataSource] of Object.entries(
748
767
  manifest.dataSources,
749
768
  )) {
@@ -1,22 +1,14 @@
1
1
  import type { bridgeDataSourceBindingsSchema } from "@notionhq/custom-blocks-protocol/dataSources/bridgeDataSourceBindings.js"
2
- import type {
3
- CustomBlockQueryDataSourceErrorInfo,
4
- queryDataSourceMessageSchema,
5
- queryDataSourceResultMessageSchema,
6
- } from "@notionhq/custom-blocks-protocol/dataSources/messages/queryDataSource.js"
7
- import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
2
+ import type { queryDataSourceMessageSchema } from "@notionhq/custom-blocks-protocol/dataSources/messages/queryDataSource.js"
3
+ import type { BridgePage } from "@notionhq/custom-blocks-protocol/pages/bridgePage.js"
8
4
  import type * as v from "valibot"
9
5
  import type { InferInput } from "valibot"
6
+ import type { CustomBlockHostResult } from "../messages/result.js"
10
7
 
11
8
  export type QueryDataSourceMessageInput = InferInput<
12
9
  typeof queryDataSourceMessageSchema
13
10
  >
14
11
 
15
- export type CustomBlockHostQueryDataSourceResult = BridgeMessagePayload<
16
- InferInput<typeof queryDataSourceResultMessageSchema>,
17
- CustomBlockQueryDataSourceErrorInfo
18
- >
19
-
20
12
  export type CustomBlockHostDataSourcesPayload = {
21
13
  bindings: v.InferInput<typeof bridgeDataSourceBindingsSchema>
22
14
  }
@@ -24,3 +16,8 @@ export type CustomBlockHostDataSourcesPayload = {
24
16
  export type CustomBlockHostNormalizedDataSourcesPayload = {
25
17
  bindings: v.InferOutput<typeof bridgeDataSourceBindingsSchema>
26
18
  }
19
+
20
+ export type CustomBlockHostQueryDataSourceResult = CustomBlockHostResult<{
21
+ items: BridgePage[]
22
+ hasMore: boolean
23
+ }>
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export type { ResizeMessageInput } from "./context/resize.js"
8
8
  export {
9
9
  type CustomBlockHostHandle,
10
10
  type CustomBlockHostOptions,
11
+ type CustomBlockHostSetDataSourcesResult,
11
12
  createCustomBlockHost,
12
13
  } from "./createCustomBlockHost.js"
13
14
  export {
@@ -35,24 +36,22 @@ export type {
35
36
  } from "./manifest/types.js"
36
37
  export type { CustomBlockHostHandlers } from "./messages/handlers.js"
37
38
  export type { CustomBlockHostLogDirection } from "./messages/logging.js"
39
+ export type { CustomBlockHostResult } from "./messages/result.js"
38
40
  export type {
39
41
  CustomBlockHostNavigationContext,
40
- CustomBlockHostOpenExternalUrlResult,
41
42
  OpenExternalUrlMessageInput,
42
43
  } from "./navigation/types.js"
43
44
  export type {
44
45
  CreatePageMessageInput,
45
- CustomBlockHostCreatePageResult,
46
- CustomBlockHostGetPageResult,
47
46
  CustomBlockHostOpenPageResult,
48
- CustomBlockHostUpdatePageResult,
47
+ CustomBlockHostPageResult,
49
48
  GetPageMessageInput,
50
49
  OpenPageMessageInput,
51
50
  UpdatePageMessageInput,
52
51
  } from "./pages/types.js"
53
52
  export type {
54
- CustomBlockHostGetUserResult,
55
- CustomBlockHostListUsersResult,
53
+ CustomBlockHostUserListResult,
54
+ CustomBlockHostUserResult,
56
55
  GetUserMessageInput,
57
56
  ListUsersMessageInput,
58
57
  } from "./users/types.js"
@@ -1,7 +1,7 @@
1
- import type { CustomBlockInitErrorInfo } from "@notionhq/custom-blocks-protocol/handshake/init.js"
2
1
  import { customBlockInitErrorInfoSchema } from "@notionhq/custom-blocks-protocol/handshake/init.js"
3
2
  import { manifestSchema } from "@notionhq/custom-blocks-protocol/manifest/manifest.js"
4
3
  import * as v from "valibot"
4
+ import type { CustomBlockHostResult } from "../messages/result.js"
5
5
 
6
6
  /** Selects the manifest used to initialize a custom block. Both sources load independently. */
7
7
  export type CustomBlockManifestSource =
@@ -19,9 +19,9 @@ export const customBlockHostManifestResultSchema = v.variant("status", [
19
19
  ])
20
20
 
21
21
  /** A persisted manifest or an explicit loading error. The host validates and normalizes it. */
22
- export type CustomBlockHostManifestResult =
23
- | { status: "success"; manifest: v.InferInput<typeof manifestSchema> }
24
- | { status: "error"; error: CustomBlockInitErrorInfo }
22
+ export type CustomBlockHostManifestResult = CustomBlockHostResult<{
23
+ manifest: v.InferInput<typeof manifestSchema>
24
+ }>
25
25
 
26
26
  export type CustomBlockHostNormalizedManifestResult = v.InferOutput<
27
27
  typeof customBlockHostManifestResultSchema
@@ -8,21 +8,17 @@ import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/pages/m
8
8
  import type { GetUserMessage } from "@notionhq/custom-blocks-protocol/users/messages/getUser.js"
9
9
  import type { ListUsersMessage } from "@notionhq/custom-blocks-protocol/users/messages/listUsers.js"
10
10
  import type { CustomBlockHostQueryDataSourceResult } from "../dataSources/types.js"
11
+ import type { CustomBlockHostNavigationContext } from "../navigation/types.js"
11
12
  import type {
12
- CustomBlockHostNavigationContext,
13
- CustomBlockHostOpenExternalUrlResult,
14
- } from "../navigation/types.js"
15
- import type {
16
- CustomBlockHostCreatePageResult,
17
- CustomBlockHostGetPageResult,
18
13
  CustomBlockHostOpenPageResult,
19
- CustomBlockHostUpdatePageResult,
14
+ CustomBlockHostPageResult,
20
15
  } from "../pages/types.js"
21
16
  import type {
22
- CustomBlockHostGetUserResult,
23
- CustomBlockHostListUsersResult,
17
+ CustomBlockHostUserListResult,
18
+ CustomBlockHostUserResult,
24
19
  } from "../users/types.js"
25
20
  import type { MaybePromise } from "../utils/maybePromise.js"
21
+ import type { CustomBlockHostResult } from "./result.js"
26
22
 
27
23
  export type CustomBlockHostHandlers = {
28
24
  queryDataSource: (
@@ -30,25 +26,21 @@ export type CustomBlockHostHandlers = {
30
26
  ) => MaybePromise<CustomBlockHostQueryDataSourceResult>
31
27
  createPage?: (
32
28
  message: CreatePageMessage,
33
- ) => MaybePromise<CustomBlockHostCreatePageResult>
34
- getPage?: (
35
- message: GetPageMessage,
36
- ) => MaybePromise<CustomBlockHostGetPageResult>
37
- getUser?: (
38
- message: GetUserMessage,
39
- ) => MaybePromise<CustomBlockHostGetUserResult>
29
+ ) => MaybePromise<CustomBlockHostPageResult>
30
+ getPage?: (message: GetPageMessage) => MaybePromise<CustomBlockHostPageResult>
31
+ getUser?: (message: GetUserMessage) => MaybePromise<CustomBlockHostUserResult>
40
32
  listUsers?: (
41
33
  message: ListUsersMessage,
42
- ) => MaybePromise<CustomBlockHostListUsersResult>
34
+ ) => MaybePromise<CustomBlockHostUserListResult>
43
35
  openPage?: (
44
36
  message: OpenPageMessage,
45
37
  ) => MaybePromise<CustomBlockHostOpenPageResult>
46
38
  openExternalUrl?: (
47
39
  message: OpenExternalUrlMessage,
48
40
  context: CustomBlockHostNavigationContext,
49
- ) => MaybePromise<CustomBlockHostOpenExternalUrlResult>
41
+ ) => MaybePromise<CustomBlockHostResult>
50
42
  updatePage?: (
51
43
  message: UpdatePageMessage,
52
- ) => MaybePromise<CustomBlockHostUpdatePageResult>
44
+ ) => MaybePromise<CustomBlockHostPageResult>
53
45
  resize?: (message: ResizeMessage) => void
54
46
  }
@@ -0,0 +1,11 @@
1
+ import type { CustomBlockErrorInfo } from "@notionhq/custom-blocks-protocol/utils/errors.js"
2
+
3
+ /**
4
+ * The outcome of a handler operation: success with its data, or failure with an error.
5
+ * The host turns the result into a response message.
6
+ */
7
+ export type CustomBlockHostResult<
8
+ Payload extends object = Record<never, never>,
9
+ > =
10
+ | ({ status: "success" } & Payload)
11
+ | { status: "error"; error: CustomBlockErrorInfo }
@@ -1,16 +1,6 @@
1
- import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
2
- import type {
3
- CustomBlockOpenExternalUrlErrorInfo,
4
- OpenExternalUrlResultMessage,
5
- openExternalUrlMessageSchema,
6
- } from "@notionhq/custom-blocks-protocol/navigation/openExternalUrl.js"
1
+ import type { openExternalUrlMessageSchema } from "@notionhq/custom-blocks-protocol/navigation/openExternalUrl.js"
7
2
  import type { InferInput } from "valibot"
8
3
 
9
- export type CustomBlockHostOpenExternalUrlResult = BridgeMessagePayload<
10
- OpenExternalUrlResultMessage,
11
- CustomBlockOpenExternalUrlErrorInfo
12
- >
13
-
14
4
  export type CustomBlockHostNavigationContext = {
15
5
  signal: AbortSignal
16
6
  }
@@ -1,50 +1,10 @@
1
- import type { BridgeMessagePayload } from "@notionhq/custom-blocks-protocol/messages/messagePayload.js"
2
- import type {
3
- CustomBlockCreatePageErrorInfo,
4
- createPageMessageSchema,
5
- createPageResultMessageSchema,
6
- } from "@notionhq/custom-blocks-protocol/pages/messages/createPage.js"
7
- import type {
8
- CustomBlockGetPageErrorInfo,
9
- getPageMessageSchema,
10
- getPageResultMessageSchema,
11
- } from "@notionhq/custom-blocks-protocol/pages/messages/getPage.js"
12
- import type {
13
- CustomBlockOpenPageErrorInfo,
14
- openPageMessageSchema,
15
- openPageResultMessageSchema,
16
- } from "@notionhq/custom-blocks-protocol/pages/messages/openPage.js"
17
- import type {
18
- CustomBlockUpdatePageErrorInfo,
19
- updatePageMessageSchema,
20
- updatePageResultMessageSchema,
21
- } from "@notionhq/custom-blocks-protocol/pages/messages/updatePage.js"
1
+ import type { BridgePage } from "@notionhq/custom-blocks-protocol/pages/bridgePage.js"
2
+ import type { createPageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/createPage.js"
3
+ import type { getPageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/getPage.js"
4
+ import type { openPageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/openPage.js"
5
+ import type { updatePageMessageSchema } from "@notionhq/custom-blocks-protocol/pages/messages/updatePage.js"
22
6
  import type { InferInput } from "valibot"
23
-
24
- /**
25
- * Host results use InferInput so adapters can return plain string IDs.
26
- * The runtime validates results before sending them and assigns protocol ID brands.
27
- * Handler requests use parsed protocol types, whose IDs are already branded.
28
- */
29
- export type CustomBlockHostCreatePageResult = BridgeMessagePayload<
30
- InferInput<typeof createPageResultMessageSchema>,
31
- CustomBlockCreatePageErrorInfo
32
- >
33
-
34
- export type CustomBlockHostGetPageResult = BridgeMessagePayload<
35
- InferInput<typeof getPageResultMessageSchema>,
36
- CustomBlockGetPageErrorInfo
37
- >
38
-
39
- export type CustomBlockHostUpdatePageResult = BridgeMessagePayload<
40
- InferInput<typeof updatePageResultMessageSchema>,
41
- CustomBlockUpdatePageErrorInfo
42
- >
43
-
44
- export type CustomBlockHostOpenPageResult = BridgeMessagePayload<
45
- InferInput<typeof openPageResultMessageSchema>,
46
- CustomBlockOpenPageErrorInfo
47
- >
7
+ import type { CustomBlockHostResult } from "../messages/result.js"
48
8
 
49
9
  export type CreatePageMessageInput = InferInput<typeof createPageMessageSchema>
50
10
 
@@ -53,3 +13,10 @@ export type GetPageMessageInput = InferInput<typeof getPageMessageSchema>
53
13
  export type OpenPageMessageInput = InferInput<typeof openPageMessageSchema>
54
14
 
55
15
  export type UpdatePageMessageInput = InferInput<typeof updatePageMessageSchema>
16
+
17
+ export type CustomBlockHostPageResult = CustomBlockHostResult<{
18
+ page: BridgePage
19
+ }>
20
+ export type CustomBlockHostOpenPageResult = CustomBlockHostResult<{
21
+ pageId: string
22
+ }>