@notionhq/custom-blocks-host 0.3.11 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -236
  3. package/THIRD_PARTY_LICENSES.md +9 -0
  4. package/dist/autoBindProperties.d.ts +5 -2
  5. package/dist/autoBindProperties.d.ts.map +1 -1
  6. package/dist/autoBindProperties.js +5 -2
  7. package/dist/browser.js +1 -1
  8. package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.d.ts +1215 -0
  9. package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.d.ts.map +1 -0
  10. package/dist/compatibility/addMetadataReadSchemasForProtocol3To4.js +27 -0
  11. package/dist/compatibility/normalizeHostToSandboxMessage.d.ts +8 -0
  12. package/dist/compatibility/normalizeHostToSandboxMessage.d.ts.map +1 -0
  13. package/dist/compatibility/normalizeHostToSandboxMessage.js +39 -0
  14. package/dist/compatibility/normalizePageResultsForProtocol3To5.d.ts +11 -0
  15. package/dist/compatibility/normalizePageResultsForProtocol3To5.d.ts.map +1 -0
  16. package/dist/compatibility/normalizePageResultsForProtocol3To5.js +18 -0
  17. package/dist/compatibility/normalizePageResultsForProtocol6.d.ts +9 -0
  18. package/dist/compatibility/normalizePageResultsForProtocol6.d.ts.map +1 -0
  19. package/dist/compatibility/normalizePageResultsForProtocol6.js +18 -0
  20. package/dist/compatibility/normalizeSandboxToHostMessage.d.ts +1091 -0
  21. package/dist/compatibility/normalizeSandboxToHostMessage.d.ts.map +1 -0
  22. package/dist/compatibility/normalizeSandboxToHostMessage.js +9 -0
  23. package/dist/compatibility/pageForProtocol3To5.d.ts +159 -0
  24. package/dist/compatibility/pageForProtocol3To5.d.ts.map +1 -0
  25. package/dist/{lifecycle/legacyPage.js → compatibility/pageForProtocol3To5.js} +50 -9
  26. package/dist/compatibility/pageResult.d.ts +11 -0
  27. package/dist/compatibility/pageResult.d.ts.map +1 -0
  28. package/dist/compatibility/pageWithNullTextFallbackProperties.d.ts +9 -0
  29. package/dist/compatibility/pageWithNullTextFallbackProperties.d.ts.map +1 -0
  30. package/dist/compatibility/pageWithNullTextFallbackProperties.js +46 -0
  31. package/dist/createCustomBlockHost.d.ts +18 -19
  32. package/dist/createCustomBlockHost.d.ts.map +1 -1
  33. package/dist/createCustomBlockHost.js +103 -38
  34. package/dist/index.d.ts +2 -19
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -2
  37. package/dist/{localBlockUrl.d.ts → isAllowedLocalPreviewUrl.d.ts} +2 -2
  38. package/dist/isAllowedLocalPreviewUrl.d.ts.map +1 -0
  39. package/dist/{localBlockUrl.js → isAllowedLocalPreviewUrl.js} +3 -7
  40. package/dist/lifecycle/initErrors.d.ts +1 -0
  41. package/dist/lifecycle/initErrors.d.ts.map +1 -1
  42. package/dist/lifecycle/initErrors.js +7 -0
  43. package/dist/lifecycle/initializationController.d.ts +6 -4
  44. package/dist/lifecycle/initializationController.d.ts.map +1 -1
  45. package/dist/lifecycle/initializationController.js +24 -15
  46. package/dist/lifecycle/resolveManifest.d.ts +13 -0
  47. package/dist/lifecycle/resolveManifest.d.ts.map +1 -0
  48. package/dist/lifecycle/resolveManifest.js +21 -0
  49. package/dist/lifecycle/types.d.ts +1637 -17
  50. package/dist/lifecycle/types.d.ts.map +1 -1
  51. package/dist/lifecycle/types.js +18 -0
  52. package/dist/messages/sandboxMessageRouter.d.ts.map +1 -1
  53. package/dist/messages/sandboxMessageRouter.js +2 -2
  54. package/dist/protocol/dataSources/dataSourcePage.d.ts +3 -4
  55. package/dist/protocol/dataSources/dataSourcePage.js +2 -3
  56. package/dist/protocol/index.d.ts +1 -0
  57. package/dist/protocol/index.js +1 -0
  58. package/dist/protocol/isLocalBlockServerUrl.d.ts +2 -0
  59. package/dist/protocol/isLocalBlockServerUrl.js +9 -0
  60. package/dist/protocol/messages/connect.d.ts +2 -2
  61. package/dist/protocol/messages/connect.js +2 -2
  62. package/dist/protocol/messages/createPageResult.d.ts +2 -2
  63. package/dist/protocol/messages/createPageResult.js +3 -3
  64. package/dist/protocol/messages/getPage.d.ts +2 -2
  65. package/dist/protocol/messages/getPage.js +3 -3
  66. package/dist/protocol/messages/hostToSandbox.d.ts +3 -3
  67. package/dist/protocol/messages/hostToSandbox.js +10 -10
  68. package/dist/protocol/messages/init.d.ts +1 -1
  69. package/dist/protocol/messages/queryDataSourceResult.d.ts +3 -3
  70. package/dist/protocol/messages/queryDataSourceResult.js +6 -3
  71. package/dist/protocol/messages/updatePageResult.d.ts +2 -2
  72. package/dist/protocol/messages/updatePageResult.js +3 -3
  73. package/dist/protocol/pages/page.d.ts +2 -2
  74. package/dist/protocol/pages/page.js +1 -1
  75. package/dist/protocol/protocolVersion.d.ts +2 -2
  76. package/dist/protocol/protocolVersion.js +2 -2
  77. package/dist/protocol.d.ts +9 -0
  78. package/dist/protocol.d.ts.map +1 -0
  79. package/dist/protocol.js +8 -0
  80. package/docs/bridge/changelog.md +67 -0
  81. package/docs/bridge/protocol.md +182 -0
  82. package/docs/bridge/versioning.md +38 -0
  83. package/docs/compatibility.md +68 -0
  84. package/docs/handlers.md +199 -0
  85. package/docs/lifecycle.md +117 -0
  86. package/package.json +10 -2
  87. package/src/autoBindProperties.ts +5 -2
  88. package/src/compatibility/addMetadataReadSchemasForProtocol3To4.ts +36 -0
  89. package/src/compatibility/normalizeHostToSandboxMessage.ts +54 -0
  90. package/src/compatibility/normalizePageResultsForProtocol3To5.ts +28 -0
  91. package/src/compatibility/normalizePageResultsForProtocol6.ts +23 -0
  92. package/src/compatibility/normalizeSandboxToHostMessage.ts +10 -0
  93. package/src/{lifecycle/legacyPage.ts → compatibility/pageForProtocol3To5.ts} +52 -11
  94. package/src/compatibility/pageResult.ts +18 -0
  95. package/src/compatibility/pageWithNullTextFallbackProperties.ts +53 -0
  96. package/src/createCustomBlockHost.ts +152 -62
  97. package/src/index.ts +4 -51
  98. package/src/{localBlockUrl.ts → isAllowedLocalPreviewUrl.ts} +4 -7
  99. package/src/lifecycle/initErrors.ts +9 -0
  100. package/src/lifecycle/initializationController.ts +34 -19
  101. package/src/lifecycle/resolveManifest.ts +31 -0
  102. package/src/lifecycle/types.ts +84 -16
  103. package/src/messages/sandboxMessageRouter.ts +2 -2
  104. package/src/protocol.ts +8 -0
  105. package/dist/lifecycle/legacyPage.d.ts +0 -70
  106. package/dist/lifecycle/legacyPage.d.ts.map +0 -1
  107. package/dist/lifecycle/loadCustomBlockManifest.d.ts +0 -16
  108. package/dist/lifecycle/loadCustomBlockManifest.d.ts.map +0 -1
  109. package/dist/lifecycle/loadCustomBlockManifest.js +0 -65
  110. package/dist/lifecycle/manifestOptions.d.ts +0 -17
  111. package/dist/lifecycle/manifestOptions.d.ts.map +0 -1
  112. package/dist/lifecycle/normalizeHostToSandboxMessage.d.ts +0 -6
  113. package/dist/lifecycle/normalizeHostToSandboxMessage.d.ts.map +0 -1
  114. package/dist/lifecycle/normalizeHostToSandboxMessage.js +0 -14
  115. package/dist/lifecycle/normalizePage.d.ts +0 -7
  116. package/dist/lifecycle/normalizePage.d.ts.map +0 -1
  117. package/dist/lifecycle/normalizePage.js +0 -47
  118. package/dist/localBlockUrl.d.ts.map +0 -1
  119. package/src/lifecycle/loadCustomBlockManifest.ts +0 -89
  120. package/src/lifecycle/manifestOptions.ts +0 -19
  121. package/src/lifecycle/normalizeHostToSandboxMessage.ts +0 -27
  122. package/src/lifecycle/normalizePage.ts +0 -71
  123. /package/dist/{lifecycle/manifestOptions.js → compatibility/pageResult.js} +0 -0
