@notionhq/custom-blocks 0.0.76 → 0.0.77
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/HOST.md +9 -5
- package/dist/bridge/SandboxBridge.d.ts +0 -1
- package/dist/bridge/SandboxBridge.d.ts.map +1 -1
- package/dist/bridge/SandboxBridge.js +15 -34
- package/dist/bridge/hostState.d.ts +1 -2
- package/dist/bridge/hostState.d.ts.map +1 -1
- package/dist/bridge/messages/hostToSandbox.d.ts +3 -79
- package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -1
- package/dist/bridge/messages/hostToSandbox.js +2 -3
- package/dist/bridge/messages/queryDataSource.d.ts +3 -7
- package/dist/bridge/messages/queryDataSource.d.ts.map +1 -1
- package/dist/bridge/messages/queryDataSource.js +3 -7
- package/dist/bridge/messages/queryDataSourceResult.d.ts +4 -240
- package/dist/bridge/messages/queryDataSourceResult.d.ts.map +1 -1
- package/dist/bridge/messages/queryDataSourceResult.js +4 -22
- package/dist/bridge/messages/sandboxToHost.d.ts +1 -2
- package/dist/bridge/messages/sandboxToHost.d.ts.map +1 -1
- package/dist/host/createCustomBlockHost.d.ts.map +1 -1
- package/dist/host/createCustomBlockHost.js +25 -20
- package/dist/host/queries/querySubscriptions.d.ts +10 -10
- package/dist/host/queries/querySubscriptions.d.ts.map +1 -1
- package/dist/host/queries/querySubscriptions.js +35 -19
- package/dist/host/queries/types.d.ts +5 -4
- package/dist/host/queries/types.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/bridge/SandboxBridge.ts +15 -35
- package/src/bridge/hostState.ts +1 -2
- package/src/bridge/messages/hostToSandbox.ts +2 -6
- package/src/bridge/messages/queryDataSource.ts +3 -7
- package/src/bridge/messages/queryDataSourceResult.ts +4 -24
- package/src/host/createCustomBlockHost.ts +27 -22
- package/src/host/queries/querySubscriptions.ts +58 -39
- package/src/host/queries/types.ts +10 -11
|
@@ -55,7 +55,6 @@ import type { NotionUser } from "./users/user.js"
|
|
|
55
55
|
* single host needs to support multiple custom blocks built with different versions of the bridge
|
|
56
56
|
* protocol. Increment this number any time a breaking change is made to the bridge protocol.
|
|
57
57
|
*/
|
|
58
|
-
// TODO(custom-blocks): Update when bumping bridge protocol version to 3.
|
|
59
58
|
export const CUSTOM_BLOCK_BRIDGE_PROTOCOL_VERSION = 2
|
|
60
59
|
|
|
61
60
|
/**
|
|
@@ -76,7 +75,6 @@ export class SandboxBridge {
|
|
|
76
75
|
private listeners = new Set<() => void>()
|
|
77
76
|
private messageLog: MessageLogEntry[] = []
|
|
78
77
|
private messageLogListeners = new Set<() => void>()
|
|
79
|
-
private nextRequestId = 1
|
|
80
78
|
private readonly pendingCreatePage = new PendingRequests<CreatePageResult>(
|
|
81
79
|
"custom-block-create-page",
|
|
82
80
|
)
|
|
@@ -400,32 +398,23 @@ export class SandboxBridge {
|
|
|
400
398
|
|
|
401
399
|
case "queryDataSourceResult": {
|
|
402
400
|
const queryEntry = Object.entries(hostState.dataSourceState).find(
|
|
403
|
-
([, state]) => state.
|
|
401
|
+
([, state]) => state.subscriptionId === message.subscriptionId,
|
|
404
402
|
)
|
|
405
403
|
if (queryEntry === undefined) {
|
|
406
404
|
return
|
|
407
405
|
}
|
|
408
406
|
const [key, currentState] = queryEntry
|
|
409
|
-
if (currentState.latestRequestId !== message.requestId) {
|
|
410
|
-
return
|
|
411
|
-
}
|
|
412
407
|
const queryResult =
|
|
413
|
-
|
|
414
|
-
?
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
: {
|
|
421
|
-
items: message.items,
|
|
422
|
-
hasMore: message.hasMore,
|
|
423
|
-
error: undefined,
|
|
424
|
-
}
|
|
408
|
+
message.status === "error"
|
|
409
|
+
? {
|
|
410
|
+
items: [],
|
|
411
|
+
hasMore: false,
|
|
412
|
+
error: message.error,
|
|
413
|
+
}
|
|
425
414
|
: {
|
|
426
415
|
items: message.items,
|
|
427
416
|
hasMore: message.hasMore,
|
|
428
|
-
error:
|
|
417
|
+
error: undefined,
|
|
429
418
|
}
|
|
430
419
|
this.hostState = {
|
|
431
420
|
...hostState,
|
|
@@ -436,10 +425,7 @@ export class SandboxBridge {
|
|
|
436
425
|
isLoading: false,
|
|
437
426
|
hasMore: queryResult.hasMore,
|
|
438
427
|
error: queryResult.error,
|
|
439
|
-
|
|
440
|
-
// same subscription still match.
|
|
441
|
-
latestRequestId: message.requestId,
|
|
442
|
-
latestSnapshotId: message.snapshotId,
|
|
428
|
+
subscriptionId: message.subscriptionId,
|
|
443
429
|
latestLimit: currentState.latestLimit,
|
|
444
430
|
},
|
|
445
431
|
},
|
|
@@ -558,21 +544,18 @@ export class SandboxBridge {
|
|
|
558
544
|
}
|
|
559
545
|
|
|
560
546
|
const limit = resolveDataSourceQueryLimit(options.limit)
|
|
561
|
-
const
|
|
547
|
+
const subscriptionId = makeDataSourceSubscriptionId({
|
|
562
548
|
key,
|
|
563
549
|
})
|
|
564
550
|
|
|
565
551
|
if (
|
|
566
552
|
currentState.isLoading &&
|
|
567
|
-
currentState.
|
|
553
|
+
currentState.subscriptionId === subscriptionId &&
|
|
568
554
|
currentState.latestLimit === limit
|
|
569
555
|
) {
|
|
570
556
|
return
|
|
571
557
|
}
|
|
572
558
|
|
|
573
|
-
const requestId = `custom-block-query-${this.nextRequestId}`
|
|
574
|
-
this.nextRequestId += 1
|
|
575
|
-
|
|
576
559
|
this.hostState = {
|
|
577
560
|
...this.hostState,
|
|
578
561
|
dataSourceState: {
|
|
@@ -581,8 +564,7 @@ export class SandboxBridge {
|
|
|
581
564
|
...currentState,
|
|
582
565
|
isLoading: true,
|
|
583
566
|
error: undefined,
|
|
584
|
-
|
|
585
|
-
latestSnapshotId: snapshotId,
|
|
567
|
+
subscriptionId,
|
|
586
568
|
latestLimit: limit,
|
|
587
569
|
},
|
|
588
570
|
},
|
|
@@ -591,8 +573,7 @@ export class SandboxBridge {
|
|
|
591
573
|
|
|
592
574
|
const outbound: QueryDataSourceMessage = {
|
|
593
575
|
type: "queryDataSource",
|
|
594
|
-
|
|
595
|
-
snapshotId,
|
|
576
|
+
subscriptionId,
|
|
596
577
|
dataSourceId: dataSource.collectionPointer.id,
|
|
597
578
|
limit,
|
|
598
579
|
}
|
|
@@ -615,8 +596,7 @@ export class SandboxBridge {
|
|
|
615
596
|
...currentState,
|
|
616
597
|
isLoading: false,
|
|
617
598
|
error,
|
|
618
|
-
|
|
619
|
-
latestSnapshotId: undefined,
|
|
599
|
+
subscriptionId: undefined,
|
|
620
600
|
latestLimit: undefined,
|
|
621
601
|
},
|
|
622
602
|
},
|
|
@@ -907,7 +887,7 @@ function resolveDataSourceQueryLimit(limit: number | undefined): number {
|
|
|
907
887
|
return limit
|
|
908
888
|
}
|
|
909
889
|
|
|
910
|
-
function
|
|
890
|
+
function makeDataSourceSubscriptionId(args: { key: string }): string {
|
|
911
891
|
const { key } = args
|
|
912
892
|
return `data-source:${encodeURIComponent(key)}`
|
|
913
893
|
}
|
package/src/bridge/hostState.ts
CHANGED
|
@@ -9,10 +9,7 @@ import { invalidSandboxMessageSchema } from "./invalidSandboxMessage.js"
|
|
|
9
9
|
import { listUsersResultMessageSchema } from "./listUsers.js"
|
|
10
10
|
import { pageChangedMessageSchema } from "./pageChanged.js"
|
|
11
11
|
import { parentChangedMessageSchema } from "./parentChanged.js"
|
|
12
|
-
import {
|
|
13
|
-
legacyQueryDataSourceResultMessageSchema,
|
|
14
|
-
statusQueryDataSourceResultMessageSchema,
|
|
15
|
-
} from "./queryDataSourceResult.js"
|
|
12
|
+
import { queryDataSourceResultMessageSchema } from "./queryDataSourceResult.js"
|
|
16
13
|
import { themeChangedMessageSchema } from "./themeChanged.js"
|
|
17
14
|
import { updatePageResultMessageSchema } from "./updatePageResult.js"
|
|
18
15
|
|
|
@@ -26,8 +23,7 @@ export const hostToSandboxMessageSchema = v.variant("type", [
|
|
|
26
23
|
pageChangedMessageSchema,
|
|
27
24
|
currentUserChangedMessageSchema,
|
|
28
25
|
dataSourcesChangedMessageSchema,
|
|
29
|
-
|
|
30
|
-
legacyQueryDataSourceResultMessageSchema,
|
|
26
|
+
queryDataSourceResultMessageSchema,
|
|
31
27
|
createPageResultMessageSchema,
|
|
32
28
|
getPageResultMessageSchema,
|
|
33
29
|
getUserResultMessageSchema,
|
|
@@ -7,15 +7,11 @@ import { notionDataSourceIdSchema } from "../ids.js"
|
|
|
7
7
|
*/
|
|
8
8
|
export const queryDataSourceMessageSchema = v.object({
|
|
9
9
|
type: v.literal("queryDataSource"),
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* The stable snapshot ID that identifies the SDK result slot to update. This is stable for the
|
|
13
|
-
* lifetime of the subscription.
|
|
14
|
-
*/
|
|
15
|
-
snapshotId: v.string(),
|
|
10
|
+
/** Stable for the lifetime of this query subscription. */
|
|
11
|
+
subscriptionId: v.string(),
|
|
16
12
|
/** The raw Notion data source ID to read from. */
|
|
17
13
|
dataSourceId: notionDataSourceIdSchema,
|
|
18
|
-
/** The number of items to return in
|
|
14
|
+
/** The number of items to return in each subscription update. */
|
|
19
15
|
limit: v.number(),
|
|
20
16
|
})
|
|
21
17
|
|
|
@@ -22,44 +22,24 @@ export const customBlockQueryDataSourceErrorInfoSchema = v.object({
|
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Message sent by the host to
|
|
25
|
+
* Message sent by the host to update a `queryDataSource` subscription.
|
|
26
26
|
*/
|
|
27
|
-
export const
|
|
28
|
-
type: v.literal("queryDataSourceResult"),
|
|
29
|
-
requestId: v.string(),
|
|
30
|
-
snapshotId: v.string(),
|
|
31
|
-
items: v.array(notionDataSourcePageBridgeSchema),
|
|
32
|
-
hasMore: v.boolean(),
|
|
33
|
-
error: v.optional(customBlockQueryDataSourceErrorInfoSchema),
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
export const statusQueryDataSourceResultMessageSchema = v.variant("status", [
|
|
27
|
+
export const queryDataSourceResultMessageSchema = v.variant("status", [
|
|
37
28
|
v.object({
|
|
38
29
|
type: v.literal("queryDataSourceResult"),
|
|
39
|
-
|
|
40
|
-
snapshotId: v.string(),
|
|
30
|
+
subscriptionId: v.string(),
|
|
41
31
|
status: v.literal("success"),
|
|
42
32
|
items: v.array(notionDataSourcePageBridgeSchema),
|
|
43
33
|
hasMore: v.boolean(),
|
|
44
34
|
}),
|
|
45
35
|
v.object({
|
|
46
36
|
type: v.literal("queryDataSourceResult"),
|
|
47
|
-
|
|
48
|
-
snapshotId: v.string(),
|
|
37
|
+
subscriptionId: v.string(),
|
|
49
38
|
status: v.literal("error"),
|
|
50
39
|
error: customBlockQueryDataSourceErrorInfoSchema,
|
|
51
40
|
}),
|
|
52
41
|
])
|
|
53
42
|
|
|
54
|
-
/**
|
|
55
|
-
* TODO(custom-blocks): Update when bumping bridge protocol version to 3.
|
|
56
|
-
* Protocol version 2 hosts and sandboxes use the legacy optional-error shape.
|
|
57
|
-
*/
|
|
58
|
-
export const queryDataSourceResultMessageSchema = v.union([
|
|
59
|
-
legacyQueryDataSourceResultMessageSchema,
|
|
60
|
-
statusQueryDataSourceResultMessageSchema,
|
|
61
|
-
])
|
|
62
|
-
|
|
63
43
|
export type QueryDataSourceResultMessage = v.InferOutput<
|
|
64
44
|
typeof queryDataSourceResultMessageSchema
|
|
65
45
|
>
|
|
@@ -111,20 +111,24 @@ export function createCustomBlockHost(
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
function postQueryDataSourceResult(args: {
|
|
114
|
-
|
|
115
|
-
snapshotId: string
|
|
114
|
+
subscriptionId: string
|
|
116
115
|
response: CustomBlockHostQueryDataSourceResult
|
|
117
116
|
}) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
117
|
+
const message: QueryDataSourceResultMessage =
|
|
118
|
+
args.response.status === "error"
|
|
119
|
+
? {
|
|
120
|
+
type: "queryDataSourceResult",
|
|
121
|
+
subscriptionId: args.subscriptionId,
|
|
122
|
+
status: "error",
|
|
123
|
+
error: args.response.error,
|
|
124
|
+
}
|
|
125
|
+
: {
|
|
126
|
+
type: "queryDataSourceResult",
|
|
127
|
+
subscriptionId: args.subscriptionId,
|
|
128
|
+
status: "success",
|
|
129
|
+
items: args.response.items,
|
|
130
|
+
hasMore: args.response.hasMore,
|
|
131
|
+
}
|
|
128
132
|
post(message)
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -183,11 +187,13 @@ export function createCustomBlockHost(
|
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
async function handleQuery(message: QueryDataSourceMessage) {
|
|
186
|
-
querySubscriptions.track(message)
|
|
190
|
+
const token = querySubscriptions.track(message)
|
|
187
191
|
const response = await handlers.queryDataSource(message)
|
|
192
|
+
if (!querySubscriptions.isCurrent(message.subscriptionId, token)) {
|
|
193
|
+
return
|
|
194
|
+
}
|
|
188
195
|
postQueryDataSourceResult({
|
|
189
|
-
|
|
190
|
-
snapshotId: message.snapshotId,
|
|
196
|
+
subscriptionId: message.subscriptionId,
|
|
191
197
|
response,
|
|
192
198
|
})
|
|
193
199
|
}
|
|
@@ -362,6 +368,7 @@ export function createCustomBlockHost(
|
|
|
362
368
|
window.removeEventListener("message", onMessage)
|
|
363
369
|
iframe.removeEventListener("load", onIframeLoad)
|
|
364
370
|
clearNoReadyTimeout()
|
|
371
|
+
querySubscriptions.clear()
|
|
365
372
|
},
|
|
366
373
|
post,
|
|
367
374
|
setTheme(nextTheme) {
|
|
@@ -392,19 +399,17 @@ export function createCustomBlockHost(
|
|
|
392
399
|
post({ type: "currentUserChanged", currentUser })
|
|
393
400
|
},
|
|
394
401
|
refreshQuery({ dataSourceId, response }) {
|
|
395
|
-
const
|
|
402
|
+
const refreshes = querySubscriptions.resolveRefreshes({
|
|
396
403
|
dataSourceId,
|
|
397
404
|
response,
|
|
398
405
|
})
|
|
399
|
-
if (
|
|
406
|
+
if (refreshes.length === 0) {
|
|
400
407
|
emit("warn", `No active query exists for data source "${dataSourceId}"`)
|
|
401
408
|
return
|
|
402
409
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
response: refresh.response,
|
|
407
|
-
})
|
|
410
|
+
for (const refresh of refreshes) {
|
|
411
|
+
postQueryDataSourceResult(refresh)
|
|
412
|
+
}
|
|
408
413
|
},
|
|
409
414
|
}
|
|
410
415
|
}
|
|
@@ -1,52 +1,71 @@
|
|
|
1
1
|
import type { NotionDataSourceId } from "../../bridge/ids.js"
|
|
2
2
|
import type { QueryDataSourceMessage } from "../../bridge/messages/queryDataSource.js"
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
import type { CustomBlockHostQueryDataSourceResult } from "./types.js"
|
|
4
|
+
|
|
5
|
+
export type QueryRefresh = {
|
|
6
|
+
subscriptionId: string
|
|
7
|
+
response: CustomBlockHostQueryDataSourceResult
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type QuerySubscriptionToken = object
|
|
11
|
+
|
|
12
|
+
type QuerySubscriptionState = {
|
|
13
|
+
dataSourceId: NotionDataSourceId
|
|
14
|
+
limit: number
|
|
15
|
+
token: QuerySubscriptionToken
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
export class QuerySubscriptions {
|
|
18
|
-
private readonly
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.latestByDataSourceId.set(message.dataSourceId, {
|
|
25
|
-
requestId: message.requestId,
|
|
26
|
-
snapshotId: message.snapshotId,
|
|
19
|
+
private readonly bySubscriptionId = new Map<string, QuerySubscriptionState>()
|
|
20
|
+
|
|
21
|
+
track(message: QueryDataSourceMessage): QuerySubscriptionToken {
|
|
22
|
+
const token = {}
|
|
23
|
+
this.bySubscriptionId.set(message.subscriptionId, {
|
|
24
|
+
dataSourceId: message.dataSourceId,
|
|
27
25
|
limit: message.limit,
|
|
26
|
+
token,
|
|
28
27
|
})
|
|
28
|
+
return token
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
isCurrent(subscriptionId: string, token: QuerySubscriptionToken): boolean {
|
|
32
|
+
return this.bySubscriptionId.get(subscriptionId)?.token === token
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
resolveRefreshes(args: {
|
|
32
36
|
dataSourceId: NotionDataSourceId
|
|
33
37
|
response: CustomBlockHostQueryDataSourceResult
|
|
34
|
-
}):
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
items,
|
|
46
|
-
hasMore:
|
|
47
|
-
args.response.hasMore ?? args.response.items.length > items.length,
|
|
48
|
-
error: args.response.error,
|
|
49
|
-
},
|
|
38
|
+
}): QueryRefresh[] {
|
|
39
|
+
const refreshes: QueryRefresh[] = []
|
|
40
|
+
for (const [subscriptionId, queryState] of this.bySubscriptionId) {
|
|
41
|
+
if (queryState.dataSourceId !== args.dataSourceId) {
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
queryState.token = {}
|
|
45
|
+
refreshes.push({
|
|
46
|
+
subscriptionId,
|
|
47
|
+
response: limitResponse(args.response, queryState.limit),
|
|
48
|
+
})
|
|
50
49
|
}
|
|
50
|
+
return refreshes
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
clear() {
|
|
54
|
+
this.bySubscriptionId.clear()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function limitResponse(
|
|
59
|
+
response: CustomBlockHostQueryDataSourceResult,
|
|
60
|
+
limit: number,
|
|
61
|
+
): CustomBlockHostQueryDataSourceResult {
|
|
62
|
+
if (response.status === "error") {
|
|
63
|
+
return response
|
|
64
|
+
}
|
|
65
|
+
const items = response.items.slice(0, limit)
|
|
66
|
+
return {
|
|
67
|
+
status: "success",
|
|
68
|
+
items,
|
|
69
|
+
hasMore: response.hasMore || response.items.length > items.length,
|
|
51
70
|
}
|
|
52
71
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { NotionDataSourcePageBridge } from "../../bridge/dataSources/dataSourcePage.js"
|
|
2
|
-
import type { QueryDataSourceMessage } from "../../bridge/messages/queryDataSource.js"
|
|
3
2
|
import type { CustomBlockQueryDataSourceErrorInfo } from "../../bridge/messages/queryDataSourceResult.js"
|
|
4
3
|
|
|
5
|
-
export type CustomBlockHostQueryDataSourceResult =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
export type CustomBlockHostQueryDataSourceResult =
|
|
5
|
+
| {
|
|
6
|
+
status: "success"
|
|
7
|
+
items: NotionDataSourcePageBridge[]
|
|
8
|
+
hasMore: boolean
|
|
9
|
+
}
|
|
10
|
+
| {
|
|
11
|
+
status: "error"
|
|
12
|
+
error: CustomBlockQueryDataSourceErrorInfo
|
|
13
|
+
}
|