@notionhq/custom-blocks 0.1.34 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/dist/autoResize.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.d.ts +1 -0
- package/dist/bridge/SandboxBridge.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.js +256 -221
- package/dist/bridge/appearance.d.ts.map +1 -1
- package/dist/bridge/dataSources/query.d.ts +2 -1
- package/dist/bridge/dataSources/query.d.ts.map +1 -1
- package/dist/bridge/dataSources/query.js +296 -161
- package/dist/bridge/dataSources/resolve.d.ts.map +1 -1
- package/dist/bridge/dataSources/resolveProperty.d.ts.map +1 -1
- package/dist/bridge/hostState.d.ts.map +1 -1
- package/dist/bridge/loadManifest.d.ts.map +1 -1
- package/dist/bridge/pendingRequests.d.ts.map +1 -1
- package/dist/bridge/sandboxClient.d.ts.map +1 -1
- package/dist/customBlock.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +1 -1
- package/dist/protocol/contrast.d.ts +0 -1
- package/dist/protocol/dataSources/dataSource.d.ts +0 -1
- package/dist/protocol/dataSources/dataSourcePage.d.ts +0 -1
- package/dist/protocol/dataSources/dataSourceValue.d.ts +0 -1
- package/dist/protocol/dataSources/dateValue.d.ts +0 -1
- package/dist/protocol/dataSources/errors.d.ts +0 -1
- package/dist/protocol/dataSources/propertySchema.d.ts +7 -1
- package/dist/protocol/dataSources/propertySchema.js +17 -0
- package/dist/protocol/dataSources/recordPointer.d.ts +0 -1
- package/dist/protocol/errors.d.ts +0 -1
- package/dist/protocol/ids.d.ts +0 -1
- package/dist/protocol/incomingType.d.ts +0 -1
- package/dist/protocol/index.d.ts +0 -1
- package/dist/protocol/manifest.d.ts +0 -1
- package/dist/protocol/messagePayload.d.ts +0 -1
- package/dist/protocol/messages/connect.d.ts +0 -1
- package/dist/protocol/messages/contrastModeChanged.d.ts +0 -1
- package/dist/protocol/messages/createPage.d.ts +0 -1
- package/dist/protocol/messages/createPage.js +0 -1
- package/dist/protocol/messages/createPageResult.d.ts +0 -1
- package/dist/protocol/messages/currentUserChanged.d.ts +0 -1
- package/dist/protocol/messages/dataSourcesChanged.d.ts +0 -1
- package/dist/protocol/messages/getPage.d.ts +0 -1
- package/dist/protocol/messages/getUser.d.ts +0 -1
- package/dist/protocol/messages/hostToSandbox.d.ts +3 -1
- package/dist/protocol/messages/init.d.ts +0 -1
- package/dist/protocol/messages/initResult.d.ts +0 -1
- package/dist/protocol/messages/invalidHostMessage.d.ts +0 -1
- package/dist/protocol/messages/invalidSandboxMessage.d.ts +0 -1
- package/dist/protocol/messages/listUsers.d.ts +0 -1
- package/dist/protocol/messages/pageChanged.d.ts +0 -1
- package/dist/protocol/messages/parentChanged.d.ts +0 -1
- package/dist/protocol/messages/queryDataSource.d.ts +15 -1
- package/dist/protocol/messages/queryDataSource.js +8 -0
- package/dist/protocol/messages/queryDataSourceResult.d.ts +1 -2
- package/dist/protocol/messages/resize.d.ts +0 -1
- package/dist/protocol/messages/sandboxToHost.d.ts +4 -1
- package/dist/protocol/messages/themeChanged.d.ts +0 -1
- package/dist/protocol/messages/updatePage.d.ts +0 -1
- package/dist/protocol/messages/updatePageResult.d.ts +0 -1
- package/dist/protocol/pages/page.d.ts +0 -1
- package/dist/protocol/pages/page.js +0 -1
- package/dist/protocol/parent.d.ts +0 -1
- package/dist/protocol/protocolVersion.d.ts +0 -1
- package/dist/protocol/theme.d.ts +0 -1
- package/dist/protocol/users/user.d.ts +0 -1
- package/dist/react/DebugMessageLog.d.ts.map +1 -1
- package/dist/react/NotionCustomBlock.css +0 -11
- package/dist/react/NotionCustomBlock.d.ts.map +1 -1
- package/dist/react/NotionCustomBlock.js +14 -3
- package/dist/react/NotionTokenScope.d.ts.map +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/standalonePreview.d.ts.map +1 -1
- package/dist/react/useCustomBlockAutoResize.d.ts.map +1 -1
- package/dist/react/useCustomBlockInit.d.ts.map +1 -1
- package/dist/react/useDataSource.d.ts +1 -1
- package/dist/react/useDataSource.d.ts.map +1 -1
- package/dist/react/useDataSource.js +1 -1
- package/dist/react/useHostState.d.ts.map +1 -1
- package/dist/react/useRuntimeState.d.ts.map +1 -1
- package/dist/testing.d.ts +17 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +13 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/docs/data-sources.md +13 -1
- package/package.json +5 -6
- package/src/bridge/SandboxBridge.ts +49 -5
- package/src/bridge/dataSources/query.ts +394 -170
- package/src/init.ts +2 -1
- package/src/react/NotionCustomBlock.css +0 -11
- package/src/react/NotionCustomBlock.tsx +28 -10
- package/src/react/useDataSource.ts +1 -1
- package/src/testing.ts +26 -0
- package/src/types.ts +8 -1
- package/dist/protocol/contrast.d.ts.map +0 -1
- package/dist/protocol/dataSources/dataSource.d.ts.map +0 -1
- package/dist/protocol/dataSources/dataSourcePage.d.ts.map +0 -1
- package/dist/protocol/dataSources/dataSourceValue.d.ts.map +0 -1
- package/dist/protocol/dataSources/dateValue.d.ts.map +0 -1
- package/dist/protocol/dataSources/errors.d.ts.map +0 -1
- package/dist/protocol/dataSources/propertySchema.d.ts.map +0 -1
- package/dist/protocol/dataSources/recordPointer.d.ts.map +0 -1
- package/dist/protocol/errors.d.ts.map +0 -1
- package/dist/protocol/ids.d.ts.map +0 -1
- package/dist/protocol/incomingType.d.ts.map +0 -1
- package/dist/protocol/index.d.ts.map +0 -1
- package/dist/protocol/manifest.d.ts.map +0 -1
- package/dist/protocol/messagePayload.d.ts.map +0 -1
- package/dist/protocol/messages/connect.d.ts.map +0 -1
- package/dist/protocol/messages/contrastModeChanged.d.ts.map +0 -1
- package/dist/protocol/messages/createPage.d.ts.map +0 -1
- package/dist/protocol/messages/createPageResult.d.ts.map +0 -1
- package/dist/protocol/messages/currentUserChanged.d.ts.map +0 -1
- package/dist/protocol/messages/dataSourcesChanged.d.ts.map +0 -1
- package/dist/protocol/messages/getPage.d.ts.map +0 -1
- package/dist/protocol/messages/getUser.d.ts.map +0 -1
- package/dist/protocol/messages/hostToSandbox.d.ts.map +0 -1
- package/dist/protocol/messages/init.d.ts.map +0 -1
- package/dist/protocol/messages/initResult.d.ts.map +0 -1
- package/dist/protocol/messages/invalidHostMessage.d.ts.map +0 -1
- package/dist/protocol/messages/invalidSandboxMessage.d.ts.map +0 -1
- package/dist/protocol/messages/listUsers.d.ts.map +0 -1
- package/dist/protocol/messages/pageChanged.d.ts.map +0 -1
- package/dist/protocol/messages/parentChanged.d.ts.map +0 -1
- package/dist/protocol/messages/queryDataSource.d.ts.map +0 -1
- package/dist/protocol/messages/queryDataSourceResult.d.ts.map +0 -1
- package/dist/protocol/messages/resize.d.ts.map +0 -1
- package/dist/protocol/messages/sandboxToHost.d.ts.map +0 -1
- package/dist/protocol/messages/themeChanged.d.ts.map +0 -1
- package/dist/protocol/messages/updatePage.d.ts.map +0 -1
- package/dist/protocol/messages/updatePageResult.d.ts.map +0 -1
- package/dist/protocol/pages/page.d.ts.map +0 -1
- package/dist/protocol/parent.d.ts.map +0 -1
- package/dist/protocol/protocolVersion.d.ts.map +0 -1
- package/dist/protocol/theme.d.ts.map +0 -1
- package/dist/protocol/users/user.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -111,7 +111,5 @@ No top-level navigation, `window.open`, or auth redirects. No direct network req
|
|
|
111
111
|
|
|
112
112
|
## Bridge protocol
|
|
113
113
|
|
|
114
|
-
The
|
|
115
|
-
|
|
116
|
-
`@notionhq/custom-blocks-protocol` and `@notionhq/custom-blocks-host` are
|
|
117
|
-
internal workspace packages and are not available to block authors.
|
|
114
|
+
The SDK communicates with Notion through a versioned `postMessage` protocol.
|
|
115
|
+
Use the SDK's public APIs and exported types. Do not send bridge messages directly.
|
package/dist/autoResize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoResize.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"autoResize.d.ts","sourceRoot":"","sources":["../src/autoResize.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAChC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAA;CACtC,GAAG,MAAM,IAAI,CA4Eb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/SandboxBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_CONTRAST_MODE } from "../protocol/contrast.js";
|
|
2
2
|
import { readIncomingType } from "../protocol/incomingType.js";
|
|
3
|
-
import { hostToSandboxMessageSchema } from "../protocol/messages/hostToSandbox.js";
|
|
3
|
+
import { hostToSandboxMessageSchema, } from "../protocol/messages/hostToSandbox.js";
|
|
4
4
|
import { CustomBlockInitializationError, initMessageSchema, } from "../protocol/messages/init.js";
|
|
5
5
|
import { CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION } from "../protocol/protocolVersion.js";
|
|
6
6
|
import * as v from "valibot";
|
|
7
|
+
import { globalPrimedResponsesCache } from "../testing.js";
|
|
7
8
|
import { unreachable } from "../utils.js";
|
|
8
9
|
import { CUSTOM_BLOCKS_SDK_VERSION } from "../version.js";
|
|
9
10
|
import { NOTION_DARK_BACKGROUND_BASE, NOTION_LIGHT_BACKGROUND_BASE, } from "./appearance.js";
|
|
@@ -12,6 +13,14 @@ import { resolveDataSources } from "./dataSources/resolve.js";
|
|
|
12
13
|
import { resolvePropertyWriteMapForDataSource } from "./dataSources/resolveProperty.js";
|
|
13
14
|
import { createEmptyDataSourceQueryState, } from "./hostState.js";
|
|
14
15
|
import { PendingRequests } from "./pendingRequests.js";
|
|
16
|
+
const RESPONSE_TYPE_BY_REQUEST = new Map([
|
|
17
|
+
["getPage", "getPageResult"],
|
|
18
|
+
["createPage", "createPageResult"],
|
|
19
|
+
["updatePage", "updatePageResult"],
|
|
20
|
+
["getUser", "getUserResult"],
|
|
21
|
+
["listUsers", "listUsersResult"],
|
|
22
|
+
["queryDataSource", "queryDataSourceResult"],
|
|
23
|
+
]);
|
|
15
24
|
const INIT_RESULT_TIMER_FALLBACK_MS = 100;
|
|
16
25
|
export class SandboxBridge {
|
|
17
26
|
constructor() {
|
|
@@ -49,226 +58,7 @@ export class SandboxBridge {
|
|
|
49
58
|
if (event.source !== window.parent) {
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
52
|
-
this.
|
|
53
|
-
const parsed = v.safeParse(hostToSandboxMessageSchema, event.data);
|
|
54
|
-
if (!parsed.success) {
|
|
55
|
-
console.warn("[custom-blocks-sdk] ignoring malformed host message", parsed.issues);
|
|
56
|
-
const incomingType = readIncomingType(event.data);
|
|
57
|
-
if (!this.hasReceivedInit &&
|
|
58
|
-
incomingType === "init" &&
|
|
59
|
-
this.initializationId !== undefined &&
|
|
60
|
-
readInitializationId(event.data) === this.initializationId) {
|
|
61
|
-
this.hasReceivedInit = true;
|
|
62
|
-
this.sendInitResultError(invalidInitPayloadError(parsed.issues));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
// Loop guard: never NACK a NACK. Excludes both directions —
|
|
66
|
-
// `invalidSandboxMessage` is what the host normally sends, but
|
|
67
|
-
// a buggy host that echoes our own `invalidHostMessage` back
|
|
68
|
-
// would otherwise spin a NACK feedback loop.
|
|
69
|
-
if (incomingType !== "invalidSandboxMessage" &&
|
|
70
|
-
incomingType !== "invalidHostMessage") {
|
|
71
|
-
const nack = {
|
|
72
|
-
type: "invalidHostMessage",
|
|
73
|
-
reason: formatInvalidHostReason(incomingType, parsed.issues),
|
|
74
|
-
};
|
|
75
|
-
this.postToHost(nack);
|
|
76
|
-
}
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const message = parsed.output;
|
|
80
|
-
// If the host couldn't parse one of our outbound sandbox-to-host messages, it sends back
|
|
81
|
-
// an `invalidSandboxMessage` NACK with a human-readable `reason`. Log it for developer
|
|
82
|
-
// visibility and stop. We don't retry as the sandbox can't recover from a host-side parse
|
|
83
|
-
// failure on its own.
|
|
84
|
-
if (message.type === "invalidSandboxMessage") {
|
|
85
|
-
console.warn("[custom-blocks-sdk] host reported invalid sandbox message:", message.reason);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
// `init` is the only message valid before initialization. Handle it up
|
|
89
|
-
// front so every later case can assume `status === "initialized"`.
|
|
90
|
-
if (message.type === "init") {
|
|
91
|
-
if (message.initializationId !== this.initializationId) {
|
|
92
|
-
console.warn(`[custom-blocks-sdk] ignoring init for unknown initializationId ${message.initializationId}`);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (this.hasReceivedInit) {
|
|
96
|
-
console.warn("[custom-blocks-sdk] ignoring duplicate init message");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
this.hasReceivedInit = true;
|
|
100
|
-
this.applyInit(message, true);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
// Alias to keep TS's narrowed `InitializedHostState` across the switch
|
|
104
|
-
// below. Reading `this.hostState` repeatedly would re-widen it.
|
|
105
|
-
const hostState = this.hostState;
|
|
106
|
-
if (hostState.status !== "initialized") {
|
|
107
|
-
console.warn(`[custom-blocks-sdk] ignoring ${message.type} before init`);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
switch (message.type) {
|
|
111
|
-
case "themeChanged": {
|
|
112
|
-
this.hostState = {
|
|
113
|
-
...hostState,
|
|
114
|
-
theme: message.theme,
|
|
115
|
-
};
|
|
116
|
-
syncDocumentAppearance({
|
|
117
|
-
theme: message.theme,
|
|
118
|
-
contrastMode: hostState.contrastMode,
|
|
119
|
-
});
|
|
120
|
-
this.notify();
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
case "contrastModeChanged": {
|
|
124
|
-
this.hostState = {
|
|
125
|
-
...hostState,
|
|
126
|
-
contrastMode: message.contrastMode,
|
|
127
|
-
};
|
|
128
|
-
syncDocumentAppearance({
|
|
129
|
-
theme: hostState.theme,
|
|
130
|
-
contrastMode: message.contrastMode,
|
|
131
|
-
});
|
|
132
|
-
this.notify();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
case "parentChanged": {
|
|
136
|
-
this.hostState = {
|
|
137
|
-
...hostState,
|
|
138
|
-
parent: message.parent,
|
|
139
|
-
};
|
|
140
|
-
this.notify();
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
case "pageChanged": {
|
|
144
|
-
this.hostState = {
|
|
145
|
-
...hostState,
|
|
146
|
-
page: message.page,
|
|
147
|
-
};
|
|
148
|
-
this.notify();
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
case "currentUserChanged": {
|
|
152
|
-
this.hostState = {
|
|
153
|
-
...hostState,
|
|
154
|
-
currentUser: message.currentUser,
|
|
155
|
-
};
|
|
156
|
-
this.notify();
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
case "dataSourcesChanged": {
|
|
160
|
-
const nextBindings = message.dataSources.bindings;
|
|
161
|
-
const dataSources = reuseDataSourcesForUnchangedBindings({
|
|
162
|
-
previousDataSources: hostState.dataSources,
|
|
163
|
-
previousBindings: this.latestDataSourceBindings,
|
|
164
|
-
nextDataSources: this.isMockState
|
|
165
|
-
? resolveMockDataSources(nextBindings)
|
|
166
|
-
: resolveDataSources({
|
|
167
|
-
manifest: hostState.manifest,
|
|
168
|
-
dataSourceBindings: nextBindings,
|
|
169
|
-
}),
|
|
170
|
-
nextBindings,
|
|
171
|
-
});
|
|
172
|
-
this.latestDataSourceBindings = nextBindings;
|
|
173
|
-
// Drop cached query state for subscriptions whose key no longer exists.
|
|
174
|
-
const nextKeys = new Set(dataSources.map(s => s.key));
|
|
175
|
-
const prunedState = {};
|
|
176
|
-
for (const [subscriptionId, state] of Object.entries(hostState.dataSourceState)) {
|
|
177
|
-
if (nextKeys.has(state.dataSourceKey)) {
|
|
178
|
-
prunedState[subscriptionId] = state;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
this.hostState = {
|
|
182
|
-
...hostState,
|
|
183
|
-
dataSources,
|
|
184
|
-
dataSourceState: prunedState,
|
|
185
|
-
};
|
|
186
|
-
this.notify();
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
case "createPageResult": {
|
|
190
|
-
const result = message.status === "success"
|
|
191
|
-
? { status: "success", page: message.page }
|
|
192
|
-
: { status: "error", error: message.error };
|
|
193
|
-
if (!this.pendingCreatePage.resolve(message.requestId, result)) {
|
|
194
|
-
console.warn(`[custom-blocks-sdk] createPageResult for unknown requestId ${message.requestId}`);
|
|
195
|
-
}
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
case "getPageResult": {
|
|
199
|
-
const result = message.status === "success"
|
|
200
|
-
? { status: "success", page: message.page }
|
|
201
|
-
: { status: "error", error: message.error };
|
|
202
|
-
if (!this.pendingGetPage.resolve(message.requestId, result)) {
|
|
203
|
-
console.warn(`[custom-blocks-sdk] getPageResult for unknown requestId ${message.requestId}`);
|
|
204
|
-
}
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
case "getUserResult": {
|
|
208
|
-
const result = message.status === "success"
|
|
209
|
-
? { status: "success", user: message.user }
|
|
210
|
-
: { status: "error", error: message.error };
|
|
211
|
-
if (!this.pendingGetUser.resolve(message.requestId, result)) {
|
|
212
|
-
console.warn(`[custom-blocks-sdk] getUserResult for unknown requestId ${message.requestId}`);
|
|
213
|
-
}
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
case "listUsersResult": {
|
|
217
|
-
const result = message.status === "success"
|
|
218
|
-
? { status: "success", list: message.list }
|
|
219
|
-
: { status: "error", error: message.error };
|
|
220
|
-
if (!this.pendingListUsers.resolve(message.requestId, result)) {
|
|
221
|
-
console.warn(`[custom-blocks-sdk] listUsersResult for unknown requestId ${message.requestId}`);
|
|
222
|
-
}
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
case "updatePageResult": {
|
|
226
|
-
const result = message.status === "success"
|
|
227
|
-
? { status: "success", page: message.page }
|
|
228
|
-
: { status: "error", error: message.error };
|
|
229
|
-
if (!this.pendingUpdatePage.resolve(message.requestId, result)) {
|
|
230
|
-
console.warn(`[custom-blocks-sdk] updatePageResult for unknown requestId ${message.requestId}`);
|
|
231
|
-
}
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
case "queryDataSourceResult": {
|
|
235
|
-
const currentState = hostState.dataSourceState[message.subscriptionId];
|
|
236
|
-
if (currentState === undefined) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
const queryResult = message.status === "error"
|
|
240
|
-
? {
|
|
241
|
-
items: [],
|
|
242
|
-
hasMore: false,
|
|
243
|
-
error: message.error,
|
|
244
|
-
}
|
|
245
|
-
: {
|
|
246
|
-
items: message.items,
|
|
247
|
-
hasMore: message.hasMore,
|
|
248
|
-
error: undefined,
|
|
249
|
-
};
|
|
250
|
-
this.hostState = {
|
|
251
|
-
...hostState,
|
|
252
|
-
dataSourceState: {
|
|
253
|
-
...hostState.dataSourceState,
|
|
254
|
-
[message.subscriptionId]: {
|
|
255
|
-
dataSourceKey: currentState.dataSourceKey,
|
|
256
|
-
items: queryResult.items,
|
|
257
|
-
isLoading: false,
|
|
258
|
-
hasMore: queryResult.hasMore,
|
|
259
|
-
error: queryResult.error,
|
|
260
|
-
latestLimit: currentState.latestLimit,
|
|
261
|
-
latestQueryIdentity: currentState.latestQueryIdentity,
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
this.notify();
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
default: {
|
|
269
|
-
unreachable(message);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
61
|
+
this.receiveMessage(event.data);
|
|
272
62
|
};
|
|
273
63
|
}
|
|
274
64
|
startListening() {
|
|
@@ -361,6 +151,28 @@ export class SandboxBridge {
|
|
|
361
151
|
this.sendToHost(message);
|
|
362
152
|
}
|
|
363
153
|
sendToHost(message) {
|
|
154
|
+
// Check if the message is a primed response
|
|
155
|
+
const messageType = readIncomingType(message);
|
|
156
|
+
if (messageType !== undefined &&
|
|
157
|
+
typeof message === "object" &&
|
|
158
|
+
message !== null) {
|
|
159
|
+
const responseType = RESPONSE_TYPE_BY_REQUEST.get(messageType);
|
|
160
|
+
const primed = responseType && globalPrimedResponsesCache.get(responseType);
|
|
161
|
+
if (responseType !== undefined && primed !== undefined) {
|
|
162
|
+
globalPrimedResponsesCache.delete(responseType);
|
|
163
|
+
const response = {
|
|
164
|
+
...primed,
|
|
165
|
+
type: responseType,
|
|
166
|
+
...("requestId" in message ? { requestId: message.requestId } : {}),
|
|
167
|
+
...("subscriptionId" in message
|
|
168
|
+
? { subscriptionId: message.subscriptionId }
|
|
169
|
+
: {}),
|
|
170
|
+
};
|
|
171
|
+
queueMicrotask(() => this.receiveMessage(response));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// If no primed response is found, proceed as normal
|
|
364
176
|
this.logMessage("sent", message);
|
|
365
177
|
window.parent.postMessage(message, "*");
|
|
366
178
|
}
|
|
@@ -376,6 +188,228 @@ export class SandboxBridge {
|
|
|
376
188
|
? message.type
|
|
377
189
|
: undefined;
|
|
378
190
|
}
|
|
191
|
+
receiveMessage(data) {
|
|
192
|
+
this.logMessage("received", data);
|
|
193
|
+
const parsed = v.safeParse(hostToSandboxMessageSchema, data);
|
|
194
|
+
if (!parsed.success) {
|
|
195
|
+
console.warn("[custom-blocks-sdk] ignoring malformed host message", parsed.issues);
|
|
196
|
+
const incomingType = readIncomingType(data);
|
|
197
|
+
if (!this.hasReceivedInit &&
|
|
198
|
+
incomingType === "init" &&
|
|
199
|
+
this.initializationId !== undefined &&
|
|
200
|
+
readInitializationId(data) === this.initializationId) {
|
|
201
|
+
this.hasReceivedInit = true;
|
|
202
|
+
this.sendInitResultError(invalidInitPayloadError(parsed.issues));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Loop guard: never NACK a NACK. Excludes both directions —
|
|
206
|
+
// `invalidSandboxMessage` is what the host normally sends, but
|
|
207
|
+
// a buggy host that echoes our own `invalidHostMessage` back
|
|
208
|
+
// would otherwise spin a NACK feedback loop.
|
|
209
|
+
if (incomingType !== "invalidSandboxMessage" &&
|
|
210
|
+
incomingType !== "invalidHostMessage") {
|
|
211
|
+
const nack = {
|
|
212
|
+
type: "invalidHostMessage",
|
|
213
|
+
reason: formatInvalidHostReason(incomingType, parsed.issues),
|
|
214
|
+
};
|
|
215
|
+
this.postToHost(nack);
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const message = parsed.output;
|
|
220
|
+
// If the host couldn't parse one of our outbound sandbox-to-host messages, it sends back
|
|
221
|
+
// an `invalidSandboxMessage` NACK with a human-readable `reason`. Log it for developer
|
|
222
|
+
// visibility and stop. We don't retry as the sandbox can't recover from a host-side parse
|
|
223
|
+
// failure on its own.
|
|
224
|
+
if (message.type === "invalidSandboxMessage") {
|
|
225
|
+
console.warn("[custom-blocks-sdk] host reported invalid sandbox message:", message.reason);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// `init` is the only message valid before initialization. Handle it up
|
|
229
|
+
// front so every later case can assume `status === "initialized"`.
|
|
230
|
+
if (message.type === "init") {
|
|
231
|
+
if (message.initializationId !== this.initializationId) {
|
|
232
|
+
console.warn(`[custom-blocks-sdk] ignoring init for unknown initializationId ${message.initializationId}`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (this.hasReceivedInit) {
|
|
236
|
+
console.warn("[custom-blocks-sdk] ignoring duplicate init message");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
this.hasReceivedInit = true;
|
|
240
|
+
this.applyInit(message, true);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
// Alias to keep TS's narrowed `InitializedHostState` across the switch
|
|
244
|
+
// below. Reading `this.hostState` repeatedly would re-widen it.
|
|
245
|
+
const hostState = this.hostState;
|
|
246
|
+
if (hostState.status !== "initialized") {
|
|
247
|
+
console.warn(`[custom-blocks-sdk] ignoring ${message.type} before init`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
switch (message.type) {
|
|
251
|
+
case "themeChanged": {
|
|
252
|
+
this.hostState = {
|
|
253
|
+
...hostState,
|
|
254
|
+
theme: message.theme,
|
|
255
|
+
};
|
|
256
|
+
syncDocumentAppearance({
|
|
257
|
+
theme: message.theme,
|
|
258
|
+
contrastMode: hostState.contrastMode,
|
|
259
|
+
});
|
|
260
|
+
this.notify();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
case "contrastModeChanged": {
|
|
264
|
+
this.hostState = {
|
|
265
|
+
...hostState,
|
|
266
|
+
contrastMode: message.contrastMode,
|
|
267
|
+
};
|
|
268
|
+
syncDocumentAppearance({
|
|
269
|
+
theme: hostState.theme,
|
|
270
|
+
contrastMode: message.contrastMode,
|
|
271
|
+
});
|
|
272
|
+
this.notify();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
case "parentChanged": {
|
|
276
|
+
this.hostState = {
|
|
277
|
+
...hostState,
|
|
278
|
+
parent: message.parent,
|
|
279
|
+
};
|
|
280
|
+
this.notify();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
case "pageChanged": {
|
|
284
|
+
this.hostState = {
|
|
285
|
+
...hostState,
|
|
286
|
+
page: message.page,
|
|
287
|
+
};
|
|
288
|
+
this.notify();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
case "currentUserChanged": {
|
|
292
|
+
this.hostState = {
|
|
293
|
+
...hostState,
|
|
294
|
+
currentUser: message.currentUser,
|
|
295
|
+
};
|
|
296
|
+
this.notify();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
case "dataSourcesChanged": {
|
|
300
|
+
const nextBindings = message.dataSources.bindings;
|
|
301
|
+
const dataSources = reuseDataSourcesForUnchangedBindings({
|
|
302
|
+
previousDataSources: hostState.dataSources,
|
|
303
|
+
previousBindings: this.latestDataSourceBindings,
|
|
304
|
+
nextDataSources: this.isMockState
|
|
305
|
+
? resolveMockDataSources(nextBindings)
|
|
306
|
+
: resolveDataSources({
|
|
307
|
+
manifest: hostState.manifest,
|
|
308
|
+
dataSourceBindings: nextBindings,
|
|
309
|
+
}),
|
|
310
|
+
nextBindings,
|
|
311
|
+
});
|
|
312
|
+
this.latestDataSourceBindings = nextBindings;
|
|
313
|
+
// Drop cached query state for subscriptions whose key no longer exists.
|
|
314
|
+
const nextKeys = new Set(dataSources.map(s => s.key));
|
|
315
|
+
const prunedState = {};
|
|
316
|
+
for (const [subscriptionId, state] of Object.entries(hostState.dataSourceState)) {
|
|
317
|
+
if (nextKeys.has(state.dataSourceKey)) {
|
|
318
|
+
prunedState[subscriptionId] = state;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
this.hostState = {
|
|
322
|
+
...hostState,
|
|
323
|
+
dataSources,
|
|
324
|
+
dataSourceState: prunedState,
|
|
325
|
+
};
|
|
326
|
+
this.notify();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
case "createPageResult": {
|
|
330
|
+
const result = message.status === "success"
|
|
331
|
+
? { status: "success", page: message.page }
|
|
332
|
+
: { status: "error", error: message.error };
|
|
333
|
+
if (!this.pendingCreatePage.resolve(message.requestId, result)) {
|
|
334
|
+
console.warn(`[custom-blocks-sdk] createPageResult for unknown requestId ${message.requestId}`);
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
case "getPageResult": {
|
|
339
|
+
const result = message.status === "success"
|
|
340
|
+
? { status: "success", page: message.page }
|
|
341
|
+
: { status: "error", error: message.error };
|
|
342
|
+
if (!this.pendingGetPage.resolve(message.requestId, result)) {
|
|
343
|
+
console.warn(`[custom-blocks-sdk] getPageResult for unknown requestId ${message.requestId}`);
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
case "getUserResult": {
|
|
348
|
+
const result = message.status === "success"
|
|
349
|
+
? { status: "success", user: message.user }
|
|
350
|
+
: { status: "error", error: message.error };
|
|
351
|
+
if (!this.pendingGetUser.resolve(message.requestId, result)) {
|
|
352
|
+
console.warn(`[custom-blocks-sdk] getUserResult for unknown requestId ${message.requestId}`);
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
case "listUsersResult": {
|
|
357
|
+
const result = message.status === "success"
|
|
358
|
+
? { status: "success", list: message.list }
|
|
359
|
+
: { status: "error", error: message.error };
|
|
360
|
+
if (!this.pendingListUsers.resolve(message.requestId, result)) {
|
|
361
|
+
console.warn(`[custom-blocks-sdk] listUsersResult for unknown requestId ${message.requestId}`);
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
case "updatePageResult": {
|
|
366
|
+
const result = message.status === "success"
|
|
367
|
+
? { status: "success", page: message.page }
|
|
368
|
+
: { status: "error", error: message.error };
|
|
369
|
+
if (!this.pendingUpdatePage.resolve(message.requestId, result)) {
|
|
370
|
+
console.warn(`[custom-blocks-sdk] updatePageResult for unknown requestId ${message.requestId}`);
|
|
371
|
+
}
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
case "queryDataSourceResult": {
|
|
375
|
+
const currentState = hostState.dataSourceState[message.subscriptionId];
|
|
376
|
+
if (currentState === undefined) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const queryResult = message.status === "error"
|
|
380
|
+
? {
|
|
381
|
+
items: [],
|
|
382
|
+
hasMore: false,
|
|
383
|
+
error: message.error,
|
|
384
|
+
}
|
|
385
|
+
: {
|
|
386
|
+
items: message.items,
|
|
387
|
+
hasMore: message.hasMore,
|
|
388
|
+
error: undefined,
|
|
389
|
+
};
|
|
390
|
+
this.hostState = {
|
|
391
|
+
...hostState,
|
|
392
|
+
dataSourceState: {
|
|
393
|
+
...hostState.dataSourceState,
|
|
394
|
+
[message.subscriptionId]: {
|
|
395
|
+
dataSourceKey: currentState.dataSourceKey,
|
|
396
|
+
items: queryResult.items,
|
|
397
|
+
isLoading: false,
|
|
398
|
+
hasMore: queryResult.hasMore,
|
|
399
|
+
error: queryResult.error,
|
|
400
|
+
latestLimit: currentState.latestLimit,
|
|
401
|
+
latestQueryIdentity: currentState.latestQueryIdentity,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
this.notify();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
default: {
|
|
409
|
+
unreachable(message);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
379
413
|
subscribe(listener) {
|
|
380
414
|
this.listeners.add(listener);
|
|
381
415
|
return () => this.listeners.delete(listener);
|
|
@@ -580,6 +614,7 @@ export class SandboxBridge {
|
|
|
580
614
|
dataSourceId: query.dataSourceId,
|
|
581
615
|
limit: query.limit,
|
|
582
616
|
...(query.filter !== undefined ? { filter: query.filter } : {}),
|
|
617
|
+
...(query.sorts !== undefined ? { sorts: query.sorts } : {}),
|
|
583
618
|
};
|
|
584
619
|
this.postToHost(outbound);
|
|
585
620
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["../../src/bridge/appearance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,YAAY,CAAA;AACpD,eAAO,MAAM,4BAA4B,YAAY,CAAA"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { NotionDataSource } from "../../protocol/dataSources/dataSource.js";
|
|
2
2
|
import type { NotionDataSourceId } from "../../protocol/ids.js";
|
|
3
|
-
import { type ResolvedCustomBlockDataSourceFilter } from "../../protocol/messages/queryDataSource.js";
|
|
3
|
+
import { type ResolvedCustomBlockDataSourceFilter, type ResolvedCustomBlockDataSourceSort } from "../../protocol/messages/queryDataSource.js";
|
|
4
4
|
import type { UseDataSourceOptions } from "../../types.js";
|
|
5
5
|
export type ResolvedDataSourceQuery = {
|
|
6
6
|
dataSourceId: NotionDataSourceId;
|
|
7
7
|
limit: number;
|
|
8
8
|
filter?: ResolvedCustomBlockDataSourceFilter;
|
|
9
|
+
sorts?: ResolvedCustomBlockDataSourceSort[];
|
|
9
10
|
identity: string;
|
|
10
11
|
};
|
|
11
12
|
export type ResolveDataSourceQueryResult = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/bridge/dataSources/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAA;AAElG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,EAQN,KAAK,mCAAmC,EAExC,KAAK,iCAAiC,EACtC,MAAM,8DAA8D,CAAA;AAErE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAU1D,MAAM,MAAM,uBAAuB,GAAG;IACrC,YAAY,EAAE,kBAAkB,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,mCAAmC,CAAA;IAC5C,KAAK,CAAC,EAAE,iCAAiC,EAAE,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,4BAA4B,GACrC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IACA,MAAM,EAAE,IAAI,CAAA;IACZ,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,uBAAuB,CAAA;CAC7B,CAAA;AAYJ,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC5C,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC,GAAG,4BAA4B,CAmD/B;AAiFD,wBAAgB,iCAAiC,CAChD,OAAO,EAAE,oBAAoB,GAAG,SAAS,GACvC,MAAM,CAMR"}
|