@notionhq/custom-blocks-host 0.3.8 → 0.4.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/LICENSE +21 -0
- package/README.md +143 -225
- package/THIRD_PARTY_LICENSES.md +9 -0
- package/dist/autoBindProperties.d.ts +5 -2
- package/dist/autoBindProperties.d.ts.map +1 -1
- package/dist/autoBindProperties.js +5 -2
- package/dist/browser.js +1 -1
- package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.d.ts +1215 -0
- package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.d.ts.map +1 -0
- package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.js +27 -0
- package/dist/compatibility/normalizeHostToSandboxMessage.d.ts +8 -0
- package/dist/compatibility/normalizeHostToSandboxMessage.d.ts.map +1 -0
- package/dist/compatibility/normalizeHostToSandboxMessage.js +39 -0
- package/dist/compatibility/normalizePageResultsForProtocol3To5.d.ts +11 -0
- package/dist/compatibility/normalizePageResultsForProtocol3To5.d.ts.map +1 -0
- package/dist/compatibility/normalizePageResultsForProtocol3To5.js +18 -0
- package/dist/compatibility/normalizePageResultsForProtocol6.d.ts +9 -0
- package/dist/compatibility/normalizePageResultsForProtocol6.d.ts.map +1 -0
- package/dist/compatibility/normalizePageResultsForProtocol6.js +18 -0
- package/dist/compatibility/normalizeSandboxToHostMessage.d.ts +1091 -0
- package/dist/compatibility/normalizeSandboxToHostMessage.d.ts.map +1 -0
- package/dist/compatibility/normalizeSandboxToHostMessage.js +9 -0
- package/dist/compatibility/pageForProtocol3To5.d.ts +159 -0
- package/dist/compatibility/pageForProtocol3To5.d.ts.map +1 -0
- package/dist/{lifecycle/legacyPage.js → compatibility/pageForProtocol3To5.js} +50 -9
- package/dist/compatibility/pageResult.d.ts +11 -0
- package/dist/compatibility/pageResult.d.ts.map +1 -0
- package/dist/compatibility/pageWithNullTextFallbackProperties.d.ts +9 -0
- package/dist/compatibility/pageWithNullTextFallbackProperties.d.ts.map +1 -0
- package/dist/compatibility/pageWithNullTextFallbackProperties.js +46 -0
- package/dist/createCustomBlockHost.d.ts +18 -19
- package/dist/createCustomBlockHost.d.ts.map +1 -1
- package/dist/createCustomBlockHost.js +103 -38
- package/dist/index.d.ts +2 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/{localBlockUrl.d.ts → isAllowedLocalPreviewUrl.d.ts} +2 -2
- package/dist/isAllowedLocalPreviewUrl.d.ts.map +1 -0
- package/dist/{localBlockUrl.js → isAllowedLocalPreviewUrl.js} +3 -7
- package/dist/lifecycle/initErrors.d.ts +1 -0
- package/dist/lifecycle/initErrors.d.ts.map +1 -1
- package/dist/lifecycle/initErrors.js +7 -0
- package/dist/lifecycle/initializationController.d.ts +6 -4
- package/dist/lifecycle/initializationController.d.ts.map +1 -1
- package/dist/lifecycle/initializationController.js +24 -15
- package/dist/lifecycle/resolveManifest.d.ts +13 -0
- package/dist/lifecycle/resolveManifest.d.ts.map +1 -0
- package/dist/lifecycle/resolveManifest.js +21 -0
- package/dist/lifecycle/types.d.ts +1637 -17
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js +18 -0
- package/dist/messages/sandboxMessageRouter.d.ts.map +1 -1
- package/dist/messages/sandboxMessageRouter.js +2 -2
- package/dist/protocol/dataSources/dataSourcePage.d.ts +3 -4
- package/dist/protocol/dataSources/dataSourcePage.js +2 -3
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/isLocalBlockServerUrl.d.ts +2 -0
- package/dist/protocol/isLocalBlockServerUrl.js +9 -0
- package/dist/protocol/messages/connect.d.ts +2 -2
- package/dist/protocol/messages/connect.js +2 -2
- package/dist/protocol/messages/createPageResult.d.ts +2 -2
- package/dist/protocol/messages/createPageResult.js +3 -3
- package/dist/protocol/messages/getPage.d.ts +2 -2
- package/dist/protocol/messages/getPage.js +3 -3
- package/dist/protocol/messages/hostToSandbox.d.ts +3 -3
- package/dist/protocol/messages/hostToSandbox.js +10 -10
- package/dist/protocol/messages/init.d.ts +1 -1
- package/dist/protocol/messages/queryDataSourceResult.d.ts +3 -3
- package/dist/protocol/messages/queryDataSourceResult.js +6 -3
- package/dist/protocol/messages/updatePageResult.d.ts +2 -2
- package/dist/protocol/messages/updatePageResult.js +3 -3
- package/dist/protocol/pages/page.d.ts +2 -2
- package/dist/protocol/pages/page.js +1 -1
- package/dist/protocol/protocolVersion.d.ts +3 -2
- package/dist/protocol/protocolVersion.js +4 -2
- package/dist/protocol.d.ts +9 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +8 -0
- package/docs/bridge/changelog.md +67 -0
- package/docs/bridge/protocol.md +182 -0
- package/docs/bridge/versioning.md +38 -0
- package/docs/compatibility.md +68 -0
- package/docs/handlers.md +199 -0
- package/docs/lifecycle.md +117 -0
- package/package.json +11 -3
- package/src/autoBindProperties.ts +5 -2
- package/src/compatibility/addMetadataReadSchemasForProtocol3To4.ts +36 -0
- package/src/compatibility/normalizeHostToSandboxMessage.ts +54 -0
- package/src/compatibility/normalizePageResultsForProtocol3To5.ts +28 -0
- package/src/compatibility/normalizePageResultsForProtocol6.ts +23 -0
- package/src/compatibility/normalizeSandboxToHostMessage.ts +10 -0
- package/src/{lifecycle/legacyPage.ts → compatibility/pageForProtocol3To5.ts} +52 -11
- package/src/compatibility/pageResult.ts +18 -0
- package/src/compatibility/pageWithNullTextFallbackProperties.ts +53 -0
- package/src/createCustomBlockHost.ts +152 -62
- package/src/index.ts +4 -51
- package/src/{localBlockUrl.ts → isAllowedLocalPreviewUrl.ts} +4 -7
- package/src/lifecycle/initErrors.ts +9 -0
- package/src/lifecycle/initializationController.ts +34 -19
- package/src/lifecycle/resolveManifest.ts +31 -0
- package/src/lifecycle/types.ts +84 -16
- package/src/messages/sandboxMessageRouter.ts +2 -2
- package/src/protocol.ts +8 -0
- package/dist/lifecycle/legacyPage.d.ts +0 -70
- package/dist/lifecycle/legacyPage.d.ts.map +0 -1
- package/dist/lifecycle/loadCustomBlockManifest.d.ts +0 -16
- package/dist/lifecycle/loadCustomBlockManifest.d.ts.map +0 -1
- package/dist/lifecycle/loadCustomBlockManifest.js +0 -65
- package/dist/lifecycle/manifestOptions.d.ts +0 -17
- package/dist/lifecycle/manifestOptions.d.ts.map +0 -1
- package/dist/lifecycle/normalizeHostToSandboxMessage.d.ts +0 -6
- package/dist/lifecycle/normalizeHostToSandboxMessage.d.ts.map +0 -1
- package/dist/lifecycle/normalizeHostToSandboxMessage.js +0 -16
- package/dist/lifecycle/normalizePage.d.ts +0 -7
- package/dist/lifecycle/normalizePage.d.ts.map +0 -1
- package/dist/lifecycle/normalizePage.js +0 -22
- package/dist/localBlockUrl.d.ts.map +0 -1
- package/src/lifecycle/loadCustomBlockManifest.ts +0 -89
- package/src/lifecycle/manifestOptions.ts +0 -19
- package/src/lifecycle/normalizeHostToSandboxMessage.ts +0 -29
- package/src/lifecycle/normalizePage.ts +0 -35
- /package/dist/{lifecycle/manifestOptions.js → compatibility/pageResult.js} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Bridge wire protocol
|
|
2
|
+
|
|
3
|
+
The bridge carries initialization, data requests, results, and live updates between a custom block's
|
|
4
|
+
SDK and its host. This reference defines the handshake, message identity, validation, and payload
|
|
5
|
+
semantics for host integrators and bridge maintainers. Block authors use the SDK's public APIs.
|
|
6
|
+
|
|
7
|
+
Messages are `postMessage` payloads defined by shared Valibot schemas, exposed through
|
|
8
|
+
`@notionhq/custom-blocks-host/protocol`. The embedding application enforces permissions and record
|
|
9
|
+
access. Version-specific formats and conversions are described in
|
|
10
|
+
[Versioning and compatibility](versioning.md).
|
|
11
|
+
|
|
12
|
+
## Initialization
|
|
13
|
+
|
|
14
|
+
The handshake is:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
sandbox connect → host init → sandbox initResult
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
All three messages carry the sandbox-generated `initializationId`. A sandbox document sends
|
|
21
|
+
`connect` once. The host sends one `init` for the accepted connection and ignores subsequent
|
|
22
|
+
`connect` messages, including malformed ones. Live updates wait for `initResult.success`.
|
|
23
|
+
`init.error` and `initResult.error` are terminal.
|
|
24
|
+
|
|
25
|
+
The sandbox waits for `init` without a timeout. If host state preparation times out, the host sends
|
|
26
|
+
`init.error` with `initial_state_timeout` to end that wait.
|
|
27
|
+
|
|
28
|
+
`connect` carries connection identity, version metadata, and an optional local manifest declaration.
|
|
29
|
+
The SDK reads that declaration from the `application/json` script with ID
|
|
30
|
+
`notion-custom-block-manifest`, injected into the block HTML by dev tooling. It reads metadata only
|
|
31
|
+
from supported local block server URLs. Missing metadata omits `connect.manifest`; invalid metadata
|
|
32
|
+
sends `connect.error` with `manifest_invalid`.
|
|
33
|
+
|
|
34
|
+
The embedding application selects the manifest source. In host mode, the host uses its persisted
|
|
35
|
+
manifest and ignores the sandbox declaration. In sandbox mode, the host uses `connect.manifest` from
|
|
36
|
+
a permitted local sandbox; a missing declaration produces `manifest_unavailable`. The selected
|
|
37
|
+
manifest is authoritative and is returned in `init` with context and data-source bindings. Errors
|
|
38
|
+
from the selected manifest source pass through unchanged. Host mode can initialize after a sandbox
|
|
39
|
+
`manifest_invalid` error using its own manifest; other connect errors remain fatal. The connect
|
|
40
|
+
parser discards unknown properties.
|
|
41
|
+
|
|
42
|
+
`initResult.success` may include `initialHeight`, the height of the sandbox's rendered content in
|
|
43
|
+
CSS pixels. The host's [lifecycle guide](../lifecycle.md) describes iframe sizing,
|
|
44
|
+
reveal, and retry behavior.
|
|
45
|
+
|
|
46
|
+
`connect.bridgeProtocolVersion` declares the sandbox's wire contract. `sdkVersion` is analytics
|
|
47
|
+
metadata. See [versioning and compatibility](versioning.md) for supported formats and
|
|
48
|
+
[Validation and errors](#validation-and-errors) for malformed handshake behavior.
|
|
49
|
+
|
|
50
|
+
## Manifests
|
|
51
|
+
|
|
52
|
+
A manifest declares a block's data sources and display metadata. `manifestSchema` defines its fields
|
|
53
|
+
and defaults omitted `dataSources` and each data source's omitted `properties` to `{}`.
|
|
54
|
+
|
|
55
|
+
`isLocalBlockServerUrl(url)` accepts HTTP(S) URLs on `localhost`, `*.localhost`, or `127.0.0.1`
|
|
56
|
+
without credentials. It checks the address only. The host also requires a sandbox-mode block to use
|
|
57
|
+
a different origin from its embedding page.
|
|
58
|
+
|
|
59
|
+
## Message identity
|
|
60
|
+
|
|
61
|
+
- One-shot request/result pairs use `requestId`.
|
|
62
|
+
- `queryDataSource` is a long-lived subscription; requests and every update use its stable
|
|
63
|
+
`subscriptionId`.
|
|
64
|
+
- The initialization lifecycle uses `initializationId`, not `requestId` or `subscriptionId`.
|
|
65
|
+
- One-way messages, such as `resize` and bridge NACKs, have no correlation ID.
|
|
66
|
+
|
|
67
|
+
Hosts key query state by `subscriptionId`, replace state when a request reuses one, and suppress
|
|
68
|
+
stale asynchronous results.
|
|
69
|
+
|
|
70
|
+
The sandbox can send `unsubscribeDataSourceQuery` with the same `subscriptionId` when it no longer
|
|
71
|
+
needs the subscription. An unknown or repeated unsubscribe is a no-op. Hosts stop future refreshes
|
|
72
|
+
and suppress results from work already in progress.
|
|
73
|
+
|
|
74
|
+
## Validation and errors
|
|
75
|
+
|
|
76
|
+
Each direction has a validation schema:
|
|
77
|
+
|
|
78
|
+
- Sandbox to host: `sandboxToHostMessageSchema`
|
|
79
|
+
- Host to sandbox: `hostToSandboxMessageSchema`
|
|
80
|
+
|
|
81
|
+
On parse failure, the host replies with `invalidSandboxMessage` and the sandbox replies with
|
|
82
|
+
`invalidHostMessage`, except for the handshake cases below. These replies are negative
|
|
83
|
+
acknowledgments (NACKs). Receivers do not NACK another NACK.
|
|
84
|
+
|
|
85
|
+
Malformed sandbox messages do not change the host's initialization state or timeout, except as
|
|
86
|
+
follows:
|
|
87
|
+
|
|
88
|
+
- The host expects `connect` and receives a malformed `connect` with a readable `initializationId`.
|
|
89
|
+
The host sends `init.error` instead of a NACK, then fails initialization. An invalid or
|
|
90
|
+
unsupported numeric protocol version takes precedence over `invalid_connect_payload`.
|
|
91
|
+
- The host expects `initResult` and receives a malformed `initResult` with the active
|
|
92
|
+
`initializationId`. The host sends a NACK and fails initialization with
|
|
93
|
+
`invalid_init_result_payload`. This error code describes a local host failure. The host does not
|
|
94
|
+
send it in `initResult.error`.
|
|
95
|
+
|
|
96
|
+
A malformed `initResult` with a missing or stale ID does not end initialization or reset its
|
|
97
|
+
timeout. Malformed messages do not restart initialization after it succeeds or fails.
|
|
98
|
+
|
|
99
|
+
The sandbox handles a malformed `init` differently if it can verify the `initializationId`. In that
|
|
100
|
+
case, it sends `initResult.error` with `invalid_init_payload` instead of a NACK. Otherwise, it sends
|
|
101
|
+
`invalidHostMessage`.
|
|
102
|
+
|
|
103
|
+
`CustomBlockErrorInfo` carries `code`, `message`, and `isRetryable`. Error schemas accept any string
|
|
104
|
+
for `code`, including unknown codes. TypeScript aliases list known codes for autocomplete.
|
|
105
|
+
|
|
106
|
+
## Data sources
|
|
107
|
+
|
|
108
|
+
### Bindings and IDs
|
|
109
|
+
|
|
110
|
+
Hosts send `NotionDataSourceBindings` as `dataSources: { bindings }`, keyed by the semantic data
|
|
111
|
+
source key declared in the manifest. `collectionSchema` contains only actual database properties.
|
|
112
|
+
|
|
113
|
+
Sandbox-to-host object references are raw IDs. The SDK resolves semantic data-source and property
|
|
114
|
+
keys before sending query or page-operation requests. Get and update requests can carry an optional
|
|
115
|
+
resolved `dataSourceId`.
|
|
116
|
+
|
|
117
|
+
### Query requests
|
|
118
|
+
|
|
119
|
+
`queryDataSource` may include a resolved `filter` and an ordered `sorts` list. Each sort contains a
|
|
120
|
+
raw `propertyId` and an `ascending` or `descending` direction. Hosts apply sorts in array order. The
|
|
121
|
+
SDK and host validate that the list contains at most ten unique properties. The host rejects
|
|
122
|
+
property types without a supported sort value.
|
|
123
|
+
|
|
124
|
+
Every filter and sort property ID must exist in `collectionSchema.propertiesById`. Queries with
|
|
125
|
+
filters or sorts return `data_source_schema_unavailable` when the schema is unavailable. Filter
|
|
126
|
+
branches, operators, person references, and sort objects reject extra fields.
|
|
127
|
+
|
|
128
|
+
#### Creator and status filters
|
|
129
|
+
|
|
130
|
+
Creator filters require `propertyId` to identify an actual database property of type `created_by`.
|
|
131
|
+
The `created_by` filter branch selects the property type, while `propertyId` addresses the column.
|
|
132
|
+
|
|
133
|
+
The `created_by` filter supports human user targets with `contains` and `does_not_contain`, plus
|
|
134
|
+
`is_empty` and `is_not_empty`. Hosts use row creator metadata, including non-human and missing
|
|
135
|
+
creators in exclusion results.
|
|
136
|
+
|
|
137
|
+
Status filters support option operators and stored group names. Group operators accept one name or
|
|
138
|
+
an array of 1–5 names. Hosts must validate each name against the bound Status property.
|
|
139
|
+
|
|
140
|
+
#### Date filters
|
|
141
|
+
|
|
142
|
+
Date comparisons accept ISO values and relative values such as `today`. The query schema defines the
|
|
143
|
+
accepted values and range operators. Range operators require an empty object.
|
|
144
|
+
|
|
145
|
+
Date comparisons accept `target` inside `date`, beside the operator. The target is `start_date` by
|
|
146
|
+
default. For ranges, `end_date` compares the range end. For individual dates, it compares the date.
|
|
147
|
+
Empty checks accept either target, but they test the whole property.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
filter: {
|
|
151
|
+
propertyId: "schedule-id",
|
|
152
|
+
date: { target: "end_date", on_or_after: "2026-10-08" },
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Page context
|
|
157
|
+
|
|
158
|
+
Containing-page context uses `CustomBlockPage`. The `init.page` and `pageChanged.page` fields
|
|
159
|
+
contain `{ type: "page", id, parent }` for an accessible page, or `{ type: "unavailable" }` when the
|
|
160
|
+
containing page itself is inaccessible. The unavailable shape never carries a page ID. This is
|
|
161
|
+
distinct from an accessible page with an inaccessible parent
|
|
162
|
+
(`page.parent: { type: "unavailable" }`).
|
|
163
|
+
|
|
164
|
+
## Page writes
|
|
165
|
+
|
|
166
|
+
The `createPage` and `updatePage` messages use raw property IDs from Notion as map keys. Each value
|
|
167
|
+
must carry the same raw property ID in its `id` field.
|
|
168
|
+
|
|
169
|
+
## Page responses
|
|
170
|
+
|
|
171
|
+
Host handlers return unified `NotionPageData` for queries and page operations. Properties use
|
|
172
|
+
display names as keys and typed values that include their raw property IDs. Only actual schema
|
|
173
|
+
properties are returned. Query results contain `items` and `hasMore`. `notionPageDataSchema` defines
|
|
174
|
+
the page fields, including archive state and creation, edit, and visit metadata.
|
|
175
|
+
|
|
176
|
+
Page reads return string values for `unique_id`, `formula`, `rollup`, `button`, `verification`, and
|
|
177
|
+
`location`, preserving each property's type. These properties are read-only. Values use stored text,
|
|
178
|
+
or `""` when absent. Hosts do not evaluate formulas or rollups.
|
|
179
|
+
|
|
180
|
+
The host converts responses to the sandbox's declared protocol. See
|
|
181
|
+
[versioning and compatibility](versioning.md) for protocol version rules. The host's
|
|
182
|
+
[compatibility reference](../compatibility.md) describes older response formats.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Bridge protocol versioning
|
|
2
|
+
|
|
3
|
+
The SDK inside a block and the host in its embedding application release independently. A bridge
|
|
4
|
+
protocol version identifies the wire contract they use, independently of their package versions.
|
|
5
|
+
This reference defines the version identifiers, protocol format names, and rules for contract
|
|
6
|
+
changes. Release boundaries and exceptions are recorded in the [changelog](changelog.md). The host's
|
|
7
|
+
[compatibility reference](../compatibility.md) describes runtime support and response
|
|
8
|
+
conversions.
|
|
9
|
+
|
|
10
|
+
## Version identifiers
|
|
11
|
+
|
|
12
|
+
- **Bridge protocol:** `connect.bridgeProtocolVersion` declares the sandbox's wire contract.
|
|
13
|
+
- **SDK package:** identifies the SDK's public API and implementation. It can change without a wire
|
|
14
|
+
change.
|
|
15
|
+
- **Host package:** identifies the runtime implementation. Publishing it does not deploy it to
|
|
16
|
+
Notion.
|
|
17
|
+
|
|
18
|
+
`connect.bridgeProtocolVersion` selects the wire contract. `sdkVersion` is analytics metadata.
|
|
19
|
+
`LATEST_BRIDGE_PROTOCOL_VERSION` identifies the latest contract defined by the package.
|
|
20
|
+
|
|
21
|
+
## Protocol export names
|
|
22
|
+
|
|
23
|
+
The `@notionhq/custom-blocks-host/protocol` entrypoint exports wire definitions. Page formats used
|
|
24
|
+
by protocols 3–5 are named `NotionPageForProtocol3To5` and `NotionDataSourcePageForProtocol3To5`,
|
|
25
|
+
with matching `notionPageForProtocol3To5Schema` and `notionDataSourcePageForProtocol3To5Schema`
|
|
26
|
+
validators. Message types and schemas containing `WithProtocol3To5Compatibility` accept both current
|
|
27
|
+
page formats and protocol 3–5 page formats. `UNIFIED_PAGE_PROTOCOL_VERSION` is 6, the minimum
|
|
28
|
+
protocol version that uses unified pages.
|
|
29
|
+
|
|
30
|
+
## Version changes
|
|
31
|
+
|
|
32
|
+
A breaking wire change increases the bridge protocol version. This includes changed meanings,
|
|
33
|
+
required fields, and new response variants an older receiver rejects. Optional fields and new
|
|
34
|
+
messages need no bump only when older receivers can safely ignore or NACK them. Parsing success
|
|
35
|
+
alone does not prove compatible SDK behavior.
|
|
36
|
+
|
|
37
|
+
An SDK that requires a newer protocol needs a host that supports that contract. Updating the SDK
|
|
38
|
+
package does not update the host in the embedding application.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Host compatibility
|
|
2
|
+
|
|
3
|
+
A host can update while deployed blocks keep older SDKs. The runtime accepts supported protocol
|
|
4
|
+
versions and converts current handler results to each block's declared contract. This reference
|
|
5
|
+
covers version admission, normalization, and the formats sent to older blocks. Protocol version
|
|
6
|
+
rules and release history are in the [versioning guide](bridge/versioning.md) and
|
|
7
|
+
[changelog](bridge/changelog.md).
|
|
8
|
+
|
|
9
|
+
## Supported versions
|
|
10
|
+
|
|
11
|
+
The protocol subpath exports `LATEST_BRIDGE_PROTOCOL_VERSION` and
|
|
12
|
+
`MIN_HOST_SUPPORTED_BRIDGE_PROTOCOL_VERSION`. These constants define the package's latest known
|
|
13
|
+
protocol and runtime minimum. Embedders can raise the minimum but cannot enable retired versions.
|
|
14
|
+
The host admits future positive integer versions and validates them against known schemas. Admission
|
|
15
|
+
does not guarantee that future features work.
|
|
16
|
+
|
|
17
|
+
`sdkVersion` is analytics metadata. Compatibility behavior depends on the protocol version.
|
|
18
|
+
|
|
19
|
+
The current SDK declares protocol 8. The shared runtime minimum is 3. The dev shell uses the Worker
|
|
20
|
+
manifest in host mode and accepts the shared runtime's supported protocol versions. Protocols 7 and
|
|
21
|
+
8 use the same page and query response formats. Protocol 8's local manifest declaration is selected
|
|
22
|
+
only in sandbox mode; host mode uses the persisted manifest. See the
|
|
23
|
+
[protocol 8 release entry](bridge/changelog.md#protocol-8-local-manifest-declarations).
|
|
24
|
+
|
|
25
|
+
The `minBridgeProtocolVersion` option defaults to the runtime minimum. Raising the option rejects
|
|
26
|
+
older SDKs for this embedding application. Lowering it cannot restore retired versions. Raising
|
|
27
|
+
`MIN_HOST_SUPPORTED_BRIDGE_PROTOCOL_VERSION` retires those versions across the runtime.
|
|
28
|
+
|
|
29
|
+
## Host normalization
|
|
30
|
+
|
|
31
|
+
The host validates sandbox requests before dispatching them to handlers. Handlers use current data
|
|
32
|
+
shapes, and the host converts responses to the sandbox's declared protocol. Setters, query
|
|
33
|
+
refreshes, and handler responses use the same conversion. Unchanged messages and errors pass
|
|
34
|
+
through.
|
|
35
|
+
|
|
36
|
+
## Current compatibility behavior
|
|
37
|
+
|
|
38
|
+
| Target | Query results | Page operation results | Binding schemas |
|
|
39
|
+
| ------ | --------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
40
|
+
| 3–4 | Flat ID-keyed values, including synthetic metadata entries | ID-keyed properties with unsupported property objects omitted | Synthetic metadata read schemas restored in outgoing copies |
|
|
41
|
+
| 5 | Same query values as protocols 3–4 | Same page format as protocols 3–4 | Actual database schemas. The SDK supplies synthetic read schemas locally |
|
|
42
|
+
| 6 | Unified name-keyed properties. Text fallback property objects become `null` | Same unified page format | Actual database schemas |
|
|
43
|
+
| 7+ | Unified pages with typed text fallback properties | Same unified page format | Actual database schemas |
|
|
44
|
+
|
|
45
|
+
The synthetic metadata IDs are `created_time`, `last_edited_time`, `created_by`, and
|
|
46
|
+
`last_edited_by`. They retain metadata meaning if an actual property uses the same raw ID. This
|
|
47
|
+
matches the protocol 3–4 binding schema precedence. Host validation always uses the unmodified
|
|
48
|
+
actual database schema.
|
|
49
|
+
|
|
50
|
+
Release-specific compatibility limits are documented in the changelog entries for
|
|
51
|
+
[protocol 5 page context](bridge/changelog.md#protocol-5-unavailable-containing-page-context)
|
|
52
|
+
and
|
|
53
|
+
[protocol 6 text fallback properties](bridge/changelog.md#protocol-6-richer-fallback-properties).
|
|
54
|
+
|
|
55
|
+
### Unavailable containing-page context
|
|
56
|
+
|
|
57
|
+
Protocols 3–4 receive `context_unavailable` during initialization or stop when containing-page
|
|
58
|
+
context becomes unavailable. This concerns `init.page` and `pageChanged.page`, not a page
|
|
59
|
+
operation's `page_unavailable` error.
|
|
60
|
+
|
|
61
|
+
### Protocol 3–5 metadata query semantics
|
|
62
|
+
|
|
63
|
+
Page creation and edit metadata is readable without corresponding database columns. Current page
|
|
64
|
+
objects carry these fields at the top level. Protocol 3–5 query adapters copy them into
|
|
65
|
+
`propertiesById` for older SDKs.
|
|
66
|
+
|
|
67
|
+
Filters and sorts require actual database properties in the bound schema. The host does not support
|
|
68
|
+
queries against synthetic metadata IDs without corresponding database properties.
|
package/docs/handlers.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Host handlers and data
|
|
2
|
+
|
|
3
|
+
Handlers connect block requests to your application's data access, persistence, and navigation. The
|
|
4
|
+
runtime validates bridge messages and manages subscriptions. Your application enforces viewer
|
|
5
|
+
permissions and implements the requested operations. This guide covers handler contracts, a
|
|
6
|
+
data-source example, refreshes, and external navigation.
|
|
7
|
+
|
|
8
|
+
The [dev shell](https://www.npmjs.com/package/@notionhq/custom-blocks-dev-shell) is a working host
|
|
9
|
+
implementation with local sample data. Use it as a reference for a larger integration. Production
|
|
10
|
+
hosts must provide their own permissions, data access, and persistence.
|
|
11
|
+
|
|
12
|
+
## Handler contracts
|
|
13
|
+
|
|
14
|
+
`queryDataSource` is required. Other handlers are optional. Omitting a one-shot request handler
|
|
15
|
+
sends no response to that request. A handler returns a result synchronously or as a promise. Errors
|
|
16
|
+
carry `{ code, message, isRetryable }`, with open string codes.
|
|
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.
|
|
21
|
+
|
|
22
|
+
Query filters and sorts are validated against the actual bound database schema before
|
|
23
|
+
`queryDataSource` runs. See the [wire reference](bridge/protocol.md#data-sources) for
|
|
24
|
+
query semantics.
|
|
25
|
+
|
|
26
|
+
## Connect a data source
|
|
27
|
+
|
|
28
|
+
Connect an embedded block to an in-memory Tasks data source with one numeric Estimate property. This
|
|
29
|
+
walkthrough extends the [README's embed example](../README.md#create-a-host): declare the data
|
|
30
|
+
source, bind its keys to IDs, return a query result, and refresh that result after a value changes.
|
|
31
|
+
|
|
32
|
+
Keep the iframe, context, and lifecycle callbacks from the embed example. The block must declare the
|
|
33
|
+
same manifest and query `tasks` through the SDK's public APIs.
|
|
34
|
+
|
|
35
|
+
### Declare and bind the data source
|
|
36
|
+
|
|
37
|
+
The manifest uses block-defined keys. Bindings connect those keys to actual data-source and property
|
|
38
|
+
IDs. Add these definitions before creating the host:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import type {
|
|
42
|
+
CustomBlockHostDataSourcesPayload,
|
|
43
|
+
CustomBlockHostHandlers,
|
|
44
|
+
} from "@notionhq/custom-blocks-host"
|
|
45
|
+
import type { CustomBlockManifest, NotionPageData } from "@notionhq/custom-blocks-host/protocol"
|
|
46
|
+
|
|
47
|
+
const tasksId = "44444444-4444-4444-8444-444444444444"
|
|
48
|
+
|
|
49
|
+
const manifest: CustomBlockManifest = {
|
|
50
|
+
version: 1,
|
|
51
|
+
dataSources: {
|
|
52
|
+
tasks: {
|
|
53
|
+
name: "Tasks",
|
|
54
|
+
properties: {
|
|
55
|
+
estimate: { name: "Estimate", type: "number" },
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const taskBindings: CustomBlockHostDataSourcesPayload = {
|
|
62
|
+
bindings: {
|
|
63
|
+
tasks: {
|
|
64
|
+
collectionPointer: { table: "collection", id: tasksId },
|
|
65
|
+
collectionSchema: {
|
|
66
|
+
propertiesById: {
|
|
67
|
+
"estimate-id": { name: "Estimate", type: "number" },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
propertyIdsByKey: { estimate: "estimate-id" },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
In the embed example, return `{ status: "success", manifest }` from `getPersistedManifest` and
|
|
77
|
+
replace `initialState.dataSources` with `taskBindings`. Here, `tasks` and `estimate` are semantic
|
|
78
|
+
keys; `tasksId` and `estimate-id` identify the bound data source and property.
|
|
79
|
+
|
|
80
|
+
### Return query results
|
|
81
|
+
|
|
82
|
+
Add this handler and use it as the embed example's `handlers.queryDataSource`. Keep its existing
|
|
83
|
+
`resize` handler.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
let estimate = 3
|
|
87
|
+
|
|
88
|
+
const handlers: CustomBlockHostHandlers = {
|
|
89
|
+
queryDataSource: message => {
|
|
90
|
+
if (message.dataSourceId !== tasksId) {
|
|
91
|
+
return {
|
|
92
|
+
status: "error",
|
|
93
|
+
error: {
|
|
94
|
+
code: "unmapped_data_source",
|
|
95
|
+
message: "This data source is not available.",
|
|
96
|
+
isRetryable: false,
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (message.filter || message.sorts?.length) {
|
|
102
|
+
return {
|
|
103
|
+
status: "error",
|
|
104
|
+
error: {
|
|
105
|
+
code: "invalid_data_source_query",
|
|
106
|
+
message: "This demo supports only unfiltered, unsorted queries.",
|
|
107
|
+
isRetryable: false,
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const items: NotionPageData[] = [
|
|
113
|
+
{
|
|
114
|
+
object: "page",
|
|
115
|
+
id: "55555555-5555-4555-8555-555555555555",
|
|
116
|
+
parent: { type: "data_source_id", data_source_id: tasksId },
|
|
117
|
+
is_archived: false,
|
|
118
|
+
in_trash: false,
|
|
119
|
+
properties: {
|
|
120
|
+
Estimate: { id: "estimate-id", type: "number", number: estimate },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
status: "success",
|
|
127
|
+
items: items.slice(0, message.limit),
|
|
128
|
+
hasMore: items.length > message.limit,
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The SDK resolves `tasks` to `tasksId` before the host receives the request. Result properties use
|
|
135
|
+
display names as keys (`Estimate`) and include their raw property IDs (`estimate-id`). The runtime
|
|
136
|
+
handles subscription IDs, validates results, and converts them for supported older SDKs.
|
|
137
|
+
|
|
138
|
+
This demo rejects filters and sorts rather than silently ignoring them. A production adapter must
|
|
139
|
+
enforce record access, execute the requested filter and sorts, and honor the result limit. See
|
|
140
|
+
[query semantics](bridge/protocol.md#data-sources).
|
|
141
|
+
|
|
142
|
+
## Refresh active queries
|
|
143
|
+
|
|
144
|
+
After creating the host, update the in-memory value and notify active subscriptions:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
estimate = 5
|
|
148
|
+
host.refreshQuery({ dataSourceId: tasksId })
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If the block has an active query for Tasks, its next result contains an estimate of `5`. A query
|
|
152
|
+
started later also reads the updated value. The application triggers refreshes when its underlying
|
|
153
|
+
data changes; the runtime re-runs matching subscriptions. Call `host.stop()` when removing the
|
|
154
|
+
embed.
|
|
155
|
+
|
|
156
|
+
`refreshQuery()` re-runs active subscriptions for the supplied data-source ID with their existing
|
|
157
|
+
filter, sorts, and limit. Overlapping refreshes queue one follow-up query. The running query
|
|
158
|
+
delivers its result first. Unsubscribe, replacement, and stop discard queued work and suppress late
|
|
159
|
+
results. Non-retryable query errors end subscriptions. Retryable errors retain them.
|
|
160
|
+
|
|
161
|
+
## Page and user operations
|
|
162
|
+
|
|
163
|
+
`createPage`, `getPage`, and `updatePage` connect page requests to your application's data access
|
|
164
|
+
and persistence. `getUser` and `listUsers` supply user data. Each handler returns a success payload
|
|
165
|
+
or an error. The runtime adds the request's correlation ID and sends the response. The application
|
|
166
|
+
enforces record access before reading or writing data.
|
|
167
|
+
|
|
168
|
+
`openPage` handles navigation to a Notion page. `resize` receives the block's requested height in
|
|
169
|
+
CSS pixels. The application owns navigation and iframe sizing.
|
|
170
|
+
|
|
171
|
+
## External navigation
|
|
172
|
+
|
|
173
|
+
`openExternalUrl` receives an `AbortSignal` and an absolute HTTP or HTTPS URL without credentials.
|
|
174
|
+
The URL is limited to 2,048 JavaScript code units before and after normalization. The adapter
|
|
175
|
+
displays the exact URL, obtains approval, and navigates only after approval. It may apply further
|
|
176
|
+
restrictions. Dismiss pending confirmation UI when the signal aborts.
|
|
177
|
+
|
|
178
|
+
Each iframe permits one pending navigation. A different request receives `pending_navigation`. A
|
|
179
|
+
duplicate of the active request is ignored. Completed requests are forgotten, so later requests
|
|
180
|
+
require fresh approval. The runtime redacts the URL from `onLog` payloads and suppresses results
|
|
181
|
+
after stop.
|
|
182
|
+
|
|
183
|
+
## Property binding
|
|
184
|
+
|
|
185
|
+
`getAutoBoundPropertyIdsByKey({ manifestProperties, propertySchemasById })` requires matching
|
|
186
|
+
property types and either an exact raw ID match or a display-name match after trimming and
|
|
187
|
+
lowercasing. IDs are not trimmed or case-folded. Exactly one candidate creates a binding. Zero or
|
|
188
|
+
multiple candidates leave the property unmapped. The result maps manifest property keys to database
|
|
189
|
+
property IDs. An ID match has no priority over a name match: if they identify different compatible
|
|
190
|
+
properties, the manifest property stays unmapped.
|
|
191
|
+
|
|
192
|
+
## Date conversion and types
|
|
193
|
+
|
|
194
|
+
`toNotionDateValue()` converts `NotionDateInput` into the four `CustomBlockDateValue` variants,
|
|
195
|
+
including reminders. Invalid input throws `InvalidNotionDateError`.
|
|
196
|
+
|
|
197
|
+
The root exports host configuration, handlers, results, and `*MessageInput` types. Wire schemas,
|
|
198
|
+
message and page types, and constants such as `LATEST_BRIDGE_PROTOCOL_VERSION` use the
|
|
199
|
+
[protocol subpath](../README.md#protocol-schemas-and-types).
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Host initialization and lifecycle
|
|
2
|
+
|
|
3
|
+
The host prepares a block's manifest and context, completes initialization, and manages the
|
|
4
|
+
connection until the iframe is removed. This reference covers state preparation, timeouts,
|
|
5
|
+
callbacks, live state, and cleanup. Start with the [embed example](../README.md#create-a-host).
|
|
6
|
+
|
|
7
|
+
## Manifest and initial state
|
|
8
|
+
|
|
9
|
+
Pass the full block URL as `sandboxUrl`. The host derives the origin used to authenticate incoming
|
|
10
|
+
messages and target outgoing messages. `CustomBlockManifestSource` selects the manifest:
|
|
11
|
+
|
|
12
|
+
| `manifestSource` | Manifest source |
|
|
13
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
14
|
+
| `"host"` | The manifest returned by `getPersistedManifest({ signal })` |
|
|
15
|
+
| `"sandbox"` | The local declaration supplied in `connect.manifest`, subject to the [local URL policy](#local-block-urls) |
|
|
16
|
+
|
|
17
|
+
`getPersistedManifest` is required in both modes and starts when the host is created. It returns
|
|
18
|
+
`CustomBlockHostManifestResult`: either `{ status: "success", manifest }` or
|
|
19
|
+
`{ status: "error", error }`. It must not resolve to `null` or `undefined`. A definition that is
|
|
20
|
+
still loading keeps the promise pending; a failed load returns an error result. The host validates
|
|
21
|
+
the result and normalizes the manifest before calling `prepareInitialState`. Omitted `dataSources`
|
|
22
|
+
and each source's omitted `properties` default to `{}`.
|
|
23
|
+
|
|
24
|
+
The sandbox loads independently and sends `connect`. In sandbox mode, the SDK reads the manifest
|
|
25
|
+
from JSON metadata injected into the local block HTML by dev tooling. The host validates the
|
|
26
|
+
declaration in `connect`. The two sources do not wait for each other; only the selected result
|
|
27
|
+
determines initialization. Sandbox mode has no persisted fallback. The
|
|
28
|
+
[wire reference](bridge/protocol.md#initialization) describes the declaration and its
|
|
29
|
+
validation errors.
|
|
30
|
+
|
|
31
|
+
Once the selected manifest is ready, the host calls `prepareInitialState({ manifest, signal })`
|
|
32
|
+
once. Return `{ status: "success", initialState }` with context and data-source bindings, or
|
|
33
|
+
`{ status: "error", error }`. This callback also must not resolve to `null` or `undefined`. The host
|
|
34
|
+
validates its result. The prepared state omits the manifest; the host adds the selected manifest to
|
|
35
|
+
`init`. Host-mode preparation runs concurrently with connection setup. Sandbox-mode preparation
|
|
36
|
+
starts after `connect` supplies the declaration. The host sends `init` after preparation and a valid
|
|
37
|
+
connection succeed. A preparation failure is retained until the sandbox connects.
|
|
38
|
+
|
|
39
|
+
Errors from the selected manifest source retain their `code`, `message`, and `isRetryable`. A
|
|
40
|
+
missing sandbox declaration produces `manifest_unavailable`. A sandbox `manifest_invalid` error is
|
|
41
|
+
ignored in host mode because that mode uses the persisted manifest; other connect errors remain
|
|
42
|
+
fatal. Unexpected exceptions or invalid results from either callback produce `unknown_error`.
|
|
43
|
+
Diagnostics go to `onLog("warn", payload)`. Stopping aborts preparation and suppresses late results
|
|
44
|
+
without a cancellation warning.
|
|
45
|
+
|
|
46
|
+
## Timeouts
|
|
47
|
+
|
|
48
|
+
| Option | Waits for | Default | Failure code |
|
|
49
|
+
| ----------------------- | ------------------------------------- | --------- | ----------------------- |
|
|
50
|
+
| `noConnectTimeoutMs` | `connect` after the first iframe load | 5 seconds | `no_connect` |
|
|
51
|
+
| `initialStateTimeoutMs` | State preparation after `connect` | 5 seconds | `initial_state_timeout` |
|
|
52
|
+
| `noInitResultTimeoutMs` | `initResult` after `init` | 5 seconds | `no_init_result` |
|
|
53
|
+
|
|
54
|
+
The SDK waits for `init` without its own timeout. Handshake failures abort preparation and suppress
|
|
55
|
+
late results. Manifest and state preparation providers must respect their `signal`.
|
|
56
|
+
|
|
57
|
+
## Live state
|
|
58
|
+
|
|
59
|
+
`setTheme()`, `setContrastMode()`, `setParent()`, `setPage()`, `setDataSources()`, and
|
|
60
|
+
`setCurrentUser()` hold updates during initialization and send them after `initResult.success`. For
|
|
61
|
+
data-source query refreshes, see [Handlers and data](handlers.md#refresh-active-queries).
|
|
62
|
+
|
|
63
|
+
## Callbacks
|
|
64
|
+
|
|
65
|
+
The required `onStatusChange(state)` callback receives the `CustomBlockHostStatus` union:
|
|
66
|
+
|
|
67
|
+
| Status | Behavior | Payload |
|
|
68
|
+
| ---------------------- | -------------------------------------------------------------- | ------------------------------------------------------ |
|
|
69
|
+
| `waitingForConnect` | The host is listening; reported synchronously during creation | None |
|
|
70
|
+
| `preparingInit` | The host accepted a connection and is preparing initialization | `localManifest`, `sdkVersion`, `bridgeProtocolVersion` |
|
|
71
|
+
| `waitingForInitResult` | Successful `init` was sent; acknowledgment is pending | None |
|
|
72
|
+
| `initialized` | The sandbox accepted initialization | `resolvedManifest`, optional `initialHeight` |
|
|
73
|
+
| `failed` | Initialization or runtime failed | `error` |
|
|
74
|
+
| `stopped` | The application explicitly disposed of the host | None |
|
|
75
|
+
|
|
76
|
+
`localManifest` is optional and comes only from a permitted local sandbox. It is available before
|
|
77
|
+
initialization completes, so an adapter can use its requirements to prepare bindings.
|
|
78
|
+
`resolvedManifest` is the selected declaration sent in `init`. Rejected connections can skip
|
|
79
|
+
intermediate statuses. Both `failed` and `stopped` are terminal; stopping a failed host releases
|
|
80
|
+
resources without replacing its failure status.
|
|
81
|
+
|
|
82
|
+
Connection failures contain `{ phase, source, code, message, isRetryable }`. The phase is `connect`,
|
|
83
|
+
`init`, `initResult`, or `runtime`. The source identifies who reported the failure. Failures can
|
|
84
|
+
occur after initialization succeeds.
|
|
85
|
+
|
|
86
|
+
At `initialized`, apply a supplied `initialHeight` in CSS pixels before revealing the iframe. If the
|
|
87
|
+
height is absent, use your application's default size. The `resize` handler applies later height
|
|
88
|
+
changes. Reveal, sizing, and failure UI belong to the embedding application.
|
|
89
|
+
|
|
90
|
+
| Other callback | Behavior |
|
|
91
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `onQueryUnsubscribed(subscriptionId)` | Runs once when a subscription ends through unsubscribe, replacement, terminal error, or stop |
|
|
93
|
+
| `onLog(direction, payload)` | Receives bridge messages and warnings |
|
|
94
|
+
|
|
95
|
+
## Iframe lifetime
|
|
96
|
+
|
|
97
|
+
Each host handles one handshake. Create a new host and iframe to retry or replace the block URL. The
|
|
98
|
+
[wire reference](bridge/protocol.md#initialization) defines handshake and
|
|
99
|
+
malformed-message behavior.
|
|
100
|
+
|
|
101
|
+
The first observed iframe `load` is allowed. A second load stops the host and reports retryable
|
|
102
|
+
`iframe_reloaded`. Load-event cleanup does not isolate documents before that event. A replacement
|
|
103
|
+
document at the same origin can receive messages and invoke handlers until the host stops.
|
|
104
|
+
|
|
105
|
+
`stop()` removes listeners, cancels preparation, clears timers, ends subscriptions, and suppresses
|
|
106
|
+
pending responses. Call it when removing the iframe.
|
|
107
|
+
|
|
108
|
+
## Local block URLs
|
|
109
|
+
|
|
110
|
+
`isAllowedLocalPreviewUrl({ url, hostOrigin })` accepts HTTP or HTTPS URLs on `localhost`,
|
|
111
|
+
`*.localhost`, or `127.0.0.1` without credentials. It rejects the embedding page's origin.
|
|
112
|
+
`hostOrigin` must be nonempty. Pass the embedding page's serialized origin.
|
|
113
|
+
|
|
114
|
+
The protocol helper `isLocalBlockServerUrl(url)` checks the server URL without requiring origin
|
|
115
|
+
isolation. The host adds the embedding-origin restriction. `manifestSource: "sandbox"` enforces this
|
|
116
|
+
policy before the host starts. An invalid sandbox-mode URL throws `CustomBlockInitializationError`
|
|
117
|
+
with code `invalid_local_preview_url`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notionhq/custom-blocks-host",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Reusable host runtime for Notion custom blocks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,14 +14,22 @@
|
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./protocol": {
|
|
19
|
+
"types": "./dist/protocol.d.ts",
|
|
20
|
+
"import": "./dist/protocol.js",
|
|
21
|
+
"default": "./dist/protocol.js"
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"dependencies": {
|
|
20
|
-
"valibot": "^1.
|
|
25
|
+
"valibot": "^1.5.0"
|
|
21
26
|
},
|
|
22
27
|
"files": [
|
|
23
28
|
"src",
|
|
24
29
|
"dist",
|
|
25
|
-
"
|
|
30
|
+
"docs",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"THIRD_PARTY_LICENSES.md"
|
|
26
34
|
]
|
|
27
35
|
}
|
|
@@ -6,8 +6,8 @@ export type AutoBindableProperty = {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Returns a map from manifest property keys to database property IDs.
|
|
10
|
+
* Unmapped keys are omitted.
|
|
11
11
|
*
|
|
12
12
|
* For each manifest property:
|
|
13
13
|
* 1. Consider only schema properties of the same type.
|
|
@@ -15,6 +15,9 @@ export type AutoBindableProperty = {
|
|
|
15
15
|
* (exact string: no trim, no case folding) or its display name equals
|
|
16
16
|
* the manifest display name after `trim()` and lowercasing.
|
|
17
17
|
* 3. Bind when there is exactly one candidate. Otherwise leave it unmapped.
|
|
18
|
+
*
|
|
19
|
+
* An ID match has no priority over a display name match. If they identify two
|
|
20
|
+
* different properties of the same type, the manifest property stays unmapped.
|
|
18
21
|
*/
|
|
19
22
|
export function getAutoBoundPropertyIdsByKey(args: {
|
|
20
23
|
manifestProperties: Readonly<Record<string, AutoBindableProperty>>
|