@@ -6,32 +6,89 @@ import {
6
6
  manifestSchema,
7
7
  } from "@notionhq/custom-blocks-protocol/manifest.js"
8
8
  import type { ConnectMessage } from "@notionhq/custom-blocks-protocol/messages/connect.js"
9
- import type { CustomBlockInitErrorInfo } from "@notionhq/custom-blocks-protocol/messages/init.js"
9
+ import {
10
+ type CustomBlockInitErrorInfo,
11
+ customBlockInitErrorInfoSchema,
12
+ } from "@notionhq/custom-blocks-protocol/messages/init.js"
10
13
  import { customBlockPageSchema } from "@notionhq/custom-blocks-protocol/pages/page.js"
11
14
  import { notionParentSchema } from "@notionhq/custom-blocks-protocol/parent.js"
12
15
  import { notionThemeSchema } from "@notionhq/custom-blocks-protocol/theme.js"
13
16
  import { notionUserSchema } from "@notionhq/custom-blocks-protocol/users/user.js"
14
17
  import * as v from "valibot"
18
+ import type { CustomBlockHostFailure } from "../messages/types.js"
19
+
20
+ /** Selects the manifest used to initialize a custom block. Both sources load independently. */
21
+ export type CustomBlockManifestSource =
22
+ /** Uses the persisted manifest returned by the host adapter's getPersistedManifest callback. */
23
+ | "host"
24
+ /** Uses the manifest sent in connect by a sandbox on a separate HTTP(S) loopback origin. */
25
+ | "sandbox"
26
+
27
+ export const customBlockHostManifestResultSchema = v.variant("status", [
28
+ v.object({ status: v.literal("success"), manifest: manifestSchema }),
29
+ v.object({
30
+ status: v.literal("error"),
31
+ error: customBlockInitErrorInfoSchema,
32
+ }),
33
+ ])
34
+
35
+ /** A persisted manifest or an explicit loading error. The host validates and normalizes it. */
36
+ export type CustomBlockHostManifestResult =
37
+ | { status: "success"; manifest: v.InferInput<typeof manifestSchema> }
38
+ | { status: "error"; error: CustomBlockInitErrorInfo }
39
+
40
+ export type CustomBlockHostNormalizedManifestResult = v.InferOutput<
41
+ typeof customBlockHostManifestResultSchema
42
+ >
15
43
 
