@notionhq/custom-blocks-host 0.3.11 → 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 -236
- 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 +2 -2
- package/dist/protocol/protocolVersion.js +2 -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 +10 -2
- 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 -14
- package/dist/lifecycle/normalizePage.d.ts +0 -7
- package/dist/lifecycle/normalizePage.d.ts.map +0 -1
- package/dist/lifecycle/normalizePage.js +0 -47
- 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 -27
- package/src/lifecycle/normalizePage.ts +0 -71
- /package/dist/{lifecycle/manifestOptions.js → compatibility/pageResult.js} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Notion Labs, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,270 +1,177 @@
|
|
|
1
1
|
# @notionhq/custom-blocks-host
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The host manages the bridge between your application and a custom block iframe. Your application
|
|
4
|
+
owns the iframe, permissions, data access, persistence, analytics, and UI. Block authors use
|
|
5
|
+
`@notionhq/custom-blocks`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`@notionhq/custom-blocks` instead; they do not need to create a host.
|
|
7
|
+
Create the host before navigating the iframe. Pass the full block URL as `sandboxUrl`, and call
|
|
8
|
+
`stop()` when removing the iframe.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
For configuration and lifecycle details, see [Initialization and lifecycle](docs/lifecycle.md).
|
|
12
11
|
|
|
13
|
-
Create a host
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
## Create a host
|
|
13
|
+
|
|
14
|
+
Install `@notionhq/custom-blocks-host` in your embedding application. Run this TypeScript through
|
|
15
|
+
your browser bundler after the document body exists.
|
|
16
|
+
|
|
17
|
+
This example embeds a block with no data sources and supplies fixed demo context. Replace
|
|
18
|
+
`https://blocks.example.com/hello` with your block's URL. Serve the block from a different origin
|
|
19
|
+
than the embedding application.
|
|
16
20
|
|
|
17
21
|
```ts
|
|
18
22
|
import { createCustomBlockHost } from "@notionhq/custom-blocks-host"
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
function mountCustomBlock(container: HTMLElement, blockUrl: URL): () => void {
|
|
25
|
+
if (
|
|
26
|
+
!["http:", "https:"].includes(blockUrl.protocol) ||
|
|
27
|
+
blockUrl.origin === window.location.origin
|
|
28
|
+
) {
|
|
29
|
+
throw new Error("The block needs an HTTP or HTTPS URL on a separate origin")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const wrapper = document.createElement("section")
|
|
33
|
+
const status = document.createElement("p")
|
|
34
|
+
status.setAttribute("role", "status")
|
|
35
|
+
status.textContent = "Loading block…"
|
|
36
|
+
const iframe = document.createElement("iframe")
|
|
37
|
+
iframe.title = "Hello custom block"
|
|
38
|
+
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin")
|
|
39
|
+
iframe.allow = "clipboard-write"
|
|
40
|
+
iframe.style.width = "100%"
|
|
41
|
+
iframe.style.height = "300px"
|
|
42
|
+
iframe.style.visibility = "hidden"
|
|
43
|
+
wrapper.append(status, iframe)
|
|
44
|
+
container.append(wrapper)
|
|
45
|
+
|
|
46
|
+
function setHeight(height: number) {
|
|
47
|
+
iframe.style.height = `${Math.min(1200, Math.max(120, height))}px`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const host = createCustomBlockHost({
|
|
51
|
+
iframe,
|
|
52
|
+
sandboxUrl: blockUrl.href,
|
|
53
|
+
manifestSource: "host",
|
|
54
|
+
getPersistedManifest: async () => ({
|
|
41
55
|
status: "success",
|
|
42
|
-
|
|
43
|
-
hasMore: false,
|
|
56
|
+
manifest: { version: 1, dataSources: {} },
|
|
44
57
|
}),
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
58
|
+
prepareInitialState: async () => ({
|
|
59
|
+
status: "success",
|
|
60
|
+
initialState: {
|
|
61
|
+
theme: "light",
|
|
62
|
+
contrastMode: "standard",
|
|
63
|
+
blockId: "11111111-1111-4111-8111-111111111111",
|
|
64
|
+
parent: {
|
|
65
|
+
type: "page_id",
|
|
66
|
+
page_id: "22222222-2222-4222-8222-222222222222",
|
|
67
|
+
},
|
|
68
|
+
page: {
|
|
69
|
+
type: "page",
|
|
70
|
+
id: "22222222-2222-4222-8222-222222222222",
|
|
71
|
+
parent: { type: "workspace", workspace: true },
|
|
72
|
+
},
|
|
73
|
+
currentUser: {
|
|
74
|
+
object: "user",
|
|
75
|
+
id: "33333333-3333-4333-8333-333333333333",
|
|
76
|
+
name: "Demo viewer",
|
|
77
|
+
avatar_url: null,
|
|
78
|
+
type: "person",
|
|
79
|
+
person: { email: "viewer@example.com" },
|
|
80
|
+
},
|
|
81
|
+
dataSources: { bindings: {} },
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
handlers: {
|
|
85
|
+
queryDataSource: () => ({
|
|
86
|
+
status: "error",
|
|
87
|
+
error: {
|
|
88
|
+
code: "unknown_data_source_key",
|
|
89
|
+
message: "This demo has no data sources.",
|
|
90
|
+
isRetryable: false,
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
resize: message => setHeight(message.height),
|
|
94
|
+
},
|
|
95
|
+
onStatusChange: state => {
|
|
96
|
+
if (state.status === "initialized") {
|
|
97
|
+
setHeight(state.initialHeight ?? 300)
|
|
98
|
+
status.hidden = true
|
|
99
|
+
iframe.style.visibility = "visible"
|
|
100
|
+
} else if (state.status === "failed") {
|
|
101
|
+
iframe.style.visibility = "hidden"
|
|
102
|
+
status.hidden = false
|
|
103
|
+
status.textContent = `Block failed: ${state.error.code}`
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onQueryUnsubscribed: undefined,
|
|
107
|
+
})
|
|
95
108
|
|
|
96
|
-
|
|
109
|
+
// The host must listen before the block starts its handshake.
|
|
110
|
+
iframe.src = blockUrl.href
|
|
97
111
|
|
|
98
|
-
|
|
112
|
+
return () => {
|
|
113
|
+
host.stop()
|
|
114
|
+
wrapper.remove()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
99
117
|
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
const dispose = mountCustomBlock(document.body, new URL("https://blocks.example.com/hello"))
|
|
119
|
+
window.addEventListener("pagehide", dispose, { once: true })
|
|
102
120
|
```
|
|
103
121
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
The first observed iframe `load` is allowed. A second load stops the host and reports retryable
|
|
108
|
-
`iframe_reloaded`. Create a new host and iframe to retry initialization or replace the block URL.
|
|
109
|
-
|
|
110
|
-
Stopping removes listeners, cancels preparation, clears timers, ends query subscriptions, and
|
|
111
|
-
prevents further outbound messages, including pending responses. Call `stop()` when the iframe is
|
|
112
|
-
removed.
|
|
113
|
-
|
|
114
|
-
Load-event cleanup does not isolate documents before that event. A replacement document at the same
|
|
115
|
-
origin can receive messages and invoke handlers until the host stops.
|
|
116
|
-
|
|
117
|
-
All handshake timeouts default to five seconds:
|
|
118
|
-
|
|
119
|
-
| Option | Waits for | Failure code |
|
|
120
|
-
| ----------------------- | --------------------------------------- | ----------------------- |
|
|
121
|
-
| `noConnectTimeoutMs` | `connect` after the iframe's first load | `no_connect` |
|
|
122
|
-
| `initialStateTimeoutMs` | State preparation after `connect` | `initial_state_timeout` |
|
|
123
|
-
| `noInitResultTimeoutMs` | `initResult` after `init` | `no_init_result` |
|
|
124
|
-
|
|
125
|
-
The local manifest fetch has its own five-second timeout, starting when the host is created. The SDK
|
|
126
|
-
waits for `init` without its own timeout. Handshake failures abort preparation and suppress late
|
|
127
|
-
results. Asynchronous callbacks must respect their `signal`.
|
|
128
|
-
|
|
129
|
-
`minBridgeProtocolVersion` defaults to the runtime's minimum supported version. A higher value
|
|
130
|
-
rejects SDKs below that minimum. A lower value cannot enable unsupported versions. The host does not
|
|
131
|
-
enforce a maximum protocol version.
|
|
122
|
+
You should see “Loading block…” until the block completes initialization, then the block iframe. A
|
|
123
|
+
connection failure displays its error code. The example limits the iframe height to 120–1,200 CSS
|
|
124
|
+
pixels.
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
Call `dispose()` when your application removes the embed. To retry a failed connection or change the
|
|
127
|
+
block URL, dispose of the current embed and call `mountCustomBlock()` again.
|
|
135
128
|
|
|
136
|
-
|
|
129
|
+
For a production integration, replace the demo context and manifest with your application's values.
|
|
130
|
+
Supply data-source bindings and handlers for the APIs your block uses. Your application must enforce
|
|
131
|
+
permissions and record access.
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
height is optional.
|
|
140
|
-
- `onConnectionFailure(error)` reports a handshake failure, timeout, unavailable page context, or
|
|
141
|
-
iframe reload. The error contains `{ phase, source, code, message, isRetryable }`. `phase` is
|
|
142
|
-
`connect`, `init`, `initResult`, or `runtime`. `source` identifies the host or sandbox that
|
|
143
|
-
reported the failure. This callback can run after initialization succeeds.
|
|
144
|
-
- `onQueryUnsubscribed(subscriptionId)` releases application resources when a subscription ends. The
|
|
145
|
-
host removes the subscription itself. The callback runs for unsubscribe, replacement, terminal
|
|
146
|
-
error, or host stop, once per ended subscription.
|
|
147
|
-
- `onLog(direction, payload)` receives bridge messages and warnings. The embedding application
|
|
148
|
-
chooses where to record them.
|
|
133
|
+
To connect workspace data, see [Connect a data source](docs/handlers.md#connect-a-data-source).
|
|
149
134
|
|
|
150
|
-
|
|
135
|
+
## Guides and reference
|
|
151
136
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
137
|
+
- [Initialization and lifecycle](docs/lifecycle.md): manifests, context, timeouts, live state, and
|
|
138
|
+
cleanup.
|
|
139
|
+
- [Handlers and data](docs/handlers.md): application handlers, data-source integration, queries, and
|
|
140
|
+
navigation.
|
|
141
|
+
- [Host compatibility](docs/compatibility.md): supported versions and response conversions.
|
|
155
142
|
|
|
156
|
-
|
|
157
|
-
|
|
143
|
+
The runtime handles the wire handshake and message validation. The shared protocol references cover
|
|
144
|
+
payload semantics, version rules, and contract history:
|
|
158
145
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
defaults. ID brands distinguish ID kinds in TypeScript; they do not check record existence or
|
|
163
|
-
access. The embedding application enforces permissions and record access.
|
|
146
|
+
- [Wire protocol](docs/bridge/protocol.md)
|
|
147
|
+
- [Protocol versioning](docs/bridge/versioning.md)
|
|
148
|
+
- [Protocol changelog](docs/bridge/changelog.md)
|
|
164
149
|
|
|
165
|
-
|
|
150
|
+
## Protocol schemas and types
|
|
166
151
|
|
|
167
|
-
The
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
Sorts retain their order and contain at most ten unique properties.
|
|
152
|
+
The `/protocol` entrypoint exposes the protocol definitions bundled with this host release. It
|
|
153
|
+
provides message schemas and types, data shapes, IDs, error definitions, and protocol-version
|
|
154
|
+
constants.
|
|
171
155
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
The `openExternalUrl` handler receives an `AbortSignal` and a normalized, absolute HTTP or HTTPS URL
|
|
175
|
-
without credentials, limited to 2,048 JavaScript code units before and after normalization. Adapters
|
|
176
|
-
display the exact URL, obtain approval, and navigate only after approval. They may apply additional
|
|
177
|
-
URL restrictions and should dismiss confirmation UI when the signal aborts on stop or iframe reload.
|
|
178
|
-
|
|
179
|
-
Each iframe permits one pending external-navigation request. A different request receives
|
|
180
|
-
`pending_navigation`; a duplicate of the active request is ignored. Every completed request is
|
|
181
|
-
forgotten, so a subsequent request requires fresh approval. Results are suppressed after stop. The
|
|
182
|
-
runtime redacts `openExternalUrl.url` from `onLog` payloads.
|
|
183
|
-
|
|
184
|
-
### Initialization and malformed messages
|
|
185
|
-
|
|
186
|
-
The host validates inbound messages, correlates handshake IDs, and rejects malformed requests.
|
|
187
|
-
Malformed messages do not restart initialization. The host logs and ignores stale valid `initResult`
|
|
188
|
-
messages.
|
|
189
|
-
|
|
190
|
-
The runtime owns the wire handshake and message validation. Integrators use the callbacks and
|
|
191
|
-
handlers above; they do not need to construct or validate bridge messages themselves.
|
|
192
|
-
|
|
193
|
-
## Updating live state
|
|
194
|
-
|
|
195
|
-
The returned handle exposes `setTheme()`, `setContrastMode()`, `setParent()`, `setPage()`,
|
|
196
|
-
`setDataSources()`, `setCurrentUser()`, `refreshQuery()`, and `stop()`.
|
|
197
|
-
|
|
198
|
-
State updates made during initialization are held until `initResult.success`. Updates after that
|
|
199
|
-
point are sent to the sandbox.
|
|
200
|
-
|
|
201
|
-
`refreshQuery()` re-runs `queryDataSource` for each active subscription with the supplied data
|
|
202
|
-
source ID, preserving its filter, sorts, and limit. Overlapping refreshes queue one follow-up query.
|
|
203
|
-
The running query delivers its result before the follow-up starts.
|
|
204
|
-
|
|
205
|
-
Unsubscribe, replacement, and host stop discard queued refreshes and suppress late results.
|
|
206
|
-
Non-retryable query errors also end the subscription. Retryable errors retain it. A failed query can
|
|
207
|
-
end its subscription while the connection stays active.
|
|
208
|
-
|
|
209
|
-
## Local block URLs
|
|
210
|
-
|
|
211
|
-
`isLocalCustomBlockUrl({ url, hostOrigin }: { url: URL; hostOrigin: string })` accepts HTTP(S) URLs
|
|
212
|
-
on `localhost`, any `.localhost` subdomain, or `127.0.0.1`, without a username or password. It
|
|
213
|
-
rejects URLs on the embedding page's origin and requires a nonempty `hostOrigin`. Pass the embedding
|
|
214
|
-
page's serialized origin, such as `window.location.origin`.
|
|
215
|
-
|
|
216
|
-
Both local manifest fetching and the dev shell use this policy. Existing callers must add the
|
|
217
|
-
required `hostOrigin` argument when adopting this version.
|
|
218
|
-
|
|
219
|
-
## `getAutoBoundPropertyIdsByKey()`
|
|
220
|
-
|
|
221
|
-
`getAutoBoundPropertyIdsByKey()` matches manifest properties to database properties for initial
|
|
222
|
-
bindings. A candidate must have the same property type and either:
|
|
223
|
-
|
|
224
|
-
- An ID that exactly equals the manifest key, without trimming or case folding.
|
|
225
|
-
- A display name that equals the manifest display name after trimming and lowercasing.
|
|
226
|
-
|
|
227
|
-
Exactly one candidate produces a binding. Zero or multiple candidates leave the property unmapped.
|
|
156
|
+
Import these definitions through the host package to use the protocol version shipped with that
|
|
157
|
+
host:
|
|
228
158
|
|
|
229
159
|
```ts
|
|
230
|
-
import {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
title: { name: "Task", type: "title" },
|
|
235
|
-
estimate: { name: "Estimate", type: "number" },
|
|
236
|
-
},
|
|
237
|
-
propertySchemasById: {
|
|
238
|
-
title: { name: "Different label", type: "title" },
|
|
239
|
-
"property-1": { name: " estimate ", type: "number" },
|
|
240
|
-
},
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
// { title: "title", estimate: "property-1" }
|
|
160
|
+
import {
|
|
161
|
+
sandboxToHostMessageSchema,
|
|
162
|
+
type SandboxToHostMessage,
|
|
163
|
+
} from "@notionhq/custom-blocks-host/protocol"
|
|
244
164
|
```
|
|
245
165
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
The published package includes `dist/browser.js`, a single ES module with all dependencies. Load
|
|
249
|
-
this file directly when the browser must not fetch additional modules, such as under an exact-URL
|
|
250
|
-
Content Security Policy.
|
|
251
|
-
|
|
252
|
-
## Wire protocol
|
|
166
|
+
`LATEST_BRIDGE_PROTOCOL_VERSION` identifies the latest bridge protocol version defined by the
|
|
167
|
+
bundled protocol.
|
|
253
168
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
included in the package; no separate protocol dependency is needed.
|
|
169
|
+
Host APIs, configuration, handler results, and `*MessageInput` types are available from
|
|
170
|
+
`@notionhq/custom-blocks-host`.
|
|
257
171
|
|
|
258
|
-
|
|
172
|
+
These schemas validate wire payloads. Your application still enforces permissions.
|
|
259
173
|
|
|
260
|
-
|
|
261
|
-
`CustomBlockDateValue`, including reminders. Conversion failures throw `InvalidNotionDateError`.
|
|
262
|
-
|
|
263
|
-
## Other exports
|
|
264
|
-
|
|
265
|
-
- `LATEST_BRIDGE_PROTOCOL_VERSION`: the latest bridge protocol version bundled with this host
|
|
266
|
-
package.
|
|
267
|
-
- `isLocalCustomBlockUrl()`: checks whether a URL can serve a local custom block over HTTP or HTTPS.
|
|
174
|
+
## Standalone browser module
|
|
268
175
|
|
|
269
|
-
|
|
270
|
-
|
|
176
|
+
`dist/browser.js` is one ES module with all dependencies. Use it when the browser must not fetch
|
|
177
|
+
additional modules, such as under an exact-URL Content Security Policy.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Fabian Hiller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -4,8 +4,8 @@ export type AutoBindableProperty = {
|
|
|
4
4
|
type: NotionPropertyType;
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Returns a map from manifest property keys to database property IDs.
|
|
8
|
+
* Unmapped keys are omitted.
|
|
9
9
|
*
|
|
10
10
|
* For each manifest property:
|
|
11
11
|
* 1. Consider only schema properties of the same type.
|
|
@@ -13,6 +13,9 @@ export type AutoBindableProperty = {
|
|
|
13
13
|
* (exact string: no trim, no case folding) or its display name equals
|
|
14
14
|
* the manifest display name after `trim()` and lowercasing.
|
|
15
15
|
* 3. Bind when there is exactly one candidate. Otherwise leave it unmapped.
|
|
16
|
+
*
|
|
17
|
+
* An ID match has no priority over a display name match. If they identify two
|
|
18
|
+
* different properties of the same type, the manifest property stays unmapped.
|
|
16
19
|
*/
|
|
17
20
|
export declare function getAutoBoundPropertyIdsByKey(args: {
|
|
18
21
|
manifestProperties: Readonly<Record<string, AutoBindableProperty>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoBindProperties.d.ts","sourceRoot":"","sources":["../src/autoBindProperties.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAA;AAExG,MAAM,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,kBAAkB,CAAA;CACxB,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"autoBindProperties.d.ts","sourceRoot":"","sources":["../src/autoBindProperties.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAA;AAExG,MAAM,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,kBAAkB,CAAA;CACxB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IAClD,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAA;IAClE,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAA;CACnE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBzB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Returns a map from manifest property keys to database property IDs.
|
|
3
|
+
* Unmapped keys are omitted.
|
|
4
4
|
*
|
|
5
5
|
* For each manifest property:
|
|
6
6
|
* 1. Consider only schema properties of the same type.
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
* (exact string: no trim, no case folding) or its display name equals
|
|
9
9
|
* the manifest display name after `trim()` and lowercasing.
|
|
10
10
|
* 3. Bind when there is exactly one candidate. Otherwise leave it unmapped.
|
|
11
|
+
*
|
|
12
|
+
* An ID match has no priority over a display name match. If they identify two
|
|
13
|
+
* different properties of the same type, the manifest property stays unmapped.
|
|
11
14
|
*/
|
|
12
15
|
export function getAutoBoundPropertyIdsByKey(args) {
|
|
13
16
|
const { manifestProperties, propertySchemasById } = args;
|