ncblock 0.0.6 → 0.0.7
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/dist/bridge/SandboxBridge.d.ts +16 -0
- package/dist/bridge/SandboxBridge.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.js +38 -18
- package/dist/bridge/sandboxClient.d.ts +4 -0
- package/dist/bridge/sandboxClient.d.ts.map +1 -1
- package/dist/bridge/sandboxClient.js +6 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +32 -3
- package/docs/lifecycle.md +32 -0
- package/package.json +1 -1
- package/src/bridge/SandboxBridge.ts +53 -18
- package/src/bridge/sandboxClient.ts +11 -1
- package/src/index.ts +6 -1
- package/src/react.tsx +43 -2
|
@@ -10,9 +10,20 @@ import type { InitMessage } from "./messages/init";
|
|
|
10
10
|
* protocol. Increment this number any time a breaking change is made to the bridge protocol.
|
|
11
11
|
*/
|
|
12
12
|
export declare const CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION = 1;
|
|
13
|
+
/**
|
|
14
|
+
* A single entry in the bridge message log. Kept intentionally plain so the log
|
|
15
|
+
* is copy-pasteable to a local coding agent without needing extra context.
|
|
16
|
+
*/
|
|
17
|
+
export type MessageLogEntry = {
|
|
18
|
+
timestamp: string;
|
|
19
|
+
direction: "sent" | "received";
|
|
20
|
+
data: unknown;
|
|
21
|
+
};
|
|
13
22
|
export declare class SandboxBridge {
|
|
14
23
|
private hostState;
|
|
15
24
|
private listeners;
|
|
25
|
+
private messageLog;
|
|
26
|
+
private messageLogListeners;
|
|
16
27
|
private nextRequestId;
|
|
17
28
|
private readonly pendingCreatePage;
|
|
18
29
|
private readonly pendingGetPage;
|
|
@@ -23,8 +34,13 @@ export declare class SandboxBridge {
|
|
|
23
34
|
private readonly initMessage;
|
|
24
35
|
private manifest;
|
|
25
36
|
constructor();
|
|
37
|
+
private static MAX_LOG_ENTRIES;
|
|
38
|
+
private logMessage;
|
|
39
|
+
getMessageLog(): readonly MessageLogEntry[];
|
|
40
|
+
subscribeToMessageLog(listener: () => void): () => boolean;
|
|
26
41
|
awaitInit(signal?: AbortSignal): Promise<InitMessage>;
|
|
27
42
|
sendReady(manifest: CustomBlockManifest | null): void;
|
|
43
|
+
private postToHost;
|
|
28
44
|
private notify;
|
|
29
45
|
private handleMessage;
|
|
30
46
|
subscribe(listener: () => void): () => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/SandboxBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,MAAM,UAAU,CAAA;AAGjB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,KAAK,EACX,+BAA+B,EAC/B,gCAAgC,EAChC,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACN,KAAK,oBAAoB,EAGzB,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAOrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAUlD;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,IAAI,CAAA;AAErD,qBAAa,aAAa;IACzB,OAAO,CAAC,SAAS,CAGhB;IACD,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAEjC;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAE9B;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAE9B;IACD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAEhC;IACD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAEjC;IACD,OAAO,CAAC,WAAW,CAA8C;IACjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAE1B;IACF,OAAO,CAAC,QAAQ,CAAmC;;IAWnD,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBrD,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/SandboxBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,8 @@ export class SandboxBridge {
|
|
|
19
19
|
theme: "light",
|
|
20
20
|
};
|
|
21
21
|
this.listeners = new Set();
|
|
22
|
+
this.messageLog = [];
|
|
23
|
+
this.messageLogListeners = new Set();
|
|
22
24
|
this.nextRequestId = 1;
|
|
23
25
|
this.pendingCreatePage = new PendingRequests("custom-block-create-page");
|
|
24
26
|
this.pendingGetPage = new PendingRequests("custom-block-get-page");
|
|
@@ -42,6 +44,7 @@ export class SandboxBridge {
|
|
|
42
44
|
if (event.source !== window.parent) {
|
|
43
45
|
return;
|
|
44
46
|
}
|
|
47
|
+
this.logMessage("received", event.data);
|
|
45
48
|
const parsed = v.safeParse(hostToSandboxMessageSchema, event.data);
|
|
46
49
|
if (!parsed.success) {
|
|
47
50
|
console.warn("[notion-custom-sdk] ignoring malformed host message", parsed.issues);
|
|
@@ -56,8 +59,7 @@ export class SandboxBridge {
|
|
|
56
59
|
type: "invalidHostMessage",
|
|
57
60
|
reason: formatInvalidHostReason(incomingType, parsed.issues),
|
|
58
61
|
};
|
|
59
|
-
|
|
60
|
-
window.parent.postMessage(nack, "*");
|
|
62
|
+
this.postToHost(nack);
|
|
61
63
|
}
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
@@ -202,6 +204,26 @@ export class SandboxBridge {
|
|
|
202
204
|
window.addEventListener("message", this.handleMessage);
|
|
203
205
|
}
|
|
204
206
|
}
|
|
207
|
+
logMessage(direction, data) {
|
|
208
|
+
if (this.messageLog.length >= SandboxBridge.MAX_LOG_ENTRIES) {
|
|
209
|
+
this.messageLog.shift();
|
|
210
|
+
}
|
|
211
|
+
this.messageLog.push({
|
|
212
|
+
timestamp: new Date().toISOString(),
|
|
213
|
+
direction,
|
|
214
|
+
data,
|
|
215
|
+
});
|
|
216
|
+
for (const listener of this.messageLogListeners) {
|
|
217
|
+
listener();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
getMessageLog() {
|
|
221
|
+
return this.messageLog;
|
|
222
|
+
}
|
|
223
|
+
subscribeToMessageLog(listener) {
|
|
224
|
+
this.messageLogListeners.add(listener);
|
|
225
|
+
return () => this.messageLogListeners.delete(listener);
|
|
226
|
+
}
|
|
205
227
|
awaitInit(signal) {
|
|
206
228
|
if (!signal) {
|
|
207
229
|
return this.initMessage;
|
|
@@ -232,8 +254,12 @@ export class SandboxBridge {
|
|
|
232
254
|
bridgeProtocolVersion: CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION,
|
|
233
255
|
manifest,
|
|
234
256
|
};
|
|
235
|
-
|
|
236
|
-
|
|
257
|
+
this.postToHost(readyMessage);
|
|
258
|
+
}
|
|
259
|
+
postToHost(message) {
|
|
260
|
+
console.debug("[notion-custom-sdk] outbound postMessage", message);
|
|
261
|
+
this.logMessage("sent", message);
|
|
262
|
+
window.parent.postMessage(message, "*");
|
|
237
263
|
}
|
|
238
264
|
subscribe(listener) {
|
|
239
265
|
this.listeners.add(listener);
|
|
@@ -301,8 +327,7 @@ export class SandboxBridge {
|
|
|
301
327
|
key,
|
|
302
328
|
limit,
|
|
303
329
|
};
|
|
304
|
-
|
|
305
|
-
window.parent.postMessage(outbound, "*");
|
|
330
|
+
this.postToHost(outbound);
|
|
306
331
|
}
|
|
307
332
|
postResize(height) {
|
|
308
333
|
if (typeof window === "undefined") {
|
|
@@ -313,8 +338,7 @@ export class SandboxBridge {
|
|
|
313
338
|
type: "resize",
|
|
314
339
|
height: safeHeight,
|
|
315
340
|
};
|
|
316
|
-
|
|
317
|
-
window.parent.postMessage(outbound, "*");
|
|
341
|
+
this.postToHost(outbound);
|
|
318
342
|
}
|
|
319
343
|
createPage(input) {
|
|
320
344
|
return new Promise(resolve => {
|
|
@@ -348,8 +372,7 @@ export class SandboxBridge {
|
|
|
348
372
|
if (input.position !== undefined) {
|
|
349
373
|
outbound.position = input.position;
|
|
350
374
|
}
|
|
351
|
-
|
|
352
|
-
window.parent.postMessage(outbound, "*");
|
|
375
|
+
this.postToHost(outbound);
|
|
353
376
|
});
|
|
354
377
|
}
|
|
355
378
|
getPage(pageId) {
|
|
@@ -360,8 +383,7 @@ export class SandboxBridge {
|
|
|
360
383
|
requestId,
|
|
361
384
|
pageId,
|
|
362
385
|
};
|
|
363
|
-
|
|
364
|
-
window.parent.postMessage(outbound, "*");
|
|
386
|
+
this.postToHost(outbound);
|
|
365
387
|
});
|
|
366
388
|
}
|
|
367
389
|
getUser(userId) {
|
|
@@ -372,8 +394,7 @@ export class SandboxBridge {
|
|
|
372
394
|
requestId,
|
|
373
395
|
userId,
|
|
374
396
|
};
|
|
375
|
-
|
|
376
|
-
window.parent.postMessage(outbound, "*");
|
|
397
|
+
this.postToHost(outbound);
|
|
377
398
|
});
|
|
378
399
|
}
|
|
379
400
|
listUsers(input = {}) {
|
|
@@ -385,8 +406,7 @@ export class SandboxBridge {
|
|
|
385
406
|
startCursor: input.startCursor,
|
|
386
407
|
pageSize: input.pageSize,
|
|
387
408
|
};
|
|
388
|
-
|
|
389
|
-
window.parent.postMessage(outbound, "*");
|
|
409
|
+
this.postToHost(outbound);
|
|
390
410
|
});
|
|
391
411
|
}
|
|
392
412
|
updatePage(input) {
|
|
@@ -420,8 +440,7 @@ export class SandboxBridge {
|
|
|
420
440
|
if (input.archived !== undefined) {
|
|
421
441
|
outbound.archived = input.archived;
|
|
422
442
|
}
|
|
423
|
-
|
|
424
|
-
window.parent.postMessage(outbound, "*");
|
|
443
|
+
this.postToHost(outbound);
|
|
425
444
|
});
|
|
426
445
|
}
|
|
427
446
|
/**
|
|
@@ -498,6 +517,7 @@ export class SandboxBridge {
|
|
|
498
517
|
}
|
|
499
518
|
}
|
|
500
519
|
}
|
|
520
|
+
SandboxBridge.MAX_LOG_ENTRIES = 100;
|
|
501
521
|
function formatInvalidHostReason(incomingType, issues) {
|
|
502
522
|
const labelled = incomingType
|
|
503
523
|
? `host message of type "${incomingType}"`
|
|
@@ -2,6 +2,8 @@ import type { CreatePageInput, CreatePageResult, GetPageResult, GetUserResult, L
|
|
|
2
2
|
import { type CustomBlockHostState, type DataSourceQueryView } from "./hostState";
|
|
3
3
|
import type { CustomBlockManifest } from "./manifest";
|
|
4
4
|
import type { InitMessage } from "./messages/init";
|
|
5
|
+
import { type MessageLogEntry } from "./SandboxBridge";
|
|
6
|
+
export type { MessageLogEntry };
|
|
5
7
|
export declare function sendCustomBlockReady(manifest: CustomBlockManifest | null): void;
|
|
6
8
|
export declare function awaitCustomBlockInit(signal?: AbortSignal): Promise<InitMessage>;
|
|
7
9
|
export declare function subscribeToCustomBlockHost(listener: () => void): () => boolean;
|
|
@@ -15,6 +17,8 @@ export declare function queryCustomBlockDataSource(key: string, limit: number):
|
|
|
15
17
|
*/
|
|
16
18
|
export declare function setMockCustomBlockState(message: InitMessage): void;
|
|
17
19
|
export declare function postCustomBlockResize(height: number): void;
|
|
20
|
+
export declare function getMessageLog(): readonly MessageLogEntry[];
|
|
21
|
+
export declare function subscribeToMessageLog(listener: () => void): () => boolean;
|
|
18
22
|
export declare function getUser(userId: NotionUserId): Promise<GetUserResult>;
|
|
19
23
|
export declare function listUsers(input?: ListUsersInput): Promise<ListUsersResult>;
|
|
20
24
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandboxClient.d.ts","sourceRoot":"","sources":["../../src/bridge/sandboxClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,MAAM,UAAU,CAAA;AACjB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAExB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"sandboxClient.d.ts","sourceRoot":"","sources":["../../src/bridge/sandboxClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,MAAM,UAAU,CAAA;AACjB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAExB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,KAAK,eAAe,EAAiB,MAAM,iBAAiB,CAAA;AAErE,YAAY,EAAE,eAAe,EAAE,CAAA;AAI/B,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,QAExE;AAED,wBAAgB,oBAAoB,CACnC,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAEtB;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,IAAI,iBAE9D;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,CAE9D;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAEpE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,QAE3D;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,QAEnD;AAED,wBAAgB,aAAa,IAAI,SAAS,eAAe,EAAE,CAE1D;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,IAAI,iBAEzD;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAEpE;AAED,wBAAgB,SAAS,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAE1E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,SAAS,EAAE,oBAAoB,EAC/B,GAAG,EAAE,MAAM,GACT,mBAAmB,CAIrB;AAED;;GAEG;AACH,eAAO,MAAM,KAAK;IACjB;;OAEG;kBACW,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIzD;;OAEG;gBACS,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIjD;;OAEG;kBACW,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIzD;;OAEG;mBACY,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAGvD,CAAA"}
|
|
@@ -28,6 +28,12 @@ export function setMockCustomBlockState(message) {
|
|
|
28
28
|
export function postCustomBlockResize(height) {
|
|
29
29
|
bridge.postResize(height);
|
|
30
30
|
}
|
|
31
|
+
export function getMessageLog() {
|
|
32
|
+
return bridge.getMessageLog();
|
|
33
|
+
}
|
|
34
|
+
export function subscribeToMessageLog(listener) {
|
|
35
|
+
return bridge.subscribeToMessageLog(listener);
|
|
36
|
+
}
|
|
31
37
|
export function getUser(userId) {
|
|
32
38
|
return bridge.getUser(userId);
|
|
33
39
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ export type { NotionDataSourceId, NotionSpaceId } from "./bridge/ids";
|
|
|
19
19
|
export type { CustomBlockManifest, ManifestDataSource, ManifestIcon, ManifestProperty, } from "./bridge/manifest";
|
|
20
20
|
export type { NotionCreatePagePosition } from "./bridge/messages/createPage";
|
|
21
21
|
export type { NotionPage, NotionPageCover, NotionPageIcon, NotionPageId, NotionPageParent, NotionPagePropertyInputMap, NotionPagePropertyInputValue, NotionPagePropertyValue, NotionPagePropertyWriteMap, } from "./bridge/pages/page";
|
|
22
|
-
export {
|
|
22
|
+
export type { MessageLogEntry } from "./bridge/sandboxClient";
|
|
23
|
+
export { getMessageLog, pages, subscribeToMessageLog, } from "./bridge/sandboxClient";
|
|
23
24
|
export type { NotionTheme } from "./bridge/theme";
|
|
24
25
|
export { type CustomBlockInitial, type InitCustomBlockOptions, initCustomBlock, NotInIframeError, } from "./init";
|
|
25
26
|
export { NotionCustomBlock, type NotionCustomBlockProps, type UseCustomBlockInitResult, useCustomBlockAutoResize, useCustomBlockContext, useCustomBlockInit, useDataSource, useDataSourceDefinitions, useTheme, } from "./react";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAChE,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,iCAAiC,CAAA;AACxC,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,qCAAqC,CAAA;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAA;AACjF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,qCAAqC,CAAA;AAC5C,YAAY,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAC7E,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrE,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAC5E,YAAY,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,0BAA0B,EAC1B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,qBAAqB,CAAA;AAC5B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAChE,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,iCAAiC,CAAA;AACxC,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,qCAAqC,CAAA;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAA;AACjF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,qCAAqC,CAAA;AAC5C,YAAY,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAC7E,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrE,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAC5E,YAAY,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,0BAA0B,EAC1B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EACN,aAAa,EACb,KAAK,EACL,qBAAqB,GACrB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,eAAe,EACf,gBAAgB,GAChB,MAAM,QAAQ,CAAA;AACf,OAAO,EACN,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACxB,QAAQ,GACR,MAAM,SAAS,CAAA;AAChB,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* downstream code.
|
|
9
9
|
*/
|
|
10
10
|
export { NOTION_BUILTIN_PROPERTY_IDS, NOTION_PROPERTY_TYPES, } from "./bridge/dataSources/propertySchema";
|
|
11
|
-
export { pages } from "./bridge/sandboxClient";
|
|
11
|
+
export { getMessageLog, pages, subscribeToMessageLog, } from "./bridge/sandboxClient";
|
|
12
12
|
export { initCustomBlock, NotInIframeError, } from "./init";
|
|
13
13
|
export { NotionCustomBlock, useCustomBlockAutoResize, useCustomBlockContext, useCustomBlockInit, useDataSource, useDataSourceDefinitions, useTheme, } from "./react";
|
|
14
14
|
export * from "./types";
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EAKd,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EAKd,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAYvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAG3B,MAAM,QAAQ,CAAA;AACf,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAsBlD;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GACjC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACrC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACjC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAEpE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,CAAC,EAAE,sBAAsB,GAC3B,wBAAwB,CA8B1B;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,sBAAsB,GAAG;IAC7D,QAAQ,EAAE,SAAS,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAA;IACzD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,EACjC,QAAQ,EACR,SAAS,EACT,QAAe,EACf,aAAa,EACb,UAAiB,GACjB,EAAE,sBAAsB,2CAoExB;AAwCD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,IAAI,wBAAwB,CAIhE;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,IAAI,WAAW,CAItC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,gBAAgB,EAAE,CAI7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,MAAwC,GACpD,mBAAmB,CAiDrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,GAAE;IACL;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACZ,GACJ,IAAI,CAmCN"}
|
package/dist/react.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs as _jsxs, Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useState, useSyncExternalStore, } from "react";
|
|
3
|
-
import { getCustomBlockHostState, getDataSourceQueryView, postCustomBlockResize, queryCustomBlockDataSource, setMockCustomBlockState, subscribeToCustomBlockHost, } from "./bridge/sandboxClient";
|
|
3
|
+
import { getCustomBlockHostState, getDataSourceQueryView, getMessageLog, postCustomBlockResize, queryCustomBlockDataSource, setMockCustomBlockState, subscribeToCustomBlockHost, subscribeToMessageLog, } from "./bridge/sandboxClient";
|
|
4
4
|
import { initCustomBlock, NotInIframeError, } from "./init";
|
|
5
5
|
const DEFAULT_DATA_SOURCE_QUERY_LIMIT = 20;
|
|
6
6
|
function useCustomBlockHost() {
|
|
@@ -80,6 +80,16 @@ export function NotionCustomBlock({ children, timeoutMs, fallback = null, errorF
|
|
|
80
80
|
useCustomBlockAutoResize({ enabled: autoResize });
|
|
81
81
|
const isStandalone = init.error instanceof NotInIframeError;
|
|
82
82
|
const host = useCustomBlockHost();
|
|
83
|
+
const [debugOpen, setDebugOpen] = useState(false);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const onKeyDown = (e) => {
|
|
86
|
+
if (e.key === "\\") {
|
|
87
|
+
setDebugOpen(prev => !prev);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
window.addEventListener("keydown", onKeyDown);
|
|
91
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
92
|
+
}, []);
|
|
83
93
|
useEffect(() => {
|
|
84
94
|
if (!isStandalone) {
|
|
85
95
|
return;
|
|
@@ -110,13 +120,32 @@ export function NotionCustomBlock({ children, timeoutMs, fallback = null, errorF
|
|
|
110
120
|
if (host.status !== "initialized") {
|
|
111
121
|
return _jsx(_Fragment, { children: fallback });
|
|
112
122
|
}
|
|
113
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { role: "status", style: STANDALONE_BANNER_STYLE, children: "Notion host not detected \u2014 running in standalone preview. SDK hooks return placeholder values until embedded in Notion." }), children] }));
|
|
123
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { role: "status", style: STANDALONE_BANNER_STYLE, children: "Notion host not detected \u2014 running in standalone preview. SDK hooks return placeholder values until embedded in Notion." }), debugOpen ? _jsx(DebugMessageLog, {}) : children] }));
|
|
114
124
|
}
|
|
115
125
|
if (!init.isLoaded) {
|
|
116
126
|
return _jsx(_Fragment, { children: fallback });
|
|
117
127
|
}
|
|
118
|
-
return _jsx(_Fragment, { children: children });
|
|
128
|
+
return _jsx(_Fragment, { children: debugOpen ? _jsx(DebugMessageLog, {}) : children });
|
|
119
129
|
}
|
|
130
|
+
function DebugMessageLog() {
|
|
131
|
+
const log = useSyncExternalStore(subscribeToMessageLog, getMessageLog);
|
|
132
|
+
const text = log
|
|
133
|
+
.map(entry => `[${entry.timestamp}] ${entry.direction}: ${JSON.stringify(entry.data)}`)
|
|
134
|
+
.join("\n");
|
|
135
|
+
return (_jsx("pre", { "data-testid": "debug-message-log", style: DEBUG_PRE_STYLE, children: text || "(no messages yet)" }));
|
|
136
|
+
}
|
|
137
|
+
const DEBUG_PRE_STYLE = {
|
|
138
|
+
margin: 0,
|
|
139
|
+
padding: "8px 12px",
|
|
140
|
+
fontSize: 12,
|
|
141
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
142
|
+
lineHeight: 1.5,
|
|
143
|
+
whiteSpace: "pre-wrap",
|
|
144
|
+
wordBreak: "break-all",
|
|
145
|
+
userSelect: "text",
|
|
146
|
+
background: "#1e1e1e",
|
|
147
|
+
color: "#d4d4d4",
|
|
148
|
+
};
|
|
120
149
|
const STANDALONE_BANNER_STYLE = {
|
|
121
150
|
padding: "8px 12px",
|
|
122
151
|
background: "#fff8e1",
|
package/docs/lifecycle.md
CHANGED
|
@@ -90,3 +90,35 @@ function App() {
|
|
|
90
90
|
return <div>…</div>;
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
|
+
|
|
94
|
+
## Debug console
|
|
95
|
+
|
|
96
|
+
Press `\` while focused in a custom block to toggle a debug overlay that replaces the block's children with a `<pre>` log of every `postMessage` sent and received over the bridge. Each line is formatted as:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
[ISO timestamp] sent/received: {"type":"ready", …}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The log is intentionally plain — no filtering or decoration — so it can be copied and pasted directly to a local coding agent for debugging.
|
|
103
|
+
|
|
104
|
+
### `getMessageLog()`
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
function getMessageLog(): readonly MessageLogEntry[];
|
|
108
|
+
|
|
109
|
+
type MessageLogEntry = {
|
|
110
|
+
timestamp: string;
|
|
111
|
+
direction: "sent" | "received";
|
|
112
|
+
data: unknown;
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Returns the full in-memory log. Entries accumulate for the lifetime of the page.
|
|
117
|
+
|
|
118
|
+
### `subscribeToMessageLog(listener)`
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
function subscribeToMessageLog(listener: () => void): () => void;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Subscribe to new log entries. Compatible with `useSyncExternalStore` for custom debug UIs.
|
package/package.json
CHANGED
|
@@ -50,12 +50,24 @@ import type { NotionUser } from "./users/user"
|
|
|
50
50
|
*/
|
|
51
51
|
export const CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION = 1
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* A single entry in the bridge message log. Kept intentionally plain so the log
|
|
55
|
+
* is copy-pasteable to a local coding agent without needing extra context.
|
|
56
|
+
*/
|
|
57
|
+
export type MessageLogEntry = {
|
|
58
|
+
timestamp: string
|
|
59
|
+
direction: "sent" | "received"
|
|
60
|
+
data: unknown
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
export class SandboxBridge {
|
|
54
64
|
private hostState: CustomBlockHostState = {
|
|
55
65
|
status: "uninitialized",
|
|
56
66
|
theme: "light",
|
|
57
67
|
}
|
|
58
68
|
private listeners = new Set<() => void>()
|
|
69
|
+
private messageLog: MessageLogEntry[] = []
|
|
70
|
+
private messageLogListeners = new Set<() => void>()
|
|
59
71
|
private nextRequestId = 1
|
|
60
72
|
private readonly pendingCreatePage = new PendingRequests<CreatePageResult>(
|
|
61
73
|
"custom-block-create-page",
|
|
@@ -87,6 +99,31 @@ export class SandboxBridge {
|
|
|
87
99
|
}
|
|
88
100
|
}
|
|
89
101
|
|
|
102
|
+
private static MAX_LOG_ENTRIES = 100
|
|
103
|
+
|
|
104
|
+
private logMessage(direction: "sent" | "received", data: unknown) {
|
|
105
|
+
if (this.messageLog.length >= SandboxBridge.MAX_LOG_ENTRIES) {
|
|
106
|
+
this.messageLog.shift()
|
|
107
|
+
}
|
|
108
|
+
this.messageLog.push({
|
|
109
|
+
timestamp: new Date().toISOString(),
|
|
110
|
+
direction,
|
|
111
|
+
data,
|
|
112
|
+
})
|
|
113
|
+
for (const listener of this.messageLogListeners) {
|
|
114
|
+
listener()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getMessageLog(): readonly MessageLogEntry[] {
|
|
119
|
+
return this.messageLog
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
subscribeToMessageLog(listener: () => void) {
|
|
123
|
+
this.messageLogListeners.add(listener)
|
|
124
|
+
return () => this.messageLogListeners.delete(listener)
|
|
125
|
+
}
|
|
126
|
+
|
|
90
127
|
awaitInit(signal?: AbortSignal): Promise<InitMessage> {
|
|
91
128
|
if (!signal) {
|
|
92
129
|
return this.initMessage
|
|
@@ -121,8 +158,13 @@ export class SandboxBridge {
|
|
|
121
158
|
bridgeProtocolVersion: CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION,
|
|
122
159
|
manifest,
|
|
123
160
|
}
|
|
124
|
-
|
|
125
|
-
|
|
161
|
+
this.postToHost(readyMessage)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private postToHost(message: unknown) {
|
|
165
|
+
console.debug("[notion-custom-sdk] outbound postMessage", message)
|
|
166
|
+
this.logMessage("sent", message)
|
|
167
|
+
window.parent.postMessage(message, "*")
|
|
126
168
|
}
|
|
127
169
|
|
|
128
170
|
private notify = () => {
|
|
@@ -139,6 +181,7 @@ export class SandboxBridge {
|
|
|
139
181
|
if (event.source !== window.parent) {
|
|
140
182
|
return
|
|
141
183
|
}
|
|
184
|
+
this.logMessage("received", event.data)
|
|
142
185
|
|
|
143
186
|
const parsed = v.safeParse(hostToSandboxMessageSchema, event.data)
|
|
144
187
|
if (!parsed.success) {
|
|
@@ -159,8 +202,7 @@ export class SandboxBridge {
|
|
|
159
202
|
type: "invalidHostMessage",
|
|
160
203
|
reason: formatInvalidHostReason(incomingType, parsed.issues),
|
|
161
204
|
}
|
|
162
|
-
|
|
163
|
-
window.parent.postMessage(nack, "*")
|
|
205
|
+
this.postToHost(nack)
|
|
164
206
|
}
|
|
165
207
|
return
|
|
166
208
|
}
|
|
@@ -409,8 +451,7 @@ export class SandboxBridge {
|
|
|
409
451
|
key,
|
|
410
452
|
limit,
|
|
411
453
|
}
|
|
412
|
-
|
|
413
|
-
window.parent.postMessage(outbound, "*")
|
|
454
|
+
this.postToHost(outbound)
|
|
414
455
|
}
|
|
415
456
|
|
|
416
457
|
postResize(height: number) {
|
|
@@ -423,8 +464,7 @@ export class SandboxBridge {
|
|
|
423
464
|
type: "resize",
|
|
424
465
|
height: safeHeight,
|
|
425
466
|
}
|
|
426
|
-
|
|
427
|
-
window.parent.postMessage(outbound, "*")
|
|
467
|
+
this.postToHost(outbound)
|
|
428
468
|
}
|
|
429
469
|
|
|
430
470
|
createPage(input: CreatePageInput): Promise<CreatePageResult> {
|
|
@@ -459,8 +499,7 @@ export class SandboxBridge {
|
|
|
459
499
|
if (input.position !== undefined) {
|
|
460
500
|
outbound.position = input.position
|
|
461
501
|
}
|
|
462
|
-
|
|
463
|
-
window.parent.postMessage(outbound, "*")
|
|
502
|
+
this.postToHost(outbound)
|
|
464
503
|
})
|
|
465
504
|
}
|
|
466
505
|
|
|
@@ -472,8 +511,7 @@ export class SandboxBridge {
|
|
|
472
511
|
requestId,
|
|
473
512
|
pageId,
|
|
474
513
|
}
|
|
475
|
-
|
|
476
|
-
window.parent.postMessage(outbound, "*")
|
|
514
|
+
this.postToHost(outbound)
|
|
477
515
|
})
|
|
478
516
|
}
|
|
479
517
|
|
|
@@ -485,8 +523,7 @@ export class SandboxBridge {
|
|
|
485
523
|
requestId,
|
|
486
524
|
userId,
|
|
487
525
|
}
|
|
488
|
-
|
|
489
|
-
window.parent.postMessage(outbound, "*")
|
|
526
|
+
this.postToHost(outbound)
|
|
490
527
|
})
|
|
491
528
|
}
|
|
492
529
|
|
|
@@ -499,8 +536,7 @@ export class SandboxBridge {
|
|
|
499
536
|
startCursor: input.startCursor,
|
|
500
537
|
pageSize: input.pageSize,
|
|
501
538
|
}
|
|
502
|
-
|
|
503
|
-
window.parent.postMessage(outbound, "*")
|
|
539
|
+
this.postToHost(outbound)
|
|
504
540
|
})
|
|
505
541
|
}
|
|
506
542
|
|
|
@@ -539,8 +575,7 @@ export class SandboxBridge {
|
|
|
539
575
|
if (input.archived !== undefined) {
|
|
540
576
|
outbound.archived = input.archived
|
|
541
577
|
}
|
|
542
|
-
|
|
543
|
-
window.parent.postMessage(outbound, "*")
|
|
578
|
+
this.postToHost(outbound)
|
|
544
579
|
})
|
|
545
580
|
}
|
|
546
581
|
|
|
@@ -17,7 +17,9 @@ import {
|
|
|
17
17
|
} from "./hostState"
|
|
18
18
|
import type { CustomBlockManifest } from "./manifest"
|
|
19
19
|
import type { InitMessage } from "./messages/init"
|
|
20
|
-
import { SandboxBridge } from "./SandboxBridge"
|
|
20
|
+
import { type MessageLogEntry, SandboxBridge } from "./SandboxBridge"
|
|
21
|
+
|
|
22
|
+
export type { MessageLogEntry }
|
|
21
23
|
|
|
22
24
|
const bridge = new SandboxBridge()
|
|
23
25
|
|
|
@@ -57,6 +59,14 @@ export function postCustomBlockResize(height: number) {
|
|
|
57
59
|
bridge.postResize(height)
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
export function getMessageLog(): readonly MessageLogEntry[] {
|
|
63
|
+
return bridge.getMessageLog()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function subscribeToMessageLog(listener: () => void) {
|
|
67
|
+
return bridge.subscribeToMessageLog(listener)
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
export function getUser(userId: NotionUserId): Promise<GetUserResult> {
|
|
61
71
|
return bridge.getUser(userId)
|
|
62
72
|
}
|
package/src/index.ts
CHANGED
|
@@ -63,7 +63,12 @@ export type {
|
|
|
63
63
|
NotionPagePropertyValue,
|
|
64
64
|
NotionPagePropertyWriteMap,
|
|
65
65
|
} from "./bridge/pages/page"
|
|
66
|
-
export {
|
|
66
|
+
export type { MessageLogEntry } from "./bridge/sandboxClient"
|
|
67
|
+
export {
|
|
68
|
+
getMessageLog,
|
|
69
|
+
pages,
|
|
70
|
+
subscribeToMessageLog,
|
|
71
|
+
} from "./bridge/sandboxClient"
|
|
67
72
|
export type { NotionTheme } from "./bridge/theme"
|
|
68
73
|
export {
|
|
69
74
|
type CustomBlockInitial,
|
package/src/react.tsx
CHANGED
|
@@ -11,10 +11,12 @@ import type { CustomBlockHostState } from "./bridge/hostState"
|
|
|
11
11
|
import {
|
|
12
12
|
getCustomBlockHostState,
|
|
13
13
|
getDataSourceQueryView,
|
|
14
|
+
getMessageLog,
|
|
14
15
|
postCustomBlockResize,
|
|
15
16
|
queryCustomBlockDataSource,
|
|
16
17
|
setMockCustomBlockState,
|
|
17
18
|
subscribeToCustomBlockHost,
|
|
19
|
+
subscribeToMessageLog,
|
|
18
20
|
} from "./bridge/sandboxClient"
|
|
19
21
|
import type { NotionTheme } from "./bridge/theme"
|
|
20
22
|
import {
|
|
@@ -168,6 +170,17 @@ export function NotionCustomBlock({
|
|
|
168
170
|
useCustomBlockAutoResize({ enabled: autoResize })
|
|
169
171
|
const isStandalone = init.error instanceof NotInIframeError
|
|
170
172
|
const host = useCustomBlockHost()
|
|
173
|
+
const [debugOpen, setDebugOpen] = useState(false)
|
|
174
|
+
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
177
|
+
if (e.key === "\\") {
|
|
178
|
+
setDebugOpen(prev => !prev)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
window.addEventListener("keydown", onKeyDown)
|
|
182
|
+
return () => window.removeEventListener("keydown", onKeyDown)
|
|
183
|
+
}, [])
|
|
171
184
|
|
|
172
185
|
useEffect(() => {
|
|
173
186
|
if (!isStandalone) {
|
|
@@ -212,14 +225,42 @@ export function NotionCustomBlock({
|
|
|
212
225
|
Notion host not detected — running in standalone preview. SDK hooks
|
|
213
226
|
return placeholder values until embedded in Notion.
|
|
214
227
|
</div>
|
|
215
|
-
{children}
|
|
228
|
+
{debugOpen ? <DebugMessageLog /> : children}
|
|
216
229
|
</>
|
|
217
230
|
)
|
|
218
231
|
}
|
|
219
232
|
if (!init.isLoaded) {
|
|
220
233
|
return <>{fallback}</>
|
|
221
234
|
}
|
|
222
|
-
return <>{children}</>
|
|
235
|
+
return <>{debugOpen ? <DebugMessageLog /> : children}</>
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function DebugMessageLog() {
|
|
239
|
+
const log = useSyncExternalStore(subscribeToMessageLog, getMessageLog)
|
|
240
|
+
const text = log
|
|
241
|
+
.map(
|
|
242
|
+
entry =>
|
|
243
|
+
`[${entry.timestamp}] ${entry.direction}: ${JSON.stringify(entry.data)}`,
|
|
244
|
+
)
|
|
245
|
+
.join("\n")
|
|
246
|
+
return (
|
|
247
|
+
<pre data-testid="debug-message-log" style={DEBUG_PRE_STYLE}>
|
|
248
|
+
{text || "(no messages yet)"}
|
|
249
|
+
</pre>
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const DEBUG_PRE_STYLE = {
|
|
254
|
+
margin: 0,
|
|
255
|
+
padding: "8px 12px",
|
|
256
|
+
fontSize: 12,
|
|
257
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
258
|
+
lineHeight: 1.5,
|
|
259
|
+
whiteSpace: "pre-wrap" as const,
|
|
260
|
+
wordBreak: "break-all" as const,
|
|
261
|
+
userSelect: "text" as const,
|
|
262
|
+
background: "#1e1e1e",
|
|
263
|
+
color: "#d4d4d4",
|
|
223
264
|
}
|
|
224
265
|
|
|
225
266
|
const STANDALONE_BANNER_STYLE = {
|