@notionhq/custom-blocks 0.0.61 → 0.0.63
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 +4 -4
- package/bin/notion-custom-blocks/build.js +187 -0
- package/bin/notion-custom-blocks/cli.js +66 -0
- package/bin/notion-custom-blocks/tar.js +102 -0
- package/bin/notion-custom-blocks/upload.js +60 -0
- package/dist/bridge/messages/hostToSandbox.d.ts +32 -0
- package/dist/bridge/messages/hostToSandbox.d.ts.map +1 -1
- package/dist/bridge/messages/init.d.ts +16 -0
- package/dist/bridge/messages/init.d.ts.map +1 -1
- package/dist/bridge/messages/pageChanged.d.ts +16 -0
- package/dist/bridge/messages/pageChanged.d.ts.map +1 -1
- package/dist/bridge/pages/page.d.ts +24 -0
- package/dist/bridge/pages/page.d.ts.map +1 -1
- package/dist/bridge/pages/page.js +9 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/init.d.ts +2 -2
- package/dist/init.d.ts.map +1 -1
- package/dist/react/standalonePreview.js +1 -1
- package/dist/react/useCustomBlockInit.d.ts +2 -2
- package/dist/react/useCustomBlockInit.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/docs/block-location.md +16 -2
- package/docs/lifecycle.md +3 -3
- package/package.json +3 -2
- package/src/bridge/pages/page.ts +9 -0
- package/src/index.ts +1 -1
- package/src/init.ts +3 -3
- package/src/react/standalonePreview.ts +1 -1
- package/src/react/useCustomBlockInit.ts +2 -2
package/HOST.md
CHANGED
|
@@ -66,7 +66,7 @@ The host replies with exactly one `init`, which has two statuses. On success it
|
|
|
66
66
|
|
|
67
67
|
```ts
|
|
68
68
|
// host → sandbox
|
|
69
|
-
{ type: "init", status: "success", theme, blockId, parent, page: { id }, currentUser, dataSources: { bindings } }
|
|
69
|
+
{ type: "init", status: "success", theme, blockId, parent, page: { id, parent }, currentUser, dataSources: { bindings } }
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
On failure it carries `error: { code, message, isRetryable }` (`CustomBlockInitErrorInfo` / `customBlockInitErrorInfoSchema`, with `code` drawn from `CustomBlockInitErrorCode` / `customBlockInitErrorCodeSchema`). The SDK surfaces this as a `CustomBlockInitError`:
|
|
@@ -82,7 +82,7 @@ After `init`, narrower messages update live state without re-running the handsha
|
|
|
82
82
|
// host → sandbox, any time after init
|
|
83
83
|
{ type: "themeChanged", theme }
|
|
84
84
|
{ type: "parentChanged", parent }
|
|
85
|
-
{ type: "pageChanged", page: { id } }
|
|
85
|
+
{ type: "pageChanged", page: { id, parent } }
|
|
86
86
|
{ type: "dataSourcesChanged", dataSources: { bindings } }
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -112,7 +112,7 @@ Host implementers can use the API-specific aliases and schemas when shaping outb
|
|
|
112
112
|
|
|
113
113
|
Types:
|
|
114
114
|
|
|
115
|
-
- `CustomBlockPage` — the current page slice carried in `init.page` and `pageChanged
|
|
115
|
+
- `CustomBlockPage` — the current page slice carried in `init.page` and `pageChanged`: the containing page's `id` plus its own `parent` (a `NotionParent`), so the sandbox can tell a freestanding page from a database row. Hosts must re-send `pageChanged` when either field changes, including when the containing page moves without its ID changing.
|
|
116
116
|
- `NotionDataSourceBinding` — a single binding (collection pointer + schema + property mapping).
|
|
117
117
|
- `NotionDataSourceBindings` — keyed-by-semantic-key map of bindings, the shape carried in `init.dataSources` and `dataSourcesChanged`.
|
|
118
118
|
- `NotionDataSourcePageBridge` — wire shape for a single page (raw property IDs in `propertiesById`). The SDK derives the consumer-facing `NotionDataSourcePage` from it.
|
|
@@ -134,7 +134,7 @@ Messages sent from the sandbox to the host. Parse `window` `message` events with
|
|
|
134
134
|
|
|
135
135
|
| Wire type | Type / schema | Behavior |
|
|
136
136
|
| -------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
137
|
-
| `ready` | `ReadyMessage` / `readyMessageSchema` | One-shot handshake; carries `bridgeProtocolVersion`, `sdkVersion`, and the manifest.
|
|
137
|
+
| `ready` | `ReadyMessage` / `readyMessageSchema` | One-shot handshake; carries `bridgeProtocolVersion`, `sdkVersion`, and the manifest. |
|
|
138
138
|
| `queryDataSource` | `QueryDataSourceMessage` / `queryDataSourceMessageSchema` | `requestId`-keyed request for the current rows in a raw `dataSourceId`. `snapshotId` names the SDK result slot to update, so later refreshes for the same `useDataSource` call replace the same snapshot instead of creating a new one. |
|
|
139
139
|
| `createPage` | `CreatePageMessage` / `createPageMessageSchema` | `requestId`-keyed page creation; parent is `page_id` or `data_source_id`. |
|
|
140
140
|
| `getPage` | `GetPageMessage` / `getPageMessageSchema` | `requestId`-keyed page fetch by page id. |
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { packDirToTarGz } from "./tar.js";
|
|
6
|
+
export const BUILD_OUTPUT_SENTINEL = "<__notion_custom_block__>";
|
|
7
|
+
export const BUILD_OUTPUT_SENTINEL_CLOSE = "</__notion_custom_block__>";
|
|
8
|
+
const WORKER_ENTRY = "dist/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Build every `_tag: "custom_block"` view declared by the worker.
|
|
11
|
+
*
|
|
12
|
+
* Imports the worker bundle (`<cwd>/dist/index.js`), reads its runtime manifest,
|
|
13
|
+
* and runs the command specified (default `npm run build`)
|
|
14
|
+
*/
|
|
15
|
+
export async function buildCustomBlocks(args) {
|
|
16
|
+
const projectRoot = args.cwd ?? process.cwd();
|
|
17
|
+
const entryPath = path.resolve(projectRoot, WORKER_ENTRY);
|
|
18
|
+
const outDir = path.resolve(args.out);
|
|
19
|
+
const blocks = await readCustomBlocks(entryPath);
|
|
20
|
+
if (blocks.length === 0) {
|
|
21
|
+
return { blocks: [] };
|
|
22
|
+
}
|
|
23
|
+
const built = [];
|
|
24
|
+
for (const block of blocks) {
|
|
25
|
+
const bundleDir = path.join(outDir, block.key);
|
|
26
|
+
buildCustomBlock({ block, projectRoot, bundleDir });
|
|
27
|
+
const { checksumCrc32 } = packDirToTarGz(bundleDir);
|
|
28
|
+
built.push({ key: block.key, checksumCrc32, bundleDir });
|
|
29
|
+
}
|
|
30
|
+
return { blocks: built };
|
|
31
|
+
}
|
|
32
|
+
/** Print the build output as the sentinel-wrapped single-line JSON contract. */
|
|
33
|
+
export function printBuildOutput(output) {
|
|
34
|
+
process.stdout.write(`${BUILD_OUTPUT_SENTINEL}${JSON.stringify(output)}${BUILD_OUTPUT_SENTINEL_CLOSE}\n`);
|
|
35
|
+
}
|
|
36
|
+
async function readCustomBlocks(entryPath) {
|
|
37
|
+
const mod = await import(pathToFileURL(entryPath).href);
|
|
38
|
+
const worker = resolveWorker(mod);
|
|
39
|
+
const manifest = readProp(worker, "manifest");
|
|
40
|
+
const capabilities = readProp(manifest, "capabilities");
|
|
41
|
+
if (!Array.isArray(capabilities)) {
|
|
42
|
+
throw new Error(`worker manifest at ${entryPath} has no capabilities array`);
|
|
43
|
+
}
|
|
44
|
+
const blocks = [];
|
|
45
|
+
for (const capability of capabilities) {
|
|
46
|
+
const block = asCustomBlock(capability);
|
|
47
|
+
if (block) {
|
|
48
|
+
blocks.push(block);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return blocks;
|
|
52
|
+
}
|
|
53
|
+
function resolveWorker(mod) {
|
|
54
|
+
const top = readProp(mod, "default");
|
|
55
|
+
if (top === undefined) {
|
|
56
|
+
throw new Error("worker module has no default export");
|
|
57
|
+
}
|
|
58
|
+
const nested = readProp(top, "default");
|
|
59
|
+
return nested ?? top;
|
|
60
|
+
}
|
|
61
|
+
function readProp(value, key) {
|
|
62
|
+
if (typeof value !== "object" || value === null) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return value[key];
|
|
66
|
+
}
|
|
67
|
+
function asCustomBlock(value) {
|
|
68
|
+
if (typeof value !== "object" || value === null) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const record = value;
|
|
72
|
+
if (record._tag !== "custom_block") {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
if (typeof record.key !== "string") {
|
|
76
|
+
throw new Error("custom_block capability is missing a string key");
|
|
77
|
+
}
|
|
78
|
+
const config = record.config;
|
|
79
|
+
if (typeof config !== "object" || config === null) {
|
|
80
|
+
throw new Error(`custom_block "${record.key}" is missing config`);
|
|
81
|
+
}
|
|
82
|
+
const source = parseSource(record.key, config.source);
|
|
83
|
+
const dataSources = config.dataSources;
|
|
84
|
+
const manifest = config.manifest;
|
|
85
|
+
return {
|
|
86
|
+
key: record.key,
|
|
87
|
+
config: {
|
|
88
|
+
source,
|
|
89
|
+
...(isStringRecord(dataSources) ? { dataSources } : {}),
|
|
90
|
+
manifest,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function parseSource(key, value) {
|
|
95
|
+
if (typeof value !== "object" || value === null) {
|
|
96
|
+
throw new Error(`custom_block "${key}" is missing a source`);
|
|
97
|
+
}
|
|
98
|
+
const source = value;
|
|
99
|
+
if (source.type === "project") {
|
|
100
|
+
if (typeof source.path !== "string") {
|
|
101
|
+
throw new Error(`custom_block "${key}" project source is missing a string path`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
type: "project",
|
|
105
|
+
path: source.path,
|
|
106
|
+
...(typeof source.command === "string"
|
|
107
|
+
? { command: source.command }
|
|
108
|
+
: {}),
|
|
109
|
+
...(typeof source.output === "string" ? { output: source.output } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (source.type === "static") {
|
|
113
|
+
if (typeof source.path !== "string") {
|
|
114
|
+
throw new Error(`custom_block "${key}" static source is missing a string path`);
|
|
115
|
+
}
|
|
116
|
+
return { type: "static", path: source.path };
|
|
117
|
+
}
|
|
118
|
+
throw new Error(`custom_block "${key}" has an unsupported source type "${String(source.type)}" — this worker may need a newer @notionhq/workers`);
|
|
119
|
+
}
|
|
120
|
+
function isStringRecord(value) {
|
|
121
|
+
if (typeof value !== "object" || value === null) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return Object.values(value).every(v => typeof v === "string");
|
|
125
|
+
}
|
|
126
|
+
function buildCustomBlock(args) {
|
|
127
|
+
const { block, projectRoot, bundleDir } = args;
|
|
128
|
+
const sourceDir = resolveSourceDir(block.key, block.config.source, projectRoot);
|
|
129
|
+
fs.rmSync(bundleDir, { recursive: true, force: true });
|
|
130
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
131
|
+
fs.cpSync(sourceDir, bundleDir, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
const DEFAULT_BUILD_COMMAND = "npm run build";
|
|
134
|
+
const DEFAULT_OUTPUT_DIR = "dist";
|
|
135
|
+
function resolveSourceDir(key, source, projectRoot) {
|
|
136
|
+
if (source.type === "static") {
|
|
137
|
+
const dir = path.resolve(projectRoot, source.path);
|
|
138
|
+
if (!fs.existsSync(dir)) {
|
|
139
|
+
throw new Error(`custom_block "${key}" static dir not found: ${dir}`);
|
|
140
|
+
}
|
|
141
|
+
return dir;
|
|
142
|
+
}
|
|
143
|
+
const projectDir = path.resolve(projectRoot, source.path);
|
|
144
|
+
if (!fs.existsSync(projectDir)) {
|
|
145
|
+
throw new Error(`custom_block "${key}" project dir not found: ${projectDir}`);
|
|
146
|
+
}
|
|
147
|
+
installProjectDeps(key, projectDir);
|
|
148
|
+
const command = source.command ?? DEFAULT_BUILD_COMMAND;
|
|
149
|
+
runCommand(key, command, projectDir);
|
|
150
|
+
const outputDir = path.resolve(projectDir, source.output ?? DEFAULT_OUTPUT_DIR);
|
|
151
|
+
if (!fs.existsSync(outputDir)) {
|
|
152
|
+
throw new Error(`custom_block "${key}" build command "${command}" produced no output at ${outputDir}`);
|
|
153
|
+
}
|
|
154
|
+
return outputDir;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Install a `project` source's own dependencies before building it. `npm ci`
|
|
158
|
+
* when a lockfile is present (faster + deterministic), else `npm install`. No-op
|
|
159
|
+
* when the project has no package.json.
|
|
160
|
+
*/
|
|
161
|
+
function installProjectDeps(key, projectDir) {
|
|
162
|
+
if (!fs.existsSync(path.join(projectDir, "package.json"))) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const hasLockfile = fs.existsSync(path.join(projectDir, "package-lock.json"));
|
|
166
|
+
runCommand(key, hasLockfile ? "npm ci" : "npm install", projectDir);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Run a shell command in `cwd`. The child's stdout/stderr are forwarded to our
|
|
170
|
+
* stderr so build/install logs never contaminate the sentinel-wrapped JSON
|
|
171
|
+
* contract this tool writes to stdout.
|
|
172
|
+
*/
|
|
173
|
+
function runCommand(key, command, cwd) {
|
|
174
|
+
const result = spawnSync(command, { cwd, shell: true, encoding: "utf8" });
|
|
175
|
+
if (result.stdout) {
|
|
176
|
+
process.stderr.write(result.stdout);
|
|
177
|
+
}
|
|
178
|
+
if (result.stderr) {
|
|
179
|
+
process.stderr.write(result.stderr);
|
|
180
|
+
}
|
|
181
|
+
if (result.error) {
|
|
182
|
+
throw new Error(`custom_block "${key}" build command "${command}" failed to start: ${result.error.message}`);
|
|
183
|
+
}
|
|
184
|
+
if (result.status !== 0) {
|
|
185
|
+
throw new Error(`custom_block "${key}" build command "${command}" exited with code ${String(result.status)}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { buildCustomBlocks, printBuildOutput } from "./build.js";
|
|
3
|
+
import { parseUploadsInput, uploadViews } from "./upload.js";
|
|
4
|
+
export async function main(argv) {
|
|
5
|
+
const [command, ...rest] = argv;
|
|
6
|
+
switch (command) {
|
|
7
|
+
case "build":
|
|
8
|
+
return runBuild(rest);
|
|
9
|
+
case "upload":
|
|
10
|
+
return runUpload(rest);
|
|
11
|
+
default:
|
|
12
|
+
printUsage();
|
|
13
|
+
return command === undefined ? 0 : 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function runBuild(args) {
|
|
17
|
+
const flags = parseFlags(args);
|
|
18
|
+
const out = flags.out;
|
|
19
|
+
if (out === undefined) {
|
|
20
|
+
process.stderr.write("usage: notion-custom-blocks build --out <dir>\n");
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
const output = await buildCustomBlocks({ out });
|
|
24
|
+
printBuildOutput(output);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
async function runUpload(args) {
|
|
28
|
+
const flags = parseFlags(args);
|
|
29
|
+
const raw = flags.uploads;
|
|
30
|
+
if (raw === undefined) {
|
|
31
|
+
process.stderr.write("usage: notion-custom-blocks upload --uploads '<json>'\n");
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
const uploads = parseUploadsInput(raw);
|
|
35
|
+
const output = await uploadViews(uploads);
|
|
36
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
function parseFlags(args) {
|
|
40
|
+
const flags = {};
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
const arg = args[i];
|
|
43
|
+
if (arg === undefined || !arg.startsWith("--")) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const name = arg.slice(2);
|
|
47
|
+
const value = args[i + 1];
|
|
48
|
+
if (value === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
flags[name] = value;
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
return flags;
|
|
55
|
+
}
|
|
56
|
+
function printUsage() {
|
|
57
|
+
process.stderr.write("Invalid command. See notion-custom-blocks source.");
|
|
58
|
+
}
|
|
59
|
+
main(process.argv.slice(2))
|
|
60
|
+
.then(code => {
|
|
61
|
+
process.exitCode = code;
|
|
62
|
+
})
|
|
63
|
+
.catch((error) => {
|
|
64
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as zlib from "node:zlib";
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic gzipped-tarball packing for custom-block bundles, shared by the
|
|
6
|
+
* `build` and `upload` phases.
|
|
7
|
+
*/
|
|
8
|
+
const BLOCK_SIZE = 512;
|
|
9
|
+
/**
|
|
10
|
+
* Pack a directory into a deterministic gzipped tarball and return both the
|
|
11
|
+
* bytes and their base64 big-endian crc32 checksum (the form
|
|
12
|
+
* `CreateCustomBlockDeploy` signs into the presigned PUT URL).
|
|
13
|
+
*/
|
|
14
|
+
export function packDirToTarGz(dir) {
|
|
15
|
+
const entries = collectFiles(dir);
|
|
16
|
+
const tar = writeUstarArchive(entries);
|
|
17
|
+
const tarGz = zlib.gzipSync(tar, {
|
|
18
|
+
level: zlib.constants.Z_BEST_COMPRESSION,
|
|
19
|
+
});
|
|
20
|
+
// Zero the gzip header's MTIME field (bytes 4..7) so repeated packs of the
|
|
21
|
+
// same input are byte-identical. The build phase's crc32 must match the
|
|
22
|
+
// bytes the upload phase PUTs, and gzip otherwise stamps the current time.
|
|
23
|
+
if (tarGz.length >= 8) {
|
|
24
|
+
tarGz.writeUInt32LE(0, 4);
|
|
25
|
+
}
|
|
26
|
+
return { tarGz, checksumCrc32: crc32Base64(tarGz) };
|
|
27
|
+
}
|
|
28
|
+
/** Base64-encoded big-endian crc32, matching the server's `CRC32_BASE64_REGEX`. */
|
|
29
|
+
export function crc32Base64(data) {
|
|
30
|
+
const checksum = zlib.crc32(data) >>> 0;
|
|
31
|
+
const buf = Buffer.alloc(4);
|
|
32
|
+
buf.writeUInt32BE(checksum);
|
|
33
|
+
return buf.toString("base64");
|
|
34
|
+
}
|
|
35
|
+
/** Recursively collect regular files under `dir`, sorted by archive path. */
|
|
36
|
+
function collectFiles(dir) {
|
|
37
|
+
const entries = [];
|
|
38
|
+
function walk(absDir, relDir) {
|
|
39
|
+
const dirents = fs.readdirSync(absDir, { withFileTypes: true });
|
|
40
|
+
for (const dirent of dirents) {
|
|
41
|
+
const abs = path.join(absDir, dirent.name);
|
|
42
|
+
const rel = relDir === "" ? dirent.name : `${relDir}/${dirent.name}`;
|
|
43
|
+
if (dirent.isDirectory()) {
|
|
44
|
+
walk(abs, rel);
|
|
45
|
+
}
|
|
46
|
+
else if (dirent.isFile()) {
|
|
47
|
+
entries.push({ name: rel, contents: fs.readFileSync(abs) });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
walk(dir, "");
|
|
52
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
53
|
+
return entries;
|
|
54
|
+
}
|
|
55
|
+
/** Serialize entries as a minimal POSIX ustar archive. */
|
|
56
|
+
function writeUstarArchive(entries) {
|
|
57
|
+
const chunks = [];
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
chunks.push(writeUstarHeader(entry.name, entry.contents.length));
|
|
60
|
+
chunks.push(entry.contents);
|
|
61
|
+
const remainder = entry.contents.length % BLOCK_SIZE;
|
|
62
|
+
if (remainder !== 0) {
|
|
63
|
+
chunks.push(Buffer.alloc(BLOCK_SIZE - remainder));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Two zero blocks mark end-of-archive.
|
|
67
|
+
chunks.push(Buffer.alloc(BLOCK_SIZE * 2));
|
|
68
|
+
return Buffer.concat(chunks);
|
|
69
|
+
}
|
|
70
|
+
function writeUstarHeader(name, size) {
|
|
71
|
+
const header = Buffer.alloc(BLOCK_SIZE);
|
|
72
|
+
const nameBytes = Buffer.from(name, "utf8");
|
|
73
|
+
if (nameBytes.length > 100) {
|
|
74
|
+
// ustar splits long paths into name/prefix; keep bundles simple by
|
|
75
|
+
// requiring short paths rather than emitting a GNU/PAX extension.
|
|
76
|
+
throw new Error(`tar entry path too long (max 100 bytes): ${name}`);
|
|
77
|
+
}
|
|
78
|
+
nameBytes.copy(header, 0);
|
|
79
|
+
writeOctal(header, 100, 8, 0o644); // mode
|
|
80
|
+
writeOctal(header, 108, 8, 0); // uid
|
|
81
|
+
writeOctal(header, 116, 8, 0); // gid
|
|
82
|
+
writeOctal(header, 124, 12, size); // size
|
|
83
|
+
writeOctal(header, 136, 12, 0); // mtime
|
|
84
|
+
header.write("0", 156, 1, "ascii"); // typeflag: regular file
|
|
85
|
+
header.write("ustar\0", 257, 6, "ascii"); // magic
|
|
86
|
+
header.write("00", 263, 2, "ascii"); // version
|
|
87
|
+
// Checksum field: spaces during computation, then octal value.
|
|
88
|
+
header.fill(" ", 148, 156);
|
|
89
|
+
let checksum = 0;
|
|
90
|
+
for (let i = 0; i < BLOCK_SIZE; i++) {
|
|
91
|
+
checksum += header[i] ?? 0;
|
|
92
|
+
}
|
|
93
|
+
header.write(checksum.toString(8).padStart(6, "0"), 148, 6, "ascii");
|
|
94
|
+
header.write("\0 ", 154, 2, "ascii");
|
|
95
|
+
return header;
|
|
96
|
+
}
|
|
97
|
+
function writeOctal(header, offset, length, value) {
|
|
98
|
+
// Numeric fields are octal ASCII, null-terminated, right-justified.
|
|
99
|
+
const str = value.toString(8).padStart(length - 1, "0");
|
|
100
|
+
header.write(str, offset, length - 1, "ascii");
|
|
101
|
+
header.write("\0", offset + length - 1, 1, "ascii");
|
|
102
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { packDirToTarGz } from "./tar.js";
|
|
2
|
+
const DEFAULT_DEPS = { fetch: globalThis.fetch };
|
|
3
|
+
export async function uploadViews(uploads, deps = DEFAULT_DEPS) {
|
|
4
|
+
const uploaded = {};
|
|
5
|
+
for (const [key, target] of Object.entries(uploads)) {
|
|
6
|
+
const { tarGz, checksumCrc32 } = packDirToTarGz(target.bundleDir);
|
|
7
|
+
const response = await deps.fetch(target.uploadUrl, {
|
|
8
|
+
method: "PUT",
|
|
9
|
+
headers: {
|
|
10
|
+
"Content-Type": "application/gzip",
|
|
11
|
+
"x-amz-checksum-crc32": checksumCrc32,
|
|
12
|
+
},
|
|
13
|
+
body: new Uint8Array(tarGz),
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
const text = await safeReadText(response);
|
|
17
|
+
throw new Error(`upload failed for block "${key}": ${response.status} ${response.statusText}${text ? `\n${text}` : ""}`);
|
|
18
|
+
}
|
|
19
|
+
uploaded[key] = true;
|
|
20
|
+
}
|
|
21
|
+
return { uploaded };
|
|
22
|
+
}
|
|
23
|
+
export function parseUploadsInput(raw) {
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw new Error(`--uploads is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
30
|
+
}
|
|
31
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
32
|
+
throw new Error("--uploads must be a JSON object of { key: target }");
|
|
33
|
+
}
|
|
34
|
+
const result = {};
|
|
35
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
36
|
+
if (typeof value !== "object" || value === null) {
|
|
37
|
+
throw new Error(`--uploads["${key}"] must be an object`);
|
|
38
|
+
}
|
|
39
|
+
const record = value;
|
|
40
|
+
if (typeof record.uploadUrl !== "string") {
|
|
41
|
+
throw new Error(`--uploads["${key}"].uploadUrl must be a string`);
|
|
42
|
+
}
|
|
43
|
+
if (typeof record.bundleDir !== "string") {
|
|
44
|
+
throw new Error(`--uploads["${key}"].bundleDir must be a string`);
|
|
45
|
+
}
|
|
46
|
+
result[key] = {
|
|
47
|
+
uploadUrl: record.uploadUrl,
|
|
48
|
+
bundleDir: record.bundleDir,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
async function safeReadText(response) {
|
|
54
|
+
try {
|
|
55
|
+
return await response.text();
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -25,6 +25,22 @@ export declare const hostToSandboxMessageSchema: v.VariantSchema<"type", [v.Vari
|
|
|
25
25
|
}, undefined>], undefined>;
|
|
26
26
|
readonly page: v.ObjectSchema<{
|
|
27
27
|
readonly id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
28
|
+
readonly parent: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
29
|
+
readonly type: v.LiteralSchema<"page_id", undefined>;
|
|
30
|
+
readonly page_id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
31
|
+
}, undefined>, v.ObjectSchema<{
|
|
32
|
+
readonly type: v.LiteralSchema<"data_source_id", undefined>;
|
|
33
|
+
readonly data_source_id: v.CustomSchema<import("../ids.js").NotionDataSourceId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
34
|
+
}, undefined>, v.ObjectSchema<{
|
|
35
|
+
readonly type: v.LiteralSchema<"workspace", undefined>;
|
|
36
|
+
readonly workspace: v.LiteralSchema<true, undefined>;
|
|
37
|
+
}, undefined>, v.ObjectSchema<{
|
|
38
|
+
readonly type: v.LiteralSchema<"block_id", undefined>;
|
|
39
|
+
readonly block_id: v.CustomSchema<import("../ids.js").NotionBlockId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
40
|
+
}, undefined>, v.ObjectSchema<{
|
|
41
|
+
readonly type: v.LiteralSchema<"agent_id", undefined>;
|
|
42
|
+
readonly agent_id: v.CustomSchema<import("../ids.js").NotionAgentId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
43
|
+
}, undefined>], undefined>;
|
|
28
44
|
}, undefined>;
|
|
29
45
|
readonly dataSources: v.ObjectSchema<{
|
|
30
46
|
readonly bindings: v.RecordSchema<v.StringSchema<undefined>, v.ObjectSchema<{
|
|
@@ -216,6 +232,22 @@ export declare const hostToSandboxMessageSchema: v.VariantSchema<"type", [v.Vari
|
|
|
216
232
|
readonly type: v.LiteralSchema<"pageChanged", undefined>;
|
|
217
233
|
readonly page: v.ObjectSchema<{
|
|
218
234
|
readonly id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
235
|
+
readonly parent: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
236
|
+
readonly type: v.LiteralSchema<"page_id", undefined>;
|
|
237
|
+
readonly page_id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
238
|
+
}, undefined>, v.ObjectSchema<{
|
|
239
|
+
readonly type: v.LiteralSchema<"data_source_id", undefined>;
|
|
240
|
+
readonly data_source_id: v.CustomSchema<import("../ids.js").NotionDataSourceId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
241
|
+
}, undefined>, v.ObjectSchema<{
|
|
242
|
+
readonly type: v.LiteralSchema<"workspace", undefined>;
|
|
243
|
+
readonly workspace: v.LiteralSchema<true, undefined>;
|
|
244
|
+
}, undefined>, v.ObjectSchema<{
|
|
245
|
+
readonly type: v.LiteralSchema<"block_id", undefined>;
|
|
246
|
+
readonly block_id: v.CustomSchema<import("../ids.js").NotionBlockId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
247
|
+
}, undefined>, v.ObjectSchema<{
|
|
248
|
+
readonly type: v.LiteralSchema<"agent_id", undefined>;
|
|
249
|
+
readonly agent_id: v.CustomSchema<import("../ids.js").NotionAgentId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
250
|
+
}, undefined>], undefined>;
|
|
219
251
|
}, undefined>;
|
|
220
252
|
}, undefined>, v.ObjectSchema<{
|
|
221
253
|
readonly type: v.LiteralSchema<"currentUserChanged", undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostToSandbox.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/hostToSandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAkB5B;;GAEG;AACH,eAAO,MAAM,0BAA0B
|
|
1
|
+
{"version":3,"file":"hostToSandbox.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/hostToSandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAkB5B;;GAEG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAerC,CAAA;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,WAAW,CAC/C,OAAO,0BAA0B,CACjC,CAAA"}
|
|
@@ -41,6 +41,22 @@ export declare const initMessageSchema: v.VariantSchema<"status", [v.ObjectSchem
|
|
|
41
41
|
}, undefined>], undefined>;
|
|
42
42
|
readonly page: v.ObjectSchema<{
|
|
43
43
|
readonly id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
44
|
+
readonly parent: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
45
|
+
readonly type: v.LiteralSchema<"page_id", undefined>;
|
|
46
|
+
readonly page_id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
47
|
+
}, undefined>, v.ObjectSchema<{
|
|
48
|
+
readonly type: v.LiteralSchema<"data_source_id", undefined>;
|
|
49
|
+
readonly data_source_id: v.CustomSchema<import("../ids.js").NotionDataSourceId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
50
|
+
}, undefined>, v.ObjectSchema<{
|
|
51
|
+
readonly type: v.LiteralSchema<"workspace", undefined>;
|
|
52
|
+
readonly workspace: v.LiteralSchema<true, undefined>;
|
|
53
|
+
}, undefined>, v.ObjectSchema<{
|
|
54
|
+
readonly type: v.LiteralSchema<"block_id", undefined>;
|
|
55
|
+
readonly block_id: v.CustomSchema<import("../ids.js").NotionBlockId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
56
|
+
}, undefined>, v.ObjectSchema<{
|
|
57
|
+
readonly type: v.LiteralSchema<"agent_id", undefined>;
|
|
58
|
+
readonly agent_id: v.CustomSchema<import("../ids.js").NotionAgentId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
59
|
+
}, undefined>], undefined>;
|
|
44
60
|
}, undefined>;
|
|
45
61
|
readonly dataSources: v.ObjectSchema<{
|
|
46
62
|
readonly bindings: v.RecordSchema<v.StringSchema<undefined>, v.ObjectSchema<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAE5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AASxD,eAAO,MAAM,8BAA8B,2BAAa,CAAA;AAExD,MAAM,MAAM,wBAAwB,GACjC,UAAU,GACV,eAAe,GACf,sBAAsB,GACtB,kBAAkB,GAClB,0BAA0B,GAC1B,8BAA8B,GAC9B,qBAAqB,GACrB,0BAA0B,GAC1B,6BAA6B,GAC7B,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,eAAe,GACf,cAAc,GACd,eAAe,GACf,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEhB,MAAM,MAAM,wBAAwB,GACnC,oBAAoB,CAAC,wBAAwB,CAAC,CAAA;AAE/C,eAAO,MAAM,8BAA8B;;;;aAIzC,CAAA;AAEF,qBAAa,oBACZ,SAAQ,KACR,YAAW,oBAAoB;gBAEnB,KAAK,EAAE,wBAAwB;IAO3C,IAAI,EAAE,wBAAwB,CAAA;IAC9B,WAAW,EAAE,OAAO,CAAA;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAE5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AASxD,eAAO,MAAM,8BAA8B,2BAAa,CAAA;AAExD,MAAM,MAAM,wBAAwB,GACjC,UAAU,GACV,eAAe,GACf,sBAAsB,GACtB,kBAAkB,GAClB,0BAA0B,GAC1B,8BAA8B,GAC9B,qBAAqB,GACrB,0BAA0B,GAC1B,6BAA6B,GAC7B,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,eAAe,GACf,cAAc,GACd,eAAe,GACf,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEhB,MAAM,MAAM,wBAAwB,GACnC,oBAAoB,CAAC,wBAAwB,CAAC,CAAA;AAE/C,eAAO,MAAM,8BAA8B;;;;aAIzC,CAAA;AAEF,qBAAa,oBACZ,SAAQ,KACR,YAAW,oBAAoB;gBAEnB,KAAK,EAAE,wBAAwB;IAO3C,IAAI,EAAE,wBAAwB,CAAA;IAC9B,WAAW,EAAE,OAAO,CAAA;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAkB5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
|
|
@@ -6,6 +6,22 @@ export declare const pageChangedMessageSchema: v.ObjectSchema<{
|
|
|
6
6
|
readonly type: v.LiteralSchema<"pageChanged", undefined>;
|
|
7
7
|
readonly page: v.ObjectSchema<{
|
|
8
8
|
readonly id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
9
|
+
readonly parent: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
10
|
+
readonly type: v.LiteralSchema<"page_id", undefined>;
|
|
11
|
+
readonly page_id: v.CustomSchema<import("../ids.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
12
|
+
}, undefined>, v.ObjectSchema<{
|
|
13
|
+
readonly type: v.LiteralSchema<"data_source_id", undefined>;
|
|
14
|
+
readonly data_source_id: v.CustomSchema<import("../ids.js").NotionDataSourceId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
15
|
+
}, undefined>, v.ObjectSchema<{
|
|
16
|
+
readonly type: v.LiteralSchema<"workspace", undefined>;
|
|
17
|
+
readonly workspace: v.LiteralSchema<true, undefined>;
|
|
18
|
+
}, undefined>, v.ObjectSchema<{
|
|
19
|
+
readonly type: v.LiteralSchema<"block_id", undefined>;
|
|
20
|
+
readonly block_id: v.CustomSchema<import("../ids.js").NotionBlockId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
21
|
+
}, undefined>, v.ObjectSchema<{
|
|
22
|
+
readonly type: v.LiteralSchema<"agent_id", undefined>;
|
|
23
|
+
readonly agent_id: v.CustomSchema<import("../ids.js").NotionAgentId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
24
|
+
}, undefined>], undefined>;
|
|
9
25
|
}, undefined>;
|
|
10
26
|
}, undefined>;
|
|
11
27
|
export type PageChangedMessage = v.InferOutput<typeof pageChangedMessageSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageChanged.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/pageChanged.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAG5B;;GAEG;AACH,eAAO,MAAM,wBAAwB
|
|
1
|
+
{"version":3,"file":"pageChanged.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/messages/pageChanged.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAG5B;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;aAGnC,CAAA;AAEF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAA"}
|
|
@@ -6,8 +6,32 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as v from "valibot";
|
|
8
8
|
export type { NotionPageId } from "../ids.js";
|
|
9
|
+
/**
|
|
10
|
+
* The custom block's nearest enclosing page ancestor, carried in `init.page` and `pageChanged`.
|
|
11
|
+
*/
|
|
9
12
|
export declare const customBlockPageSchema: v.ObjectSchema<{
|
|
10
13
|
readonly id: v.CustomSchema<import("./page.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* The containing page's own parent. It lets a block distinguish a freestanding page from a
|
|
16
|
+
* database row without a round trip. Not to be confused with the top-level `parent` runtime
|
|
17
|
+
* value, which is the custom block's own parent.
|
|
18
|
+
*/
|
|
19
|
+
readonly parent: v.VariantSchema<"type", [v.ObjectSchema<{
|
|
20
|
+
readonly type: v.LiteralSchema<"page_id", undefined>;
|
|
21
|
+
readonly page_id: v.CustomSchema<import("./page.js").NotionPageId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
22
|
+
}, undefined>, v.ObjectSchema<{
|
|
23
|
+
readonly type: v.LiteralSchema<"data_source_id", undefined>;
|
|
24
|
+
readonly data_source_id: v.CustomSchema<import("../ids.js").NotionDataSourceId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
25
|
+
}, undefined>, v.ObjectSchema<{
|
|
26
|
+
readonly type: v.LiteralSchema<"workspace", undefined>;
|
|
27
|
+
readonly workspace: v.LiteralSchema<true, undefined>;
|
|
28
|
+
}, undefined>, v.ObjectSchema<{
|
|
29
|
+
readonly type: v.LiteralSchema<"block_id", undefined>;
|
|
30
|
+
readonly block_id: v.CustomSchema<import("../ids.js").NotionBlockId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
31
|
+
}, undefined>, v.ObjectSchema<{
|
|
32
|
+
readonly type: v.LiteralSchema<"agent_id", undefined>;
|
|
33
|
+
readonly agent_id: v.CustomSchema<import("../ids.js").NotionAgentId, v.ErrorMessage<v.CustomIssue> | undefined>;
|
|
34
|
+
}, undefined>], undefined>;
|
|
11
35
|
}, undefined>;
|
|
12
36
|
export type CustomBlockPage = v.InferOutput<typeof customBlockPageSchema>;
|
|
13
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/pages/page.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAI5B,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,eAAO,MAAM,qBAAqB;;
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/bridge/pages/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,17 @@
|
|
|
7
7
|
import * as v from "valibot";
|
|
8
8
|
import { notionDataSourceIdSchema, notionPageIdSchema } from "../ids.js";
|
|
9
9
|
import { notionParentSchema } from "../parent.js";
|
|
10
|
+
/**
|
|
11
|
+
* The custom block's nearest enclosing page ancestor, carried in `init.page` and `pageChanged`.
|
|
12
|
+
*/
|
|
10
13
|
export const customBlockPageSchema = v.object({
|
|
11
14
|
id: notionPageIdSchema,
|
|
15
|
+
/**
|
|
16
|
+
* The containing page's own parent. It lets a block distinguish a freestanding page from a
|
|
17
|
+
* database row without a round trip. Not to be confused with the top-level `parent` runtime
|
|
18
|
+
* value, which is the custom block's own parent.
|
|
19
|
+
*/
|
|
20
|
+
parent: notionParentSchema,
|
|
12
21
|
});
|
|
13
22
|
/**
|
|
14
23
|
* Parent reference accepted by `pages.create` / `pages.update` inputs.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,6 @@ export type { NotionParent } from "./bridge/parent.js";
|
|
|
32
32
|
export { pages, users } from "./bridge/sandboxClient.js";
|
|
33
33
|
export type { NotionTheme } from "./bridge/theme.js";
|
|
34
34
|
export { type CustomBlockState, customBlock } from "./customBlock.js";
|
|
35
|
-
export { type
|
|
35
|
+
export { type CustomBlockInitPayload, type InitCustomBlockOptions, initCustomBlock, NotInIframeError, } from "./init.js";
|
|
36
36
|
export * from "./types.js";
|
|
37
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,oCAAoC,CAAA;AAC3C,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAA;AACpF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EACX,wCAAwC,EACxC,wCAAwC,GACxC,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,YAAY,EACX,4BAA4B,EAC5B,4BAA4B,GAC5B,MAAM,yCAAyC,CAAA;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,YAAY,EACX,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC/E,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EACX,6BAA6B,EAC7B,6BAA6B,GAC7B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,mCAAmC,EACnC,mCAAmC,GACnC,MAAM,4CAA4C,CAAA;AACnD,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,0BAA0B,EAC1B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACX,sBAAsB,EACtB,gBAAgB,GAChB,MAAM,oCAAoC,CAAA;AAC3C,YAAY,EACX,oBAAoB,EACpB,+BAA+B,EAC/B,gCAAgC,GAChC,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAA;AACpF,YAAY,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EACX,wCAAwC,EACxC,wCAAwC,GACxC,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GACjB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,GACrB,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,YAAY,EACX,4BAA4B,EAC5B,4BAA4B,GAC5B,MAAM,yCAAyC,CAAA;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,YAAY,EACX,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GAChB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC/E,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACX,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EACX,6BAA6B,EAC7B,6BAA6B,GAC7B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACX,mCAAmC,EACnC,mCAAmC,GACnC,MAAM,4CAA4C,CAAA;AACnD,YAAY,EACX,8BAA8B,EAC9B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,YAAY,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,0BAA0B,EAC1B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACN,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,eAAe,EACf,gBAAgB,GAChB,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA"}
|
package/dist/init.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { NotionUser } from "./bridge/users/user.js";
|
|
|
8
8
|
/**
|
|
9
9
|
* The payload sent by the host in the `init` message in response to the sandbox's `ready` message.
|
|
10
10
|
*/
|
|
11
|
-
export type
|
|
11
|
+
export type CustomBlockInitPayload = {
|
|
12
12
|
theme: NotionTheme;
|
|
13
13
|
blockId: NotionBlockId;
|
|
14
14
|
parent: NotionParent;
|
|
@@ -49,5 +49,5 @@ export type InitCustomBlockOptions = {
|
|
|
49
49
|
* Mount your React tree (or call any SDK hook / `customBlock.subscribe`) only after the
|
|
50
50
|
* returned promise resolves.
|
|
51
51
|
*/
|
|
52
|
-
export declare function initCustomBlock(opts?: InitCustomBlockOptions): Promise<
|
|
52
|
+
export declare function initCustomBlock(opts?: InitCustomBlockOptions): Promise<CustomBlockInitPayload>;
|
|
53
53
|
//# sourceMappingURL=init.d.ts.map
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAEN,KAAK,wBAAwB,EAE7B,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAExD;;GAEG;AACH,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAEN,KAAK,wBAAwB,EAE7B,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAExD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACpC,KAAK,EAAE,WAAW,CAAA;IAClB,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;CAC/B,CAAA;AAED;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC9B,OAAO,GAAE,MAA8B;IAOnD,IAAI,EAAE,wBAAwB,CAAA;IAC9B,WAAW,EAAE,OAAO,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACpC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AASD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC9B,IAAI,GAAE,sBAA2B,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CAyDjC"}
|
|
@@ -10,7 +10,7 @@ export function seedStandalonePreviewState() {
|
|
|
10
10
|
theme: "light",
|
|
11
11
|
blockId: previewBlockId,
|
|
12
12
|
parent: { type: "page_id", page_id: previewPageId },
|
|
13
|
-
page: { id: previewPageId },
|
|
13
|
+
page: { id: previewPageId, parent: { type: "workspace", workspace: true } },
|
|
14
14
|
dataSources: { bindings: {} },
|
|
15
15
|
currentUser: {
|
|
16
16
|
object: "user",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomBlockInitError } from "../bridge/messages/init.js";
|
|
2
|
-
import { type
|
|
2
|
+
import { type CustomBlockInitPayload, type InitCustomBlockOptions, NotInIframeError } from "../init.js";
|
|
3
3
|
export type CustomBlockInitFailure = CustomBlockInitError | NotInIframeError;
|
|
4
4
|
/**
|
|
5
5
|
* Discriminated state returned by {@link useCustomBlockInit}.
|
|
@@ -20,7 +20,7 @@ export type UseCustomBlockInitResult = {
|
|
|
20
20
|
} | {
|
|
21
21
|
isLoaded: true;
|
|
22
22
|
error: undefined;
|
|
23
|
-
initial:
|
|
23
|
+
initial: CustomBlockInitPayload;
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
26
|
* React wrapper around {@link initCustomBlock}. Kicks off the SDK ↔ host
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCustomBlockInit.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useCustomBlockInit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"useCustomBlockInit.d.ts","sourceRoot":"","sources":["../../../../home/runner/work/custom-blocks/custom-blocks/sdk/src/react/useCustomBlockInit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EACN,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAE3B,gBAAgB,EAChB,MAAM,YAAY,CAAA;AAEnB,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,GAAG,gBAAgB,CAAA;AAE5E;;;;;;;;;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,sBAAsB,CAAA;CAAE,GAClD;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,sBAAsB,CAAA;CAAE,CAAA;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,CAAC,EAAE,sBAAsB,GAC3B,wBAAwB,CA8B1B"}
|
package/dist/version.js
CHANGED
package/docs/block-location.md
CHANGED
|
@@ -63,12 +63,26 @@ export function AgentInstructionBadge() {
|
|
|
63
63
|
|
|
64
64
|
Returns the nearest enclosing `page` / `collection_view_page` ancestor.
|
|
65
65
|
|
|
66
|
-
Re-renders when the host sends a block location update.
|
|
66
|
+
Re-renders when the host sends a block location update — including when the containing page itself moves (its `parent` changes) without the page ID changing.
|
|
67
67
|
|
|
68
68
|
```ts
|
|
69
|
-
function usePage():
|
|
69
|
+
function usePage(): CustomBlockPage;
|
|
70
|
+
|
|
71
|
+
type CustomBlockPage = {
|
|
72
|
+
id: NotionPageId;
|
|
73
|
+
parent: NotionParent; // the containing page's own parent
|
|
74
|
+
};
|
|
70
75
|
```
|
|
71
76
|
|
|
77
|
+
`page.parent` allows determining if the custom block is in a freestanding page or part of a database. Don't confuse it with `useParent()`, which is the custom block's own parent.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
const page = usePage();
|
|
81
|
+
const isInsideDatabaseRow = page.parent.type === "data_source_id";
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For anything beyond location — title, icon, properties — fetch the page through the pages API: `pages.get(page.id)`.
|
|
85
|
+
|
|
72
86
|
For non-React renderers, use `customBlock.getPage()` after `initCustomBlock()` resolves.
|
|
73
87
|
|
|
74
88
|
### `useTheme()`
|
package/docs/lifecycle.md
CHANGED
|
@@ -4,7 +4,7 @@ The SDK ↔ host handshake, the React wrapper that runs it, and the auto-resize
|
|
|
4
4
|
|
|
5
5
|
## Handshake
|
|
6
6
|
|
|
7
|
-
`initCustomBlock()` posts `ready` to `window.parent` and awaits the host's `init` (theme, block ID/parent/page ID, current user, and `dataSources: { bindings }` keyed by semantic data-source key, which the SDK resolves against the manifest). The promise resolves with the normalized initial state, captured in `
|
|
7
|
+
`initCustomBlock()` posts `ready` to `window.parent` and awaits the host's `init` (theme, block ID/parent/page ID, current user, and `dataSources: { bindings }` keyed by semantic data-source key, which the SDK resolves against the manifest). The promise resolves with the normalized initial state, captured in `CustomBlockInitPayload` — `await` it before mounting React so hooks always see populated state.
|
|
8
8
|
|
|
9
9
|
- Default `timeoutMs` is 15000; rejects with `CustomBlockInitError` code `init_timeout` if the host doesn't respond.
|
|
10
10
|
- In a top-level browser tab (no parent frame), rejects with `NotInIframeError` code `not_in_iframe`. `<NotionCustomBlock>` catches this, seeds placeholders, and renders `children` behind a warning banner so dev-time previews still work.
|
|
@@ -45,7 +45,7 @@ function useCustomBlockInit(
|
|
|
45
45
|
type UseCustomBlockInitResult =
|
|
46
46
|
| { isLoaded: false; error: undefined }
|
|
47
47
|
| { isLoaded: false; error: CustomBlockInitFailure }
|
|
48
|
-
| { isLoaded: true; error: undefined; initial:
|
|
48
|
+
| { isLoaded: true; error: undefined; initial: CustomBlockInitPayload };
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
React wrapper around `initCustomBlock` for templates that prefer not to use top-level `await`. Multiple components calling it share the same handshake.
|
|
@@ -64,7 +64,7 @@ function Root() {
|
|
|
64
64
|
```ts
|
|
65
65
|
function initCustomBlock(
|
|
66
66
|
opts?: InitCustomBlockOptions,
|
|
67
|
-
): Promise<
|
|
67
|
+
): Promise<CustomBlockInitPayload>;
|
|
68
68
|
|
|
69
69
|
type InitCustomBlockOptions = { timeoutMs?: number };
|
|
70
70
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notionhq/custom-blocks",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"bin": {
|
|
35
|
-
"ncblock": "./bin/cli/cli.js"
|
|
35
|
+
"ncblock": "./bin/cli/cli.js",
|
|
36
|
+
"notion-custom-blocks": "./bin/notion-custom-blocks/cli.js"
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
39
|
"test": "vitest run --environment jsdom",
|
package/src/bridge/pages/page.ts
CHANGED
|
@@ -11,8 +11,17 @@ import { notionParentSchema } from "../parent.js"
|
|
|
11
11
|
|
|
12
12
|
export type { NotionPageId } from "../ids.js"
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The custom block's nearest enclosing page ancestor, carried in `init.page` and `pageChanged`.
|
|
16
|
+
*/
|
|
14
17
|
export const customBlockPageSchema = v.object({
|
|
15
18
|
id: notionPageIdSchema,
|
|
19
|
+
/**
|
|
20
|
+
* The containing page's own parent. It lets a block distinguish a freestanding page from a
|
|
21
|
+
* database row without a round trip. Not to be confused with the top-level `parent` runtime
|
|
22
|
+
* value, which is the custom block's own parent.
|
|
23
|
+
*/
|
|
24
|
+
parent: notionParentSchema,
|
|
16
25
|
})
|
|
17
26
|
|
|
18
27
|
export type CustomBlockPage = v.InferOutput<typeof customBlockPageSchema>
|
package/src/index.ts
CHANGED
|
@@ -108,7 +108,7 @@ export { pages, users } from "./bridge/sandboxClient.js"
|
|
|
108
108
|
export type { NotionTheme } from "./bridge/theme.js"
|
|
109
109
|
export { type CustomBlockState, customBlock } from "./customBlock.js"
|
|
110
110
|
export {
|
|
111
|
-
type
|
|
111
|
+
type CustomBlockInitPayload,
|
|
112
112
|
type InitCustomBlockOptions,
|
|
113
113
|
initCustomBlock,
|
|
114
114
|
NotInIframeError,
|
package/src/init.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type { NotionUser } from "./bridge/users/user.js"
|
|
|
15
15
|
/**
|
|
16
16
|
* The payload sent by the host in the `init` message in response to the sandbox's `ready` message.
|
|
17
17
|
*/
|
|
18
|
-
export type
|
|
18
|
+
export type CustomBlockInitPayload = {
|
|
19
19
|
theme: NotionTheme
|
|
20
20
|
blockId: NotionBlockId
|
|
21
21
|
parent: NotionParent
|
|
@@ -60,7 +60,7 @@ const DEFAULT_INIT_TIMEOUT_MS = 15_000
|
|
|
60
60
|
const NOT_IN_IFRAME_MESSAGE =
|
|
61
61
|
"<NotionCustomBlock> only works inside an iframe — use the dev shell or deploy to Notion."
|
|
62
62
|
|
|
63
|
-
let initPromise: Promise<
|
|
63
|
+
let initPromise: Promise<CustomBlockInitPayload> | undefined
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Performs the SDK <-> host handshake: loads `custom_blocks.json`, posts
|
|
@@ -74,7 +74,7 @@ let initPromise: Promise<CustomBlockInitial> | undefined
|
|
|
74
74
|
*/
|
|
75
75
|
export function initCustomBlock(
|
|
76
76
|
opts: InitCustomBlockOptions = {},
|
|
77
|
-
): Promise<
|
|
77
|
+
): Promise<CustomBlockInitPayload> {
|
|
78
78
|
if (initPromise === undefined) {
|
|
79
79
|
initPromise = (async () => {
|
|
80
80
|
// Fail fast with a typed error when rendered as a standalone tab and not in a parent frame.
|
|
@@ -12,7 +12,7 @@ export function seedStandalonePreviewState() {
|
|
|
12
12
|
theme: "light",
|
|
13
13
|
blockId: previewBlockId,
|
|
14
14
|
parent: { type: "page_id", page_id: previewPageId },
|
|
15
|
-
page: { id: previewPageId },
|
|
15
|
+
page: { id: previewPageId, parent: { type: "workspace", workspace: true } },
|
|
16
16
|
dataSources: { bindings: {} },
|
|
17
17
|
currentUser: {
|
|
18
18
|
object: "user",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react"
|
|
2
2
|
import { CustomBlockInitError } from "../bridge/messages/init.js"
|
|
3
3
|
import {
|
|
4
|
-
type
|
|
4
|
+
type CustomBlockInitPayload,
|
|
5
5
|
type InitCustomBlockOptions,
|
|
6
6
|
initCustomBlock,
|
|
7
7
|
NotInIframeError,
|
|
@@ -22,7 +22,7 @@ export type CustomBlockInitFailure = CustomBlockInitError | NotInIframeError
|
|
|
22
22
|
export type UseCustomBlockInitResult =
|
|
23
23
|
| { isLoaded: false; error: undefined }
|
|
24
24
|
| { isLoaded: false; error: CustomBlockInitFailure }
|
|
25
|
-
| { isLoaded: true; error: undefined; initial:
|
|
25
|
+
| { isLoaded: true; error: undefined; initial: CustomBlockInitPayload }
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* React wrapper around {@link initCustomBlock}. Kicks off the SDK ↔ host
|