16
44
  export type ConnectSuccessMessage = Extract<
17
45
  ConnectMessage,
18
46
  { status: "success" }
19
47
  >
20
48
 
21
- /** Tracks initialization and lifetime for one host instance. */
22
- export type InitStatus =
23
- /** The host is waiting for the sandbox's first `connect` message. */
24
- | "waitingForConnect"
25
- /** The host is waiting for host state preparation to complete `init`. */
26
- | "preparingInit"
27
- /** The host is waiting for a matching `initResult` after it sends `init`. */
28
- | "waitingForInitResult"
29
- /** The host is initialized and can send live updates. */
30
- | "initialized"
31
- /** The host is in an error state after an initialization failure or timeout. */
32
- | "error"
33
- /** The host is stopped and no longer sends or accepts sandbox messages. */
34
- | "stopped"
49
+ /**
50
+ * Accepted lifecycle transitions for one host and iframe. The host reports
51
+ * waitingForConnect during creation. Handshake failures can skip intermediate
52
+ * statuses, and runtime failures can occur after initialization.
53
+ *
54
+ * failed and stopped are terminal. Stopping a failed host releases resources
55
+ * without replacing its failure status. Create a new host and iframe to retry.
56
+ */
57
+ export type CustomBlockHostStatus =
58
+ /** The host is listening for the sandbox's first connect message. */
59
+ | { status: "waitingForConnect" }
60
+ /**
61
+ * The host accepted connect. The local manifest comes from a permitted
62
+ * local sandbox. It does not replace a selected persisted manifest.
63
+ */
64
+ | {
65
+ status: "preparingInit"
66
+ localManifest: CustomBlockManifest | undefined
67
+ bridgeProtocolVersion: number
68
+ sdkVersion: string
69
+ }
70
+ /** Successful init has been sent. The host awaits its matching initResult. */
71
+ | { status: "waitingForInitResult" }
72
+ /**
73
+ * The sandbox acknowledged setup. resolvedManifest is the declaration selected by
74
+ * the host, and initialHeight is the sandbox's initial content height in CSS
75
+ * pixels. The height is optional.
76
+ */
77
+ | {
78
+ status: "initialized"
79
+ resolvedManifest: CustomBlockManifest
80
+ initialHeight: number | undefined
81
+ }
82
+ /**
83
+ * Initialization or runtime failed. error identifies the phase, reporting
84
+ * source, code, and whether a fresh host and iframe could plausibly succeed.
85
+ */
86
+ | { status: "failed"; error: CustomBlockHostFailure }
87
+ /** The embedding application explicitly stopped the host and released its resources. */
88
+ | { status: "stopped" }
89
+
90
+ /** Internal lifecycle discriminant, shared with the public status contract. */
91
+ export type InitStatus = CustomBlockHostStatus["status"]
35
92
 
36
93
  export type CustomBlockHostDataSourcesPayload = {
37
94
  bindings: v.InferInput<typeof notionDataSourceBindingsSchema>
@@ -70,7 +127,18 @@ export type CustomBlockHostInitialStateResult =
70
127
  error: CustomBlockInitErrorInfo
71
128
  }
