@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
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,259 +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
|
-
|
|
7
|
+
Create the host before navigating the iframe. Pass the full block URL as `sandboxUrl`, and call
|
|
8
|
+
`stop()` when removing the iframe.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
For configuration and lifecycle details, see [Initialization and lifecycle](docs/lifecycle.md).
|
|
11
11
|
|
|
12
|
-
Create a host
|
|
13
|
-
|
|
14
|
-
|
|
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.
|
|
15
20
|
|
|
16
21
|
```ts
|
|
17
22
|
import { createCustomBlockHost } from "@notionhq/custom-blocks-host"
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 () => ({
|
|
40
55
|
status: "success",
|
|
41
|
-
|
|
42
|
-
hasMore: false,
|
|
56
|
+
manifest: { version: 1, dataSources: {} },
|
|
43
57
|
}),
|
|
44
|
-
|
|
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
|
-
|
|
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
|
+
})
|
|
82
108
|
|
|
83
|
-
|
|
109
|
+
// The host must listen before the block starts its handshake.
|
|
110
|
+
iframe.src = blockUrl.href
|
|
84
111
|
|
|
85
|
-
|
|
112
|
+
return () => {
|
|
113
|
+
host.stop()
|
|
114
|
+
wrapper.remove()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
86
117
|
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
const dispose = mountCustomBlock(document.body, new URL("https://blocks.example.com/hello"))
|
|
119
|
+
window.addEventListener("pagehide", dispose, { once: true })
|
|
89
120
|
```
|
|
90
121
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
The first observed iframe `load` is allowed. A second load stops the host and reports retryable
|
|
95
|
-
`iframe_reloaded`. Create a new host and iframe to retry initialization or replace the block URL.
|
|
96
|
-
|
|
97
|
-
Stopping removes listeners, cancels preparation, clears timers, ends query subscriptions, and
|
|
98
|
-
prevents further outbound messages, including pending responses. Call `stop()` when the iframe is
|
|
99
|
-
removed.
|
|
100
|
-
|
|
101
|
-
Load-event cleanup does not isolate documents before that event. A replacement document at the same
|
|
102
|
-
origin can receive messages and invoke handlers until the host stops.
|
|
103
|
-
|
|
104
|
-
All handshake timeouts default to five seconds:
|
|
105
|
-
|
|
106
|
-
| Option | Waits for | Failure code |
|
|
107
|
-
| ----------------------- | --------------------------------------- | ----------------------- |
|
|
108
|
-
| `noConnectTimeoutMs` | `connect` after the iframe's first load | `no_connect` |
|
|
109
|
-
| `initialStateTimeoutMs` | State preparation after `connect` | `initial_state_timeout` |
|
|
110
|
-
| `noInitResultTimeoutMs` | `initResult` after `init` | `no_init_result` |
|
|
111
|
-
|
|
112
|
-
The local manifest fetch has its own five-second timeout, starting when the host is created. The SDK
|
|
113
|
-
waits for `init` without its own timeout. Handshake failures abort preparation and suppress late
|
|
114
|
-
results. Asynchronous callbacks must respect their `signal`.
|
|
115
|
-
|
|
116
|
-
`minBridgeProtocolVersion` defaults to the runtime's minimum supported version. A higher value
|
|
117
|
-
rejects SDKs below that minimum. A lower value cannot enable unsupported versions. The host does not
|
|
118
|
-
enforce a maximum protocol version.
|
|
119
|
-
|
|
120
|
-
Unavailable page context requires protocol 5. With protocols 3 and 4, an unavailable page produces
|
|
121
|
-
`context_unavailable` during initialization or ends an active connection.
|
|
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.
|
|
122
125
|
|
|
123
|
-
|
|
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.
|
|
124
128
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
iframe reload. The error contains `{ phase, source, code, message, isRetryable }`. `phase` is
|
|
129
|
-
`connect`, `init`, `initResult`, or `runtime`. `source` identifies the host or sandbox that
|
|
130
|
-
reported the failure. This callback can run after initialization succeeds.
|
|
131
|
-
- `onQueryUnsubscribed(subscriptionId)` releases application resources when a subscription ends. The
|
|
132
|
-
host removes the subscription itself. The callback runs for unsubscribe, replacement, terminal
|
|
133
|
-
error, or host stop, once per ended subscription.
|
|
134
|
-
- `onLog(direction, payload)` receives bridge messages and warnings. The embedding application
|
|
135
|
-
chooses where to record them.
|
|
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.
|
|
136
132
|
|
|
137
|
-
|
|
133
|
+
To connect workspace data, see [Connect a data source](docs/handlers.md#connect-a-data-source).
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
synchronously or as a promise. Successful results carry their response payload. Errors carry
|
|
141
|
-
`{ code, message, isRetryable }`; error codes are open strings.
|
|
135
|
+
## Guides and reference
|
|
142
136
|
|
|
143
|
-
|
|
144
|
-
|
|
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.
|
|
145
142
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
handler results also accept plain string IDs. The runtime validates these values and applies schema
|
|
149
|
-
defaults. ID brands distinguish ID kinds in TypeScript; they do not check record existence or
|
|
150
|
-
access. The embedding application enforces permissions and record access.
|
|
143
|
+
The runtime handles the wire handshake and message validation. The shared protocol references cover
|
|
144
|
+
payload semantics, version rules, and contract history:
|
|
151
145
|
|
|
152
|
-
|
|
146
|
+
- [Wire protocol](docs/bridge/protocol.md)
|
|
147
|
+
- [Protocol versioning](docs/bridge/versioning.md)
|
|
148
|
+
- [Protocol changelog](docs/bridge/changelog.md)
|
|
153
149
|
|
|
154
|
-
|
|
155
|
-
validates filters and sorts against actual database properties in `collectionSchema.propertiesById`
|
|
156
|
-
before invoking `queryDataSource`. Status group names and option names must match the bound schema.
|
|
157
|
-
Sorts retain their order and contain at most ten unique properties.
|
|
150
|
+
## Protocol schemas and types
|
|
158
151
|
|
|
159
|
-
|
|
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.
|
|
160
155
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
display the exact URL, obtain approval, and navigate only after approval. They may apply additional
|
|
164
|
-
URL restrictions and should dismiss confirmation UI when the signal aborts on stop or iframe reload.
|
|
165
|
-
|
|
166
|
-
Each iframe permits one pending external-navigation request. A different request receives
|
|
167
|
-
`pending_navigation`; a duplicate of the active request is ignored. Every completed request is
|
|
168
|
-
forgotten, so a subsequent request requires fresh approval. Results are suppressed after stop. The
|
|
169
|
-
runtime redacts `openExternalUrl.url` from `onLog` payloads.
|
|
170
|
-
|
|
171
|
-
### Initialization and malformed messages
|
|
172
|
-
|
|
173
|
-
The host validates inbound messages, correlates handshake IDs, and rejects malformed requests.
|
|
174
|
-
Malformed messages do not restart initialization. The host logs and ignores stale valid `initResult`
|
|
175
|
-
messages.
|
|
176
|
-
|
|
177
|
-
See the protocol's [initialization contract](../protocol/README.md#initialization) and
|
|
178
|
-
[validation and error rules](../protocol/README.md#validation-and-errors) for message shapes and
|
|
179
|
-
failure behavior.
|
|
180
|
-
|
|
181
|
-
## Updating live state
|
|
182
|
-
|
|
183
|
-
The returned handle exposes `setTheme()`, `setContrastMode()`, `setParent()`, `setPage()`,
|
|
184
|
-
`setDataSources()`, `setCurrentUser()`, `refreshQuery()`, and `stop()`.
|
|
185
|
-
|
|
186
|
-
State updates made during initialization are held until `initResult.success`. Updates after that
|
|
187
|
-
point are sent to the sandbox.
|
|
188
|
-
|
|
189
|
-
`refreshQuery()` re-runs `queryDataSource` for each active subscription with the supplied data
|
|
190
|
-
source ID, preserving its filter, sorts, and limit. Overlapping refreshes queue one follow-up query.
|
|
191
|
-
The running query delivers its result before the follow-up starts.
|
|
192
|
-
|
|
193
|
-
Unsubscribe, replacement, and host stop discard queued refreshes and suppress late results.
|
|
194
|
-
Non-retryable query errors also end the subscription. Retryable errors retain it. A failed query can
|
|
195
|
-
end its subscription while the connection stays active.
|
|
196
|
-
|
|
197
|
-
## Local block URLs
|
|
198
|
-
|
|
199
|
-
`isLocalCustomBlockUrl({ url, hostOrigin }: { url: URL; hostOrigin: string })` accepts HTTP(S) URLs
|
|
200
|
-
on `localhost`, any `.localhost` subdomain, or `127.0.0.1`, without a username or password. It
|
|
201
|
-
rejects URLs on the embedding page's origin and requires a nonempty `hostOrigin`. Pass the embedding
|
|
202
|
-
page's serialized origin, such as `window.location.origin`.
|
|
203
|
-
|
|
204
|
-
Both local manifest fetching and the dev shell use this policy. Existing callers must add the
|
|
205
|
-
required `hostOrigin` argument when adopting this version.
|
|
206
|
-
|
|
207
|
-
## `getAutoBoundPropertyIdsByKey()`
|
|
208
|
-
|
|
209
|
-
`getAutoBoundPropertyIdsByKey()` matches manifest properties to database properties for initial
|
|
210
|
-
bindings. A candidate must have the same property type and either:
|
|
211
|
-
|
|
212
|
-
- An ID that exactly equals the manifest key, without trimming or case folding.
|
|
213
|
-
- A display name that equals the manifest display name after trimming and lowercasing.
|
|
214
|
-
|
|
215
|
-
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:
|
|
216
158
|
|
|
217
159
|
```ts
|
|
218
|
-
import {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
title: { name: "Task", type: "title" },
|
|
223
|
-
estimate: { name: "Estimate", type: "number" },
|
|
224
|
-
},
|
|
225
|
-
propertySchemasById: {
|
|
226
|
-
title: { name: "Different label", type: "title" },
|
|
227
|
-
"property-1": { name: " estimate ", type: "number" },
|
|
228
|
-
},
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
// { title: "title", estimate: "property-1" }
|
|
160
|
+
import {
|
|
161
|
+
sandboxToHostMessageSchema,
|
|
162
|
+
type SandboxToHostMessage,
|
|
163
|
+
} from "@notionhq/custom-blocks-host/protocol"
|
|
232
164
|
```
|
|
233
165
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
The published package includes `dist/browser.js`, a single ES module with all dependencies. Load
|
|
237
|
-
this file directly when the browser must not fetch additional modules, such as under an exact-URL
|
|
238
|
-
Content Security Policy.
|
|
239
|
-
|
|
240
|
-
## Wire protocol
|
|
166
|
+
`LATEST_BRIDGE_PROTOCOL_VERSION` identifies the latest bridge protocol version defined by the
|
|
167
|
+
bundled protocol.
|
|
241
168
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
files. Runtime source imports schemas from the workspace protocol package; the publish build bundles
|
|
245
|
-
that dependency into the host package.
|
|
169
|
+
Host APIs, configuration, handler results, and `*MessageInput` types are available from
|
|
170
|
+
`@notionhq/custom-blocks-host`.
|
|
246
171
|
|
|
247
|
-
|
|
172
|
+
These schemas validate wire payloads. Your application still enforces permissions.
|
|
248
173
|
|
|
249
|
-
|
|
250
|
-
`CustomBlockDateValue`, including reminders. Conversion failures throw `InvalidNotionDateError`.
|
|
251
|
-
|
|
252
|
-
## Other exports
|
|
253
|
-
|
|
254
|
-
- `LATEST_BRIDGE_PROTOCOL_VERSION`: the latest bridge protocol version bundled with this host
|
|
255
|
-
package.
|
|
256
|
-
- `isLocalCustomBlockUrl()`: checks whether a URL can serve a local custom block over HTTP or HTTPS.
|
|
174
|
+
## Standalone browser module
|
|
257
175
|
|
|
258
|
-
|
|
259
|
-
|
|
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;
|