@notionhq/custom-blocks 0.1.42 → 0.1.44
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 +3 -3
- package/dist/bridge/SandboxBridge.d.ts +9 -2
- package/dist/bridge/SandboxBridge.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.js +31 -13
- package/dist/bridge/dataSources/subscribe.d.ts +3 -0
- package/dist/bridge/dataSources/subscribe.d.ts.map +1 -0
- package/dist/bridge/dataSources/subscribe.js +63 -0
- package/dist/bridge/hostState.d.ts.map +1 -1
- package/dist/bridge/hostState.js +8 -5
- package/dist/bridge/notifyListener.d.ts +3 -0
- package/dist/bridge/notifyListener.d.ts.map +1 -0
- package/dist/bridge/notifyListener.js +16 -0
- package/dist/bridge/sandboxClient.d.ts +13 -4
- package/dist/bridge/sandboxClient.d.ts.map +1 -1
- package/dist/bridge/sandboxClient.js +23 -5
- package/dist/customBlock.d.ts +6 -0
- package/dist/customBlock.d.ts.map +1 -1
- package/dist/customBlock.js +6 -0
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/messages/sandboxToHost.d.ts +3 -0
- package/dist/protocol/messages/sandboxToHost.js +2 -0
- package/dist/protocol/messages/unsubscribeDataSourceQuery.d.ts +10 -0
- package/dist/protocol/messages/unsubscribeDataSourceQuery.js +9 -0
- package/dist/react/useDataSource.d.ts.map +1 -1
- package/dist/react/useDataSource.js +26 -29
- package/dist/types.d.ts +29 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/docs/data-sources.md +213 -66
- package/docs/lifecycle.md +1 -11
- package/docs/pages.md +16 -8
- package/docs/users.md +0 -1
- package/package.json +1 -1
- package/src/bridge/SandboxBridge.ts +49 -19
- package/src/bridge/dataSources/subscribe.ts +97 -0
- package/src/bridge/hostState.ts +9 -6
- package/src/bridge/notifyListener.ts +14 -0
- package/src/bridge/sandboxClient.ts +31 -10
- package/src/customBlock.ts +7 -0
- package/src/react/useDataSource.ts +32 -39
- package/src/types.ts +37 -17
package/README.md
CHANGED
|
@@ -124,10 +124,10 @@ Each page covers one API category. Import framework-neutral APIs from
|
|
|
124
124
|
`@notionhq/custom-blocks`. Import React hooks and components from
|
|
125
125
|
`@notionhq/custom-blocks/react`.
|
|
126
126
|
|
|
127
|
-
- [`docs/lifecycle.md`](./docs/lifecycle.md) — `<NotionCustomBlock>`, `useCustomBlockInit`, `initCustomBlock`, `NotInIframeError
|
|
127
|
+
- [`docs/lifecycle.md`](./docs/lifecycle.md) — `<NotionCustomBlock>`, `useCustomBlockInit`, `initCustomBlock`, `NotInIframeError`. The handshake, the React wrapper, sizing.
|
|
128
128
|
- [`docs/block-location.md`](./docs/block-location.md) — `useBlockId`, `useParent`, `usePage`, `useTheme`, `useContrastMode`, `NotionTokenScope`, and `NotionTokenScopeProps`. Where the block sits and how to read the host's appearance.
|
|
129
|
-
- [`docs/data-sources.md`](./docs/data-sources.md) — `useDataSource`, `useManifest`, `customBlock.getManifest`, the row, property, and date-value types, plus a worked example.
|
|
130
|
-
- [`docs/pages.md`](./docs/pages.md) — `pages.create / get / update /
|
|
129
|
+
- [`docs/data-sources.md`](./docs/data-sources.md) — `customBlock.subscribeToDataSource`, `useDataSource`, `useManifest`, `customBlock.getManifest`, the row, property, and date-value types, plus a worked example.
|
|
130
|
+
- [`docs/pages.md`](./docs/pages.md) — `pages.create / get / update / archive / unarchive`, parent variants (including the recommended `data_source_key`), property input shapes.
|
|
131
131
|
- [`docs/users.md`](./docs/users.md) — `users.list / get`, the `NotionUser` shape, paging.
|
|
132
132
|
- [`docs/errors.md`](./docs/errors.md) — request results, error format, error codes, retries, and initialization failures.
|
|
133
133
|
- [`docs/deployment.md`](./docs/deployment.md) — worker-backed deploys, localhost self-hosted fallback, where the manifest comes from.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NotionDataSource } from "../protocol/dataSources/dataSource.js";
|
|
2
2
|
import type { NotionPageId } from "../protocol/ids.js";
|
|
3
3
|
import { type InitMessage } from "../protocol/messages/init.js";
|
|
4
|
-
import type { CreatePageArgs, CreatePageResult, GetPageResult, GetUserResult, ListUsersArgs, ListUsersResult, NotionDataSourcePageUpdateArgs, NotionUserId, UpdatePageArgs, UpdatePageResult
|
|
4
|
+
import type { CreatePageArgs, CreatePageResult, DataSourceQueryOptions, GetPageResult, GetUserResult, ListUsersArgs, ListUsersResult, NotionDataSourcePageUpdateArgs, NotionUserId, UpdatePageArgs, UpdatePageResult } from "../types.js";
|
|
5
5
|
import { type CustomBlockHostState } from "./hostState.js";
|
|
6
6
|
import type { ManifestLoadResult } from "./loadManifest.js";
|
|
7
7
|
/**
|
|
@@ -13,6 +13,13 @@ export type MessageLogEntry = {
|
|
|
13
13
|
direction: "sent" | "received";
|
|
14
14
|
data: unknown;
|
|
15
15
|
};
|
|
16
|
+
export type QueryDataSourceArgs = {
|
|
17
|
+
subscriptionId: string;
|
|
18
|
+
key: string;
|
|
19
|
+
options?: DataSourceQueryOptions;
|
|
20
|
+
/** Send the query even if an identical query is already loading. */
|
|
21
|
+
forceRequery?: boolean;
|
|
22
|
+
};
|
|
16
23
|
export declare class SandboxBridge {
|
|
17
24
|
private hostState;
|
|
18
25
|
private listeners;
|
|
@@ -67,7 +74,7 @@ export declare class SandboxBridge {
|
|
|
67
74
|
*/
|
|
68
75
|
private scheduleInitResult;
|
|
69
76
|
createDataSourceSubscriptionId(): string;
|
|
70
|
-
queryDataSource(subscriptionId
|
|
77
|
+
queryDataSource({ subscriptionId, key, options, forceRequery, }: QueryDataSourceArgs): void;
|
|
71
78
|
private setDataSourceQueryError;
|
|
72
79
|
releaseDataSourceSubscription(subscriptionId: string): void;
|
|
73
80
|
postResize(height: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/SandboxBridge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,gBAAgB,EAEhB,MAAM,4DAA4D,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAA;AAc3E,OAAO,EAEN,KAAK,WAAW,EAEhB,MAAM,mDAAmD,CAAA;
|
|
1
|
+
{"version":3,"file":"SandboxBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/SandboxBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ import { resolveDataSourceQuery } from "./dataSources/query.js";
|
|
|
12
12
|
import { resolveDataSources } from "./dataSources/resolve.js";
|
|
13
13
|
import { resolvePropertyWriteMapForDataSource } from "./dataSources/resolveProperty.js";
|
|
14
14
|
import { createEmptyDataSourceQueryState, } from "./hostState.js";
|
|
15
|
+
import { notifyListener } from "./notifyListener.js";
|
|
15
16
|
import { PendingRequests } from "./pendingRequests.js";
|
|
16
17
|
const RESPONSE_TYPE_BY_REQUEST = new Map([
|
|
17
18
|
["getPage", "getPageResult"],
|
|
@@ -181,7 +182,7 @@ export class SandboxBridge {
|
|
|
181
182
|
}
|
|
182
183
|
notify = () => {
|
|
183
184
|
for (const listener of this.listeners) {
|
|
184
|
-
listener
|
|
185
|
+
notifyListener(listener);
|
|
185
186
|
}
|
|
186
187
|
};
|
|
187
188
|
handleMessage = (event) => {
|
|
@@ -312,13 +313,21 @@ export class SandboxBridge {
|
|
|
312
313
|
nextBindings,
|
|
313
314
|
});
|
|
314
315
|
this.latestDataSourceBindings = nextBindings;
|
|
315
|
-
//
|
|
316
|
-
const
|
|
316
|
+
// Preserve rows only while the key still refers to the same backing data source.
|
|
317
|
+
const previousSourcesByKey = new Map(hostState.dataSources.map(source => [source.key, source]));
|
|
318
|
+
const nextSourcesByKey = new Map(dataSources.map(source => [source.key, source]));
|
|
317
319
|
const prunedState = {};
|
|
318
320
|
for (const [subscriptionId, state] of Object.entries(hostState.dataSourceState)) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
+
const nextSource = nextSourcesByKey.get(state.dataSourceKey);
|
|
322
|
+
if (nextSource === undefined) {
|
|
323
|
+
continue;
|
|
321
324
|
}
|
|
325
|
+
const previousSource = previousSourcesByKey.get(state.dataSourceKey);
|
|
326
|
+
prunedState[subscriptionId] =
|
|
327
|
+
previousSource?.collectionPointer?.id ===
|
|
328
|
+
nextSource.collectionPointer?.id
|
|
329
|
+
? state
|
|
330
|
+
: createEmptyDataSourceQueryState(state.dataSourceKey);
|
|
322
331
|
}
|
|
323
332
|
this.hostState = {
|
|
324
333
|
...hostState,
|
|
@@ -552,7 +561,7 @@ export class SandboxBridge {
|
|
|
552
561
|
createDataSourceSubscriptionId() {
|
|
553
562
|
return `data-source:${globalThis.crypto.randomUUID()}`;
|
|
554
563
|
}
|
|
555
|
-
queryDataSource(subscriptionId, key, options = {}) {
|
|
564
|
+
queryDataSource({ subscriptionId, key, options = {}, forceRequery = false, }) {
|
|
556
565
|
if (this.hostState.status !== "initialized") {
|
|
557
566
|
return;
|
|
558
567
|
}
|
|
@@ -591,7 +600,8 @@ export class SandboxBridge {
|
|
|
591
600
|
return;
|
|
592
601
|
}
|
|
593
602
|
const query = resolvedQuery.query;
|
|
594
|
-
if (
|
|
603
|
+
if (!forceRequery &&
|
|
604
|
+
currentState.isLoading &&
|
|
595
605
|
currentState.latestQueryIdentity === query.identity) {
|
|
596
606
|
return;
|
|
597
607
|
}
|
|
@@ -609,7 +619,6 @@ export class SandboxBridge {
|
|
|
609
619
|
},
|
|
610
620
|
},
|
|
611
621
|
};
|
|
612
|
-
this.notify();
|
|
613
622
|
const outbound = {
|
|
614
623
|
type: "queryDataSource",
|
|
615
624
|
subscriptionId,
|
|
@@ -619,6 +628,7 @@ export class SandboxBridge {
|
|
|
619
628
|
...(query.sorts !== undefined ? { sorts: query.sorts } : {}),
|
|
620
629
|
};
|
|
621
630
|
this.postToHost(outbound);
|
|
631
|
+
this.notify();
|
|
622
632
|
}
|
|
623
633
|
setDataSourceQueryError(subscriptionId, currentState, error) {
|
|
624
634
|
if (this.hostState.status !== "initialized") {
|
|
@@ -649,6 +659,11 @@ export class SandboxBridge {
|
|
|
649
659
|
...this.hostState,
|
|
650
660
|
dataSourceState,
|
|
651
661
|
};
|
|
662
|
+
const outbound = {
|
|
663
|
+
type: "unsubscribeDataSourceQuery",
|
|
664
|
+
subscriptionId,
|
|
665
|
+
};
|
|
666
|
+
this.postToHost(outbound);
|
|
652
667
|
}
|
|
653
668
|
postResize(height) {
|
|
654
669
|
if (typeof window === "undefined") {
|
|
@@ -725,17 +740,20 @@ export class SandboxBridge {
|
|
|
725
740
|
});
|
|
726
741
|
}
|
|
727
742
|
updatePage(args) {
|
|
743
|
+
// Prefer is_archived over the deprecated archived argument.
|
|
744
|
+
// TODO(custom-blocks): Remove the archived fallback when upgrading to bridge protocol v4.
|
|
745
|
+
const isArchived = args.is_archived ?? args.archived;
|
|
728
746
|
return new Promise(resolve => {
|
|
729
747
|
if ((args.properties === undefined ||
|
|
730
748
|
Object.keys(args.properties).length === 0) &&
|
|
731
749
|
args.icon === undefined &&
|
|
732
750
|
args.cover === undefined &&
|
|
733
|
-
|
|
751
|
+
isArchived === undefined) {
|
|
734
752
|
resolve({
|
|
735
753
|
status: "error",
|
|
736
754
|
error: {
|
|
737
755
|
code: "invalid_page_update",
|
|
738
|
-
message: "updatePage requires at least one
|
|
756
|
+
message: "updatePage requires at least one property.",
|
|
739
757
|
isRetryable: false,
|
|
740
758
|
},
|
|
741
759
|
});
|
|
@@ -756,8 +774,8 @@ export class SandboxBridge {
|
|
|
756
774
|
if (args.cover !== undefined) {
|
|
757
775
|
outbound.cover = args.cover;
|
|
758
776
|
}
|
|
759
|
-
if (
|
|
760
|
-
outbound.archived =
|
|
777
|
+
if (isArchived !== undefined) {
|
|
778
|
+
outbound.archived = isArchived;
|
|
761
779
|
}
|
|
762
780
|
this.postToHost(outbound);
|
|
763
781
|
});
|
|
@@ -784,7 +802,7 @@ export class SandboxBridge {
|
|
|
784
802
|
properties: resolvedProperties?.properties,
|
|
785
803
|
icon: pageUpdateArgs.icon,
|
|
786
804
|
cover: pageUpdateArgs.cover,
|
|
787
|
-
|
|
805
|
+
is_archived: pageUpdateArgs.is_archived ?? pageUpdateArgs.archived,
|
|
788
806
|
});
|
|
789
807
|
}
|
|
790
808
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../../src/bridge/dataSources/subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAA;AAQ/D,wBAAgB,qBAAqB,CAAC,EACrC,GAAG,EACH,UAAU,EACV,OAAO,EAAE,eAAoB,GAC7B,EAAE,yBAAyB,GAAG,MAAM,IAAI,CAoFxC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { notifyListener } from "../notifyListener.js";
|
|
2
|
+
import { customBlockDataSources, customBlockHost } from "../sandboxClient.js";
|
|
3
|
+
export function subscribeToDataSource({ key, onSnapshot, options: providedOptions = {}, }) {
|
|
4
|
+
const options = structuredClone(providedOptions);
|
|
5
|
+
const subscriptionId = customBlockDataSources.createSubscriptionId();
|
|
6
|
+
let active = true;
|
|
7
|
+
let lastSnapshotInputs;
|
|
8
|
+
let lastMatchingSignature;
|
|
9
|
+
const deliverSnapshotIfChanged = (hostState, dataSource, queryState) => {
|
|
10
|
+
if (lastSnapshotInputs !== undefined &&
|
|
11
|
+
lastSnapshotInputs.status === hostState.status &&
|
|
12
|
+
lastSnapshotInputs.dataSource === dataSource &&
|
|
13
|
+
lastSnapshotInputs.queryState === queryState) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const snapshot = customBlockDataSources.getView(hostState, key, subscriptionId);
|
|
17
|
+
// Record inputs before calling consumer code, which can trigger another notification.
|
|
18
|
+
lastSnapshotInputs = { status: hostState.status, dataSource, queryState };
|
|
19
|
+
notifyListener(() => onSnapshot(snapshot));
|
|
20
|
+
};
|
|
21
|
+
const handleHostChange = () => {
|
|
22
|
+
if (!active) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const hostState = customBlockHost.getState();
|
|
26
|
+
if (hostState.status !== "initialized") {
|
|
27
|
+
deliverSnapshotIfChanged(hostState, undefined, undefined);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const dataSource = hostState.dataSources.find(source => source.key === key);
|
|
31
|
+
const signature = dataSource === undefined ? null : JSON.stringify(dataSource);
|
|
32
|
+
if (signature !== lastMatchingSignature) {
|
|
33
|
+
const forceRequery = lastMatchingSignature !== undefined;
|
|
34
|
+
lastMatchingSignature = signature;
|
|
35
|
+
// Querying updates SDK state and calls this listener again.
|
|
36
|
+
customBlockDataSources.query({
|
|
37
|
+
subscriptionId,
|
|
38
|
+
key,
|
|
39
|
+
options,
|
|
40
|
+
forceRequery,
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
deliverSnapshotIfChanged(hostState, dataSource, hostState.dataSourceState[subscriptionId]);
|
|
45
|
+
};
|
|
46
|
+
const unsubscribeHost = customBlockHost.subscribe(handleHostChange);
|
|
47
|
+
try {
|
|
48
|
+
handleHostChange();
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
unsubscribeHost();
|
|
52
|
+
customBlockDataSources.release(subscriptionId);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
return () => {
|
|
56
|
+
if (!active) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
active = false;
|
|
60
|
+
unsubscribeHost();
|
|
61
|
+
customBlockDataSources.release(subscriptionId);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostState.d.ts","sourceRoot":"","sources":["../../src/bridge/hostState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAA;AAClG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gEAAgE,CAAA;AAEhH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gEAAgE,CAAA;AAC1G,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AACvF,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,oEAAoE,CAAA;AAC7H,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,KAAK,EACX,oBAAoB,EACpB,8BAA8B,EAC9B,gBAAgB,EAChB,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IACpC,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAClC,MAAM,EAAE,aAAa,CAAA;IACrB,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,UAAU,CAAA;IACvB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CACrD,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAClC,aAAa,EAAE,MAAM,CAAA;IACrB,iGAAiG;IACjG,KAAK,EAAE,0BAA0B,EAAE,CAAA;IACnC,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,mCAAmC,CAAA;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,wBAAgB,+BAA+B,CAC9C,aAAa,EAAE,MAAM,GACnB,oBAAoB,CAOtB;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG;IACjC,KAAK,EAAE,oBAAoB,EAAE,CAAA;IAC7B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IACvD,mBAAmB,EAAE;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAAA;KAAE,CAAA;IACnE,gBAAgB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAA;IACvD,oBAAoB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAAA;KAAE,CAAA;IACzE,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,mCAAmC,CAAA;CAC3C,CAAA;AAWD;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE;IAC3C,UAAU,EAAE,gBAAgB,CAAA;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,cAAc,EAAE,8BAA8B,CAAA;CAC9C,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAA;AAE/B,wBAAgB,sBAAsB,CACrC,SAAS,EAAE,oBAAoB,EAC/B,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,sBAAsB,GAC1C,mBAAmB,
|
|
1
|
+
{"version":3,"file":"hostState.d.ts","sourceRoot":"","sources":["../../src/bridge/hostState.ts"],"names":[],"mappings":"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"}
|
package/dist/bridge/hostState.js
CHANGED
|
@@ -43,17 +43,20 @@ export function getDataSourceQueryView(hostState, key, subscriptionId, updateDat
|
|
|
43
43
|
propertiesByKey[key] =
|
|
44
44
|
propertyId === undefined ? undefined : entry.propertiesById[propertyId];
|
|
45
45
|
}
|
|
46
|
+
const update = (args) => updateDataSourcePage({
|
|
47
|
+
dataSource,
|
|
48
|
+
pageId: entry.id,
|
|
49
|
+
pageUpdateArgs: args,
|
|
50
|
+
});
|
|
46
51
|
return {
|
|
47
52
|
id: entry.id,
|
|
48
53
|
is_archived: entry.is_archived,
|
|
49
54
|
in_trash: entry.in_trash,
|
|
50
55
|
propertiesById: entry.propertiesById,
|
|
51
56
|
propertiesByKey,
|
|
52
|
-
update
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
pageUpdateArgs: args,
|
|
56
|
-
}),
|
|
57
|
+
update,
|
|
58
|
+
archive: () => update({ is_archived: true }),
|
|
59
|
+
unarchive: () => update({ is_archived: false }),
|
|
57
60
|
};
|
|
58
61
|
});
|
|
59
62
|
const propertySchemasByKey = {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifyListener.d.ts","sourceRoot":"","sources":["../../src/bridge/notifyListener.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAYzD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Report consumer errors without interrupting bridge operations or other listeners. */
|
|
2
|
+
export function notifyListener(listener) {
|
|
3
|
+
try {
|
|
4
|
+
listener();
|
|
5
|
+
}
|
|
6
|
+
catch (error) {
|
|
7
|
+
if (typeof globalThis.reportError === "function") {
|
|
8
|
+
globalThis.reportError(error);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
setTimeout(() => {
|
|
12
|
+
throw error;
|
|
13
|
+
}, 0);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { NotionPageId } from "../protocol/ids.js";
|
|
2
2
|
import type { InitMessage } from "../protocol/messages/init.js";
|
|
3
|
-
import type { CreatePageArgs, CreatePageResult, GetPageResult, GetUserResult, ListUsersArgs, ListUsersResult, NotionUserId, UpdatePageArgs, UpdatePageResult
|
|
3
|
+
import type { CreatePageArgs, CreatePageResult, GetPageResult, GetUserResult, ListUsersArgs, ListUsersResult, NotionUserId, UpdatePageArgs, UpdatePageResult } from "../types.js";
|
|
4
4
|
import { type CustomBlockHostState, type DataSourceQueryView } from "./hostState.js";
|
|
5
5
|
import type { ManifestLoadResult } from "./loadManifest.js";
|
|
6
|
-
import { type MessageLogEntry } from "./SandboxBridge.js";
|
|
6
|
+
import { type MessageLogEntry, type QueryDataSourceArgs } from "./SandboxBridge.js";
|
|
7
7
|
export declare const customBlockHost: {
|
|
8
8
|
start: () => void;
|
|
9
9
|
sendConnect: (manifestResult: ManifestLoadResult) => void;
|
|
@@ -20,7 +20,7 @@ export declare const customBlockHost: {
|
|
|
20
20
|
};
|
|
21
21
|
export declare const customBlockDataSources: {
|
|
22
22
|
createSubscriptionId: () => string;
|
|
23
|
-
query: (
|
|
23
|
+
query: (args: QueryDataSourceArgs) => void;
|
|
24
24
|
release: (subscriptionId: string) => void;
|
|
25
25
|
getView: (hostState: CustomBlockHostState, key: string, subscriptionId: string) => DataSourceQueryView;
|
|
26
26
|
};
|
|
@@ -45,7 +45,16 @@ export declare const pages: {
|
|
|
45
45
|
*/
|
|
46
46
|
update: (input: UpdatePageArgs) => Promise<UpdatePageResult>;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
48
|
+
* Archives a page.
|
|
49
|
+
*/
|
|
50
|
+
archive: (pageId: NotionPageId) => Promise<UpdatePageResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Unarchives a page.
|
|
53
|
+
*/
|
|
54
|
+
unarchive: (pageId: NotionPageId) => Promise<UpdatePageResult>;
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated This method archives the page. It does not move the page to Trash.
|
|
57
|
+
* Use `pages.archive(pageId)` instead.
|
|
49
58
|
*/
|
|
50
59
|
delete: (pageId: NotionPageId) => Promise<UpdatePageResult>;
|
|
51
60
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandboxClient.d.ts","sourceRoot":"","sources":["../../src/bridge/sandboxClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mDAAmD,CAAA;AACpF,OAAO,KAAK,EACX,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"sandboxClient.d.ts","sourceRoot":"","sources":["../../src/bridge/sandboxClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mDAAmD,CAAA;AACpF,OAAO,KAAK,EACX,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAExB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAExB,MAAM,oBAAoB,CAAA;AAY3B,eAAO,MAAM,eAAe;IAC3B,KAAK;IAIL,WAAW,mBAAmB,kBAAkB;IAIhD,SAAS,YAAY,WAAW,KAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,SAAS,aAAa,MAAM,IAAI;IAIhC,QAAQ,QAAM,oBAAoB;IAIlC;;;OAGG;IACH,YAAY,YAAY,WAAW;IAInC,sBAAsB;IAItB,UAAU,WAAW,MAAM;CAG3B,CAAA;AAED,eAAO,MAAM,sBAAsB;IAClC,oBAAoB;IAIpB,KAAK,SAAS,mBAAmB;IAIjC,OAAO,mBAAmB,MAAM;IAIhC,OAAO,cACK,oBAAoB,OAC1B,MAAM,kBACK,MAAM,KACpB,mBAAmB;CAQtB,CAAA;AAED,eAAO,MAAM,UAAU;IACtB,WAAW,QAAM,SAAS,eAAe,EAAE;IAI3C,SAAS,aAAa,MAAM,IAAI;CAGhC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,KAAK;IACjB;;OAEG;IACH,MAAM,UAAU,cAAc,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAI1D;;OAEG;IACH,GAAG,WAAW,YAAY,KAAG,OAAO,CAAC,aAAa,CAAC;IAInD;;OAEG;IACH,MAAM,UAAU,cAAc,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAI1D;;OAEG;IACH,OAAO,WAAW,YAAY,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAI1D;;OAEG;IACH,SAAS,WAAW,YAAY,KAAG,OAAO,CAAC,gBAAgB,CAAC;IAI5D;;;OAGG;IACH,MAAM,WAAW,YAAY,KAAG,OAAO,CAAC,gBAAgB,CAAC;CASzD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,KAAK;IACjB;;OAEG;IACH,IAAI,WAAW,aAAa,KAAG,OAAO,CAAC,eAAe,CAAC;IAIvD;;OAEG;IACH,GAAG,WAAW,YAAY,KAAG,OAAO,CAAC,aAAa,CAAC;CAGnD,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getDataSourceQueryView as getDataSourceQueryViewWithBridge, } from "./hostState.js";
|
|
2
|
-
import { SandboxBridge } from "./SandboxBridge.js";
|
|
2
|
+
import { SandboxBridge, } from "./SandboxBridge.js";
|
|
3
3
|
let bridge;
|
|
4
|
+
let didWarnAboutPagesDelete = false;
|
|
4
5
|
function getBridge() {
|
|
5
6
|
if (!bridge) {
|
|
6
7
|
bridge = new SandboxBridge();
|
|
@@ -41,8 +42,8 @@ export const customBlockDataSources = {
|
|
|
41
42
|
createSubscriptionId: () => {
|
|
42
43
|
return getBridge().createDataSourceSubscriptionId();
|
|
43
44
|
},
|
|
44
|
-
query: (
|
|
45
|
-
getBridge().queryDataSource(
|
|
45
|
+
query: (args) => {
|
|
46
|
+
getBridge().queryDataSource(args);
|
|
46
47
|
},
|
|
47
48
|
release: (subscriptionId) => {
|
|
48
49
|
getBridge().releaseDataSourceSubscription(subscriptionId);
|
|
@@ -82,10 +83,27 @@ export const pages = {
|
|
|
82
83
|
return getBridge().updatePage(input);
|
|
83
84
|
},
|
|
84
85
|
/**
|
|
85
|
-
*
|
|
86
|
+
* Archives a page.
|
|
87
|
+
*/
|
|
88
|
+
archive: (pageId) => {
|
|
89
|
+
return getBridge().updatePage({ pageId, is_archived: true });
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Unarchives a page.
|
|
93
|
+
*/
|
|
94
|
+
unarchive: (pageId) => {
|
|
95
|
+
return getBridge().updatePage({ pageId, is_archived: false });
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* @deprecated This method archives the page. It does not move the page to Trash.
|
|
99
|
+
* Use `pages.archive(pageId)` instead.
|
|
86
100
|
*/
|
|
87
101
|
delete: (pageId) => {
|
|
88
|
-
|
|
102
|
+
if (!didWarnAboutPagesDelete) {
|
|
103
|
+
didWarnAboutPagesDelete = true;
|
|
104
|
+
console.warn("[Notion Custom Blocks] DEPRECATED: pages.delete() archives the page. It does not move the page to Trash. Use pages.archive() instead.");
|
|
105
|
+
}
|
|
106
|
+
return getBridge().updatePage({ pageId, is_archived: true });
|
|
89
107
|
},
|
|
90
108
|
};
|
|
91
109
|
/**
|
package/dist/customBlock.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { NotionParent } from "./protocol/parent.js";
|
|
|
7
7
|
import type { NotionTheme } from "./protocol/theme.js";
|
|
8
8
|
import type { NotionUser } from "./protocol/users/user.js";
|
|
9
9
|
import { autoResize } from "./autoResize.js";
|
|
10
|
+
import { subscribeToDataSource } from "./bridge/dataSources/subscribe.js";
|
|
10
11
|
export type CustomBlockState = {
|
|
11
12
|
status: "uninitialized";
|
|
12
13
|
theme: NotionTheme;
|
|
@@ -36,5 +37,10 @@ export declare const customBlock: {
|
|
|
36
37
|
getPage(): CustomBlockPage;
|
|
37
38
|
getManifest(): CustomBlockManifest;
|
|
38
39
|
autoResize: typeof autoResize;
|
|
40
|
+
/**
|
|
41
|
+
* Registers a listener that receives the current query snapshot and later updates.
|
|
42
|
+
* Returns a function that removes this listener. Other listeners remain subscribed.
|
|
43
|
+
*/
|
|
44
|
+
subscribeToDataSource: typeof subscribeToDataSource;
|
|
39
45
|
};
|
|
40
46
|
//# sourceMappingURL=customBlock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customBlock.d.ts","sourceRoot":"","sources":["../src/customBlock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAA;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"customBlock.d.ts","sourceRoot":"","sources":["../src/customBlock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAA;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAA;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AAOzE,MAAM,MAAM,gBAAgB,GACzB;IACA,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;CAC/B,GACD;IACA,MAAM,EAAE,aAAa,CAAA;IACrB,KAAK,EAAE,WAAW,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,UAAU,CAAA;IACvB,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAC9B,CAAA;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW;wBACH,MAAM,IAAI,GAAG,MAAM,IAAI;gBAI/B,gBAAgB;sBAIV,UAAU;gBAIhB,WAAW;uBAIJ,kBAAkB;kBAIvB,aAAa;iBAId,YAAY;eAId,eAAe;mBAIX,mBAAmB;;IAMlC;;;OAGG;;CAEH,CAAA"}
|
package/dist/customBlock.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { autoResize } from "./autoResize.js";
|
|
2
|
+
import { subscribeToDataSource } from "./bridge/dataSources/subscribe.js";
|
|
2
3
|
import { customBlockHost } from "./bridge/sandboxClient.js";
|
|
3
4
|
/**
|
|
4
5
|
* Framework-neutral runtime state APIs for a custom block. Call `initCustomBlock`
|
|
@@ -33,6 +34,11 @@ export const customBlock = {
|
|
|
33
34
|
return getInitializedHostState("getManifest").manifest;
|
|
34
35
|
},
|
|
35
36
|
autoResize,
|
|
37
|
+
/**
|
|
38
|
+
* Registers a listener that receives the current query snapshot and later updates.
|
|
39
|
+
* Returns a function that removes this listener. Other listeners remain subscribed.
|
|
40
|
+
*/
|
|
41
|
+
subscribeToDataSource,
|
|
36
42
|
};
|
|
37
43
|
let lastHostState;
|
|
38
44
|
let lastPublicState;
|
package/dist/protocol/index.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export * from "./messages/queryDataSourceResult.js";
|
|
|
39
39
|
export * from "./messages/resize.js";
|
|
40
40
|
export * from "./messages/sandboxToHost.js";
|
|
41
41
|
export * from "./messages/themeChanged.js";
|
|
42
|
+
export * from "./messages/unsubscribeDataSourceQuery.js";
|
|
42
43
|
export * from "./messages/updatePage.js";
|
|
43
44
|
export * from "./messages/updatePageResult.js";
|
|
44
45
|
export * from "./pages/page.js";
|
package/dist/protocol/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export * from "./messages/queryDataSourceResult.js";
|
|
|
39
39
|
export * from "./messages/resize.js";
|
|
40
40
|
export * from "./messages/sandboxToHost.js";
|
|
41
41
|
export * from "./messages/themeChanged.js";
|
|
42
|
+
export * from "./messages/unsubscribeDataSourceQuery.js";
|
|
42
43
|
export * from "./messages/updatePage.js";
|
|
43
44
|
export * from "./messages/updatePageResult.js";
|
|
44
45
|
export * from "./pages/page.js";
|
|
@@ -411,6 +411,9 @@ export declare const sandboxToHostMessageSchema: v.VariantSchema<"type", [v.Vari
|
|
|
411
411
|
readonly propertyId: v.StringSchema<undefined>;
|
|
412
412
|
readonly direction: v.PicklistSchema<["ascending", "descending"], undefined>;
|
|
413
413
|
}, undefined>, undefined>, undefined>;
|
|
414
|
+
}, undefined>, v.ObjectSchema<{
|
|
415
|
+
readonly type: v.LiteralSchema<"unsubscribeDataSourceQuery", undefined>;
|
|
416
|
+
readonly subscriptionId: v.StringSchema<undefined>;
|
|
414
417
|
}, undefined>, v.ObjectSchema<{
|
|
415
418
|
readonly type: v.LiteralSchema<"createPage", undefined>;
|
|
416
419
|
readonly requestId: v.StringSchema<undefined>;
|
|
@@ -8,6 +8,7 @@ import { invalidHostMessageSchema } from "./invalidHostMessage.js";
|
|
|
8
8
|
import { listUsersMessageSchema } from "./listUsers.js";
|
|
9
9
|
import { queryDataSourceMessageSchema } from "./queryDataSource.js";
|
|
10
10
|
import { resizeMessageSchema } from "./resize.js";
|
|
11
|
+
import { unsubscribeDataSourceQueryMessageSchema } from "./unsubscribeDataSourceQuery.js";
|
|
11
12
|
import { updatePageMessageSchema } from "./updatePage.js";
|
|
12
13
|
/**
|
|
13
14
|
* Discriminated union of every message the sandbox is allowed to send the host. Useful for hosts
|
|
@@ -17,6 +18,7 @@ export const sandboxToHostMessageSchema = v.variant("type", [
|
|
|
17
18
|
connectMessageSchema,
|
|
18
19
|
initResultMessageSchema,
|
|
19
20
|
queryDataSourceMessageSchema,
|
|
21
|
+
unsubscribeDataSourceQueryMessageSchema,
|
|
20
22
|
createPageMessageSchema,
|
|
21
23
|
getPageMessageSchema,
|
|
22
24
|
getUserMessageSchema,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* Tells the host to stop an active data source query subscription.
|
|
4
|
+
*/
|
|
5
|
+
export declare const unsubscribeDataSourceQueryMessageSchema: v.ObjectSchema<{
|
|
6
|
+
readonly type: v.LiteralSchema<"unsubscribeDataSourceQuery", undefined>;
|
|
7
|
+
/** The subscription to remove from the host. */
|
|
8
|
+
readonly subscriptionId: v.StringSchema<undefined>;
|
|
9
|
+
}, undefined>;
|
|
10
|
+
export type UnsubscribeDataSourceQueryMessage = v.InferOutput<typeof unsubscribeDataSourceQueryMessageSchema>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* Tells the host to stop an active data source query subscription.
|
|
4
|
+
*/
|
|
5
|
+
export const unsubscribeDataSourceQueryMessageSchema = v.object({
|
|
6
|
+
type: v.literal("unsubscribeDataSourceQuery"),
|
|
7
|
+
/** The subscription to remove from the host. */
|
|
8
|
+
subscriptionId: v.string(),
|
|
9
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataSource.d.ts","sourceRoot":"","sources":["../../src/react/useDataSource.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"useDataSource.d.ts","sourceRoot":"","sources":["../../src/react/useDataSource.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAiB5E;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,oBAAoB,GAC5B,mBAAmB,CAqBrB"}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { getDataSourceQueryOptionsIdentity } from "../bridge/dataSources/query.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { customBlock } from "../customBlock.js";
|
|
4
|
+
const EMPTY_DATA_SOURCE_RESULT = {
|
|
5
|
+
items: [],
|
|
6
|
+
propertySchemasById: {},
|
|
7
|
+
propertyIdsByKey: {},
|
|
8
|
+
propertySchemasByKey: {},
|
|
9
|
+
isLoading: false,
|
|
10
|
+
hasMore: false,
|
|
11
|
+
};
|
|
5
12
|
/**
|
|
6
13
|
* Reads from the data source mapped to the given semantic `key`.
|
|
7
14
|
*
|
|
@@ -13,34 +20,24 @@ import { useCustomBlockHost } from "./useHostState.js";
|
|
|
13
20
|
* const { items, isLoading, hasMore, error } = useDataSource("default", { limit: 25 })
|
|
14
21
|
*/
|
|
15
22
|
export function useDataSource(key, options) {
|
|
16
|
-
const host = useCustomBlockHost();
|
|
17
|
-
const [subscriptionId] = useState(() => customBlockDataSources.createSubscriptionId());
|
|
18
23
|
const optionsIdentity = getDataSourceQueryOptionsIdentity(options);
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
const [state, setState] = useState(() => ({
|
|
25
|
+
key,
|
|
26
|
+
optionsIdentity,
|
|
27
|
+
snapshot: EMPTY_DATA_SOURCE_RESULT,
|
|
28
|
+
}));
|
|
23
29
|
// biome-ignore lint/correctness/useExhaustiveDependencies(options): Compare options by value through optionsIdentity. Object identity alone must not trigger queries.
|
|
24
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies(optionsIdentity): Changes to the serialized options must trigger a query even though the callback reads options.
|
|
25
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies(matchingDataSource): Requery when the matching data source changes, even when the key and options are unchanged.
|
|
26
30
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}, [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
propertySchemasById: view.propertySchemasById,
|
|
40
|
-
propertyIdsByKey: view.propertyIdsByKey,
|
|
41
|
-
propertySchemasByKey: view.propertySchemasByKey,
|
|
42
|
-
isLoading: view.isLoading,
|
|
43
|
-
hasMore: view.hasMore,
|
|
44
|
-
error: view.error,
|
|
45
|
-
};
|
|
31
|
+
return customBlock.subscribeToDataSource({
|
|
32
|
+
key,
|
|
33
|
+
onSnapshot: snapshot => {
|
|
34
|
+
setState({ key, optionsIdentity, snapshot });
|
|
35
|
+
},
|
|
36
|
+
options,
|
|
37
|
+
});
|
|
38
|
+
}, [key, optionsIdentity]);
|
|
39
|
+
if (state.key !== key || state.optionsIdentity !== optionsIdentity) {
|
|
40
|
+
return EMPTY_DATA_SOURCE_RESULT;
|
|
41
|
+
}
|
|
42
|
+
return state.snapshot;
|
|
46
43
|
}
|