72
129
 
73
- /** Adapter-owned state; the runtime adds its selected manifest to init. */
130
+ export const customBlockHostPreparedStateResultSchema = v.variant("status", [
131
+ v.object({
132
+ status: v.literal("success"),
133
+ initialState: v.omit(customBlockHostInitialStateSchema, ["manifest"]),
134
+ }),
135
+ v.object({
136
+ status: v.literal("error"),
137
+ error: customBlockInitErrorInfoSchema,
138
+ }),
139
+ ])
140
+
141
+ /** Adapter-owned state or an explicit preparation error. The host adds the manifest to init. */
74
142
  export type CustomBlockHostPreparedStateResult =
75
143
  | {
76
144
  status: "success"
@@ -10,10 +10,10 @@ import type { OpenExternalUrlMessage } from "@notionhq/custom-blocks-protocol/me
10
10
  import type { OpenPageMessage } from "@notionhq/custom-blocks-protocol/messages/openPage.js"
11
11
  import type { QueryDataSourceMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSource.js"
12
12
  import type { ResizeMessage } from "@notionhq/custom-blocks-protocol/messages/resize.js"
13
- import { sandboxToHostMessageSchema } from "@notionhq/custom-blocks-protocol/messages/sandboxToHost.js"
14
13
  import type { UnsubscribeDataSourceQueryMessage } from "@notionhq/custom-blocks-protocol/messages/unsubscribeDataSourceQuery.js"
15
14
  import type { UpdatePageMessage } from "@notionhq/custom-blocks-protocol/messages/updatePage.js"
16
15
  import * as v from "valibot"
16
+ import { normalizeSandboxToHostMessage } from "../compatibility/normalizeSandboxToHostMessage.js"
17
17
  import {
18
18
  invalidConnectPayloadError,
19
19
  invalidInitResultPayloadError,
@@ -138,7 +138,7 @@ export function createSandboxMessageRouter(
138
138
  }
139
139
 
140
140
  // Parse and validate the message from the sandbox.
141
- const parsed = v.safeParse(sandboxToHostMessageSchema, event.data)
141
+ const parsed = normalizeSandboxToHostMessage(event.data)
142
142
  if (!parsed.success) {
143
143
  onInvalidSandboxMessage(event.data, parsed.issues)
144
144
  return
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The protocol package is private and is bundled into the published host package.
3
+ * This public /protocol entrypoint lets consumers use the schemas, types, and
4
+ * constants that ship with their host version without a separate protocol package.
5
+ *
6
+ * Keep wire definitions here so the package root stays focused on host APIs.
7
+ */
8
+ export * from "@notionhq/custom-blocks-protocol"
@@ -1,70 +0,0 @@
1
- import type { LegacyNotionPage, notionPageDataSchema } from "../protocol/pages/page.js";
2
- import type { InferOutput } from "valibot";
3
- export declare function toLegacyPage(page: InferOutput<typeof notionPageDataSchema>): LegacyNotionPage;
4
- export declare function toLegacyQueryPage(page: InferOutput<typeof notionPageDataSchema>): {
5
- id: string & import("valibot").Brand<"NotionPageId">;
6
- is_archived: boolean;
7
- in_trash: boolean;
8
- propertiesById: Record<string, string | number | boolean | string[] | {
9
- id: string;
10
- table: string;
11
- }[] | {
12
- type: "date";
13
- start_date: string;
14
- reminder?: {
15
- unit: "day" | "month" | "week" | "year";
16
- value: number;
17
- time: string;
18
- defaultTimeZone?: string | undefined;
19
- } | {
20
- unit: "none";
21
- } | undefined;
22
- } | {
23
- type: "daterange";
24
- start_date: string;
25
- end_date: string;
26
- reminder?: {
27
- unit: "day" | "month" | "week" | "year";
28
- value: number;
29
- time: string;
30
- defaultTimeZone?: string | undefined;
31
- } | {
32
- unit: "none";
33
- } | undefined;
34
- } | {
35
- type: "datetime";
36
- start_date: string;
37
- start_time: string;
38
- time_zone?: string | undefined;
39
- reminder?: {
40
- unit: "day" | "month" | "week" | "year";
41
- value: number;
42
- time: string;
43
- defaultTimeZone?: string | undefined;
44
- } | {
45
- unit: "hour" | "minute";
46
- value: number;
47
- } | {
48
- unit: "none";
49
- } | undefined;
50
- } | {
51
- type: "datetimerange";
52
- start_date: string;
53
- start_time: string;
54
- end_date: string;
55
- end_time: string;
56
- time_zone?: string | undefined;
57
- reminder?: {
58
- unit: "day" | "month" | "week" | "year";
59
- value: number;
60
- time: string;
61
- defaultTimeZone?: string | undefined;
62
- } | {
63
- unit: "hour" | "minute";
64
- value: number;
65
- } | {
66
- unit: "none";
67
- } | undefined;
68
- } | undefined>;
69
- };
70
- //# sourceMappingURL=legacyPage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"legacyPage.d.ts","sourceRoot":"","sources":["../../src/lifecycle/legacyPage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,gBAAgB,EAEhB,oBAAoB,EACpB,MAAM,gDAAgD,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,wBAAgB,YAAY,CAC3B,IAAI,EAAE,WAAW,CAAC,OAAO,oBAAoB,CAAC,GAC5C,gBAAgB,CAelB;AAED,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,WAAW,CAAC,OAAO,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc9C"}
@@ -1,16 +0,0 @@
1
- import { type CustomBlockManifest } from "../protocol/manifest.js";
2
- import type { CustomBlockInitErrorInfo } from "../protocol/messages/init.js";
3
- import type { CustomBlockHostManifestOptions } from "./manifestOptions.js";
4
- /** Internal to the host: preview requests never carry credentials or follow redirects. */
5
- export declare function loadCustomBlockManifest(args: CustomBlockHostManifestOptions & {
6
- sandboxOrigin: string;
7
- signal: AbortSignal;
8
- onError: (error: unknown) => void;
9
- }): Promise<{
10
- status: "success";
11
- manifest: CustomBlockManifest;
12
- } | {
13
- status: "error";
14
- error: CustomBlockInitErrorInfo;
15
- }>;
16
- //# sourceMappingURL=loadCustomBlockManifest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loadCustomBlockManifest.d.ts","sourceRoot":"","sources":["../../src/lifecycle/loadCustomBlockManifest.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,mBAAmB,EAExB,MAAM,8CAA8C,CAAA;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAA;AAGjG,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAA;AAE1E,0FAA0F;AAC1F,wBAAsB,uBAAuB,CAC5C,IAAI,EAAE,8BAA8B,GAAG;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACjC,GACC,OAAO,CACP;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,GACpD;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,CACtD,CAiDA"}
@@ -1,65 +0,0 @@
1
- import { manifestSchema, } from "../protocol/manifest.js";
2
- import * as v from "valibot";
3
- import { isLocalCustomBlockUrl } from "../localBlockUrl.js";
4
- /** Internal to the host: preview requests never carry credentials or follow redirects. */
5
- export async function loadCustomBlockManifest(args) {
6
- const controller = new AbortController();
7
- const abort = () => controller.abort();
8
- args.signal.addEventListener("abort", abort, { once: true });
9
- const cancelled = new Promise((_resolve, reject) => {
10
- controller.signal.addEventListener("abort", () => reject(controller.signal.reason), { once: true });
11
- });
12
- if (args.signal.aborted) {
13
- controller.abort();
14
- }
15
- const timeout = args.manifestSource === "local"
16
- ? window.setTimeout(() => {
17
- controller.abort(new Error("Manifest loading timed out after 5000 ms."));
18
- }, 5_000)
19
- : undefined;
20
- try {
21
- const input = await Promise.race([
22
- args.manifestSource === "local"
23
- ? fetchLocalCustomBlockManifest(args.sandboxOrigin, controller.signal)
24
- : args.getPersistedManifest({ signal: controller.signal }),
25
- cancelled,
26
- ]);
27
- if (controller.signal.aborted) {
28
- throw new Error("Manifest loading was cancelled.");
29
- }
30
- return { status: "success", manifest: v.parse(manifestSchema, input) };
31
- }
32
- catch (error) {
33
- if (!args.signal.aborted) {
34
- args.onError(error);
35
- }
36
- return {
37
- status: "error",
38
- error: {
39
- code: "manifest_unavailable",
40
- message: "The custom block manifest is unavailable.",
41
- isRetryable: true,
42
- },
43
- };
44
- }
45
- finally {
46
- window.clearTimeout(timeout);
47
- args.signal.removeEventListener("abort", abort);
48
- }
49
- }
50
- async function fetchLocalCustomBlockManifest(origin, signal) {
51
- const url = new URL(origin);
52
- if (!isLocalCustomBlockUrl({ url, hostOrigin: window.location.origin })) {
53
- throw new Error("Preview requires a separate loopback origin.");
54
- }
55
- const response = await fetch(new URL("/manifest", url), {
56
- credentials: "omit",
57
- redirect: "error",
58
- cache: "no-store",
59
- signal,
60
- });
61
- if (!response.ok) {
62
- throw new Error(`Manifest request failed: HTTP ${response.status}.`);
63
- }
64
- return response.json();
65
- }
@@ -1,17 +0,0 @@
1
- import type { manifestSchema } from "../protocol/manifest.js";
2
- import type { InferInput } from "valibot";
3
- /** Selects the manifest source used during host initialization. */
4
- export type CustomBlockHostManifestOptions = {
5
- /** Calls getPersistedManifest for a saved definition or worker registry manifest. */
6
- manifestSource: "persisted";
7
- getPersistedManifest: (args: {
8
- signal: AbortSignal;
9
- }) => Promise<InferInput<typeof manifestSchema> | undefined>;
10
- } | {
11
- /**
12
- * Fetches /manifest from the loopback sandboxOrigin. No persisted fallback.
13
- * Local refers to the manifest server, not the host's environment.
14
- */
15
- manifestSource: "local";
16
- };
17
- //# sourceMappingURL=manifestOptions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifestOptions.d.ts","sourceRoot":"","sources":["../../src/lifecycle/manifestOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAA;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,mEAAmE;AACnE,MAAM,MAAM,8BAA8B,GACvC;IACA,qFAAqF;IACrF,cAAc,EAAE,WAAW,CAAA;IAC3B,oBAAoB,EAAE,CAAC,IAAI,EAAE;QAC5B,MAAM,EAAE,WAAW,CAAA;KACnB,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,GAAG,SAAS,CAAC,CAAA;CAC3D,GACD;IACA;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAA;CACtB,CAAA"}
@@ -1,6 +0,0 @@
1
- import type { HostToSandboxMessage, HostToSandboxMessageLegacy } from "../protocol/messages/hostToSandbox.js";
2
- /**
3
- * Normalizes outgoing page shapes for the sandbox's bridge protocol version.
4
- */
5
- export declare function normalizeHostToSandboxMessage(message: HostToSandboxMessage, bridgeProtocolVersion: number): HostToSandboxMessageLegacy;
6
- //# sourceMappingURL=normalizeHostToSandboxMessage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalizeHostToSandboxMessage.d.ts","sourceRoot":"","sources":["../../src/lifecycle/normalizeHostToSandboxMessage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,0BAA0B,EAC1B,MAAM,4DAA4D,CAAA;AAGnE;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE,oBAAoB,EAC7B,qBAAqB,EAAE,MAAM,GAC3B,0BAA0B,CAc5B"}
@@ -1,14 +0,0 @@
1
- import { normalizeToLegacyPage } from "./normalizePage.js";
2
- /**
3
- * Normalizes outgoing page shapes for the sandbox's bridge protocol version.
4
- */
5
- export function normalizeHostToSandboxMessage(message, bridgeProtocolVersion) {
6
- if (message.type !== "queryDataSourceResult" &&
7
- message.type !== "getPageResult" &&
8
- message.type !== "createPageResult" &&
9
- message.type !== "updatePageResult") {
10
- return message;
11
- }
12
- const normalizedMessage = normalizeToLegacyPage(message, bridgeProtocolVersion);
13
- return normalizedMessage;
14
- }
@@ -1,7 +0,0 @@
1
- import type { CreatePageResultMessage } from "../protocol/messages/createPageResult.js";
2
- import type { GetPageResultMessage } from "../protocol/messages/getPage.js";
3
- import type { HostToSandboxMessageLegacy } from "../protocol/messages/hostToSandbox.js";
4
- import type { QueryDataSourceResultMessage } from "../protocol/messages/queryDataSourceResult.js";
5
- import type { UpdatePageResultMessage } from "../protocol/messages/updatePageResult.js";
6
- export declare function normalizeToLegacyPage(message: CreatePageResultMessage | GetPageResultMessage | UpdatePageResultMessage | QueryDataSourceResultMessage, bridgeProtocolVersion: number): HostToSandboxMessageLegacy;
7
- //# sourceMappingURL=normalizePage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalizePage.d.ts","sourceRoot":"","sources":["../../src/lifecycle/normalizePage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+DAA+D,CAAA;AAC5G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAA;AAChG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4DAA4D,CAAA;AAC5G,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,oEAAoE,CAAA;AACtH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+DAA+D,CAAA;AAU5G,wBAAgB,qBAAqB,CACpC,OAAO,EACJ,uBAAuB,GACvB,oBAAoB,GACpB,uBAAuB,GACvB,4BAA4B,EAC/B,qBAAqB,EAAE,MAAM,GAC3B,0BAA0B,CA0B5B"}
@@ -1,47 +0,0 @@
1
- import { LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION, TEXT_FALLBACK_PROPERTY_PROTOCOL_VERSION, } from "../protocol/protocolVersion.js";
2
- import { unreachable } from "../utils.js";
3
- import { toLegacyPage, toLegacyQueryPage } from "./legacyPage.js";
4
- export function normalizeToLegacyPage(message, bridgeProtocolVersion) {
5
- if (bridgeProtocolVersion >= TEXT_FALLBACK_PROPERTY_PROTOCOL_VERSION) {
6
- return message;
7
- }
8
- if (message.status === "error") {
9
- return message;
10
- }
11
- switch (message.type) {
12
- case "queryDataSourceResult":
13
- if (bridgeProtocolVersion >= LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION) {
14
- return { ...message, items: message.items.map(toPreFallbackPage) };
15
- }
16
- return { ...message, items: message.items.map(toLegacyQueryPage) };
17
- case "getPageResult":
18
- case "createPageResult":
19
- case "updatePageResult":
20
- return {
21
- ...message,
22
- page: bridgeProtocolVersion >= LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION
23
- ? toPreFallbackPage(message.page)
24
- : toLegacyPage(toPreFallbackPage(message.page)),
25
- };
26
- default:
27
- return unreachable(message);
28
- }
29
- }
30
- function toPreFallbackPage(page) {
31
- return {
32
- ...page,
33
- properties: Object.fromEntries(Object.entries(page.properties).map(([name, property]) => {
34
- switch (property?.type) {
35
- case "unique_id":
36
- case "button":
37
- case "formula":
38
- case "location":
39
- case "rollup":
40
- case "verification":
41
- return [name, null];
42
- default:
43
- return [name, property];
44
- }
45
- })),
46
- };
47
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"localBlockUrl.d.ts","sourceRoot":"","sources":["../src/localBlockUrl.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EACrC,GAAG,EACH,UAAU,GACV,EAAE;IACF,GAAG,EAAE,GAAG,CAAA;IACR,UAAU,EAAE,MAAM,CAAA;CAClB,GAAG,OAAO,CAYV"}
@@ -1,89 +0,0 @@
1
- import {
2
- type CustomBlockManifest,
3
- manifestSchema,
4
- } from "@notionhq/custom-blocks-protocol/manifest.js"
5
- import type { CustomBlockInitErrorInfo } from "@notionhq/custom-blocks-protocol/messages/init.js"
6
- import * as v from "valibot"
7
- import { isLocalCustomBlockUrl } from "../localBlockUrl.js"
8
- import type { CustomBlockHostManifestOptions } from "./manifestOptions.js"
9
-
10
- /** Internal to the host: preview requests never carry credentials or follow redirects. */
11
- export async function loadCustomBlockManifest(
12
- args: CustomBlockHostManifestOptions & {
13
- sandboxOrigin: string
14
- signal: AbortSignal
15
- onError: (error: unknown) => void
16
- },
17
- ): Promise<
18
- | { status: "success"; manifest: CustomBlockManifest }
19
- | { status: "error"; error: CustomBlockInitErrorInfo }
20
- > {
21
- const controller = new AbortController()
22
- const abort = () => controller.abort()
23
- args.signal.addEventListener("abort", abort, { once: true })
24
- const cancelled = new Promise<never>((_resolve, reject) => {
25
- controller.signal.addEventListener(
26
- "abort",
27
- () => reject(controller.signal.reason),
28
- { once: true },
29
- )
30
- })
31
- if (args.signal.aborted) {
32
- controller.abort()
33
- }
34
- const timeout =
35
- args.manifestSource === "local"
36
- ? window.setTimeout(() => {
37
- controller.abort(
38
- new Error("Manifest loading timed out after 5000 ms."),
39
- )
40
- }, 5_000)
41
- : undefined
42
- try {
43
- const input = await Promise.race([
44
- args.manifestSource === "local"
45
- ? fetchLocalCustomBlockManifest(args.sandboxOrigin, controller.signal)
46
- : args.getPersistedManifest({ signal: controller.signal }),
47
- cancelled,
48
- ])
49
- if (controller.signal.aborted) {
50
- throw new Error("Manifest loading was cancelled.")
51
- }
52
- return { status: "success", manifest: v.parse(manifestSchema, input) }
53
- } catch (error) {
54
- if (!args.signal.aborted) {
55
- args.onError(error)
56
- }
57
- return {
58
- status: "error",
59
- error: {
60
- code: "manifest_unavailable",
61
- message: "The custom block manifest is unavailable.",
62
- isRetryable: true,
63
- },
64
- }
65
- } finally {
66
- window.clearTimeout(timeout)
67
- args.signal.removeEventListener("abort", abort)
68
- }
69
- }
70
-
71
- async function fetchLocalCustomBlockManifest(
72
- origin: string,
73
- signal: AbortSignal,
74
- ): Promise<unknown> {
75
- const url = new URL(origin)
76
- if (!isLocalCustomBlockUrl({ url, hostOrigin: window.location.origin })) {
77
- throw new Error("Preview requires a separate loopback origin.")
78
- }
79
- const response = await fetch(new URL("/manifest", url), {
80
- credentials: "omit",
81
- redirect: "error",
82
- cache: "no-store",
83
- signal,
84
- })
85
- if (!response.ok) {
86
- throw new Error(`Manifest request failed: HTTP ${response.status}.`)
87
- }
88
- return response.json()
89
- }
@@ -1,19 +0,0 @@
1
- import type { manifestSchema } from "@notionhq/custom-blocks-protocol/manifest.js"
2
- import type { InferInput } from "valibot"
3
-
4
- /** Selects the manifest source used during host initialization. */
5
- export type CustomBlockHostManifestOptions =
6
- | {
7
- /** Calls getPersistedManifest for a saved definition or worker registry manifest. */
8
- manifestSource: "persisted"
9
- getPersistedManifest: (args: {
10
- signal: AbortSignal
11
- }) => Promise<InferInput<typeof manifestSchema> | undefined>
12
- }
13
- | {
14
- /**
15
- * Fetches /manifest from the loopback sandboxOrigin. No persisted fallback.
16
- * Local refers to the manifest server, not the host's environment.
17
- */
18
- manifestSource: "local"
19
- }
@@ -1,27 +0,0 @@
1
- import type {
2
- HostToSandboxMessage,
3
- HostToSandboxMessageLegacy,
4
- } from "@notionhq/custom-blocks-protocol/messages/hostToSandbox.js"
5
- import { normalizeToLegacyPage } from "./normalizePage.js"
6
-
7
- /**
8
- * Normalizes outgoing page shapes for the sandbox's bridge protocol version.
9
- */
10
- export function normalizeHostToSandboxMessage(
11
- message: HostToSandboxMessage,
12
- bridgeProtocolVersion: number,
13
- ): HostToSandboxMessageLegacy {
14
- if (
15
- message.type !== "queryDataSourceResult" &&
16
- message.type !== "getPageResult" &&
17
- message.type !== "createPageResult" &&
18
- message.type !== "updatePageResult"
19
- ) {
20
- return message
21
- }
22
- const normalizedMessage = normalizeToLegacyPage(
23
- message,
24
- bridgeProtocolVersion,
25
- )
26
- return normalizedMessage
27
- }
@@ -1,71 +0,0 @@
1
- import type { CreatePageResultMessage } from "@notionhq/custom-blocks-protocol/messages/createPageResult.js"
2
- import type { GetPageResultMessage } from "@notionhq/custom-blocks-protocol/messages/getPage.js"
3
- import type { HostToSandboxMessageLegacy } from "@notionhq/custom-blocks-protocol/messages/hostToSandbox.js"
4
- import type { QueryDataSourceResultMessage } from "@notionhq/custom-blocks-protocol/messages/queryDataSourceResult.js"
5
- import type { UpdatePageResultMessage } from "@notionhq/custom-blocks-protocol/messages/updatePageResult.js"
6
- import type { notionPageDataSchema } from "@notionhq/custom-blocks-protocol/pages/page.js"
7
- import {
8
- LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION,
9
- TEXT_FALLBACK_PROPERTY_PROTOCOL_VERSION,
10
- } from "@notionhq/custom-blocks-protocol/protocolVersion.js"
11
- import type { InferOutput } from "valibot"
12
- import { unreachable } from "../utils.js"
13
- import { toLegacyPage, toLegacyQueryPage } from "./legacyPage.js"
14
-
15
- export function normalizeToLegacyPage(
16
- message:
17
- | CreatePageResultMessage
18
- | GetPageResultMessage
19
- | UpdatePageResultMessage
20
- | QueryDataSourceResultMessage,
21
- bridgeProtocolVersion: number,
22
- ): HostToSandboxMessageLegacy {
23
- if (bridgeProtocolVersion >= TEXT_FALLBACK_PROPERTY_PROTOCOL_VERSION) {
24
- return message
25
- }
26
- if (message.status === "error") {
27
- return message
28
- }
29
- switch (message.type) {
30
- case "queryDataSourceResult":
31
- if (bridgeProtocolVersion >= LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION) {
32
- return { ...message, items: message.items.map(toPreFallbackPage) }
33
- }
34
- return { ...message, items: message.items.map(toLegacyQueryPage) }
35
- case "getPageResult":
36
- case "createPageResult":
37
- case "updatePageResult":
38
- return {
39
- ...message,
40
- page:
41
- bridgeProtocolVersion >= LEGACY_PROPERTY_SHAPE_PROTOCOL_VERSION
42
- ? toPreFallbackPage(message.page)
43
- : toLegacyPage(toPreFallbackPage(message.page)),
44
- }
45
- default:
46
- return unreachable(message)
47
- }
48
- }
49
-
50
- function toPreFallbackPage(
51
- page: InferOutput<typeof notionPageDataSchema>,
52
- ): InferOutput<typeof notionPageDataSchema> {
53
- return {
54
- ...page,
55
- properties: Object.fromEntries(
56
- Object.entries(page.properties).map(([name, property]) => {
57
- switch (property?.type) {
58
- case "unique_id":
59
- case "button":
60
- case "formula":
61
- case "location":
62
- case "rollup":
63
- case "verification":
64
- return [name, null]
65
- default:
66
- return [name, property]
67
- }
68
- }),
69
- ),
70
- }
71
- }