@notionhq/custom-blocks-dev-shell 0.1.36 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cli/build-block-registry.js +9 -0
- package/dist-cli/convert.js +22 -14
- package/dist-cli/data-sources.js +2 -1
- package/dist-cli/dev-shell-launcher.js +40 -13
- package/dist-cli/errors.js +8 -0
- package/dist-cli/process-supervisor.js +64 -19
- package/dist-cli/published-cli.js +7 -2
- package/dist-cli/serve-ui.js +2 -1
- package/dist-cli/utils.js +7 -6
- package/dist-cli/{block-server.js → vite-block-server.js} +7 -11
- package/package.json +4 -3
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BLOCK_BASE_PORT } from "./ports.js";
|
|
2
|
+
/** The registry for a worker's blocks, assuming sequential port assignment. */
|
|
3
|
+
export function buildBlockRegistry(blocks, basePort = BLOCK_BASE_PORT) {
|
|
4
|
+
return blocks.map((capability, index) => ({
|
|
5
|
+
key: capability.key,
|
|
6
|
+
name: capability.key,
|
|
7
|
+
url: `http://localhost:${basePort + index}/`,
|
|
8
|
+
}));
|
|
9
|
+
}
|
package/dist-cli/convert.js
CHANGED
|
@@ -9,7 +9,8 @@ import { readFileSync } from "node:fs";
|
|
|
9
9
|
import * as v from "valibot";
|
|
10
10
|
import { convertPublicApiPropertyValue, isDataSourceValue, matchesPropertyType, } from "./convert-values.js";
|
|
11
11
|
import { NOTION_PROPERTY_TYPES, sourceFileSchema } from "./data-sources.js";
|
|
12
|
-
import {
|
|
12
|
+
import { formatUnknownError } from "./errors.js";
|
|
13
|
+
import { claimUniqueKey, parseCliArgs, slugify } from "./utils.js";
|
|
13
14
|
const SUPPORTED_TYPES = new Set(NOTION_PROPERTY_TYPES);
|
|
14
15
|
/** The spelling of "text" in the local file format. */
|
|
15
16
|
const UNSUPPORTED_TYPE_FALLBACK = "rich_text";
|
|
@@ -19,18 +20,25 @@ export function parseConvertArgs(argv) {
|
|
|
19
20
|
key: undefined,
|
|
20
21
|
name: undefined,
|
|
21
22
|
};
|
|
22
|
-
|
|
23
|
-
"--in": value => {
|
|
24
|
-
args.input = value;
|
|
25
|
-
},
|
|
26
|
-
"--key": value => {
|
|
27
|
-
args.key = value;
|
|
28
|
-
},
|
|
29
|
-
"--name": value => {
|
|
30
|
-
args.name = value;
|
|
31
|
-
},
|
|
32
|
-
}, arg => {
|
|
23
|
+
const rejectUnknown = (arg) => {
|
|
33
24
|
throw new Error(`Unknown convert option "${arg}". Supported: --in <file>, --key <key>, --name <name>.`);
|
|
25
|
+
};
|
|
26
|
+
parseCliArgs({
|
|
27
|
+
argv,
|
|
28
|
+
handlers: {
|
|
29
|
+
"--in": value => {
|
|
30
|
+
args.input = value;
|
|
31
|
+
},
|
|
32
|
+
"--key": value => {
|
|
33
|
+
args.key = value;
|
|
34
|
+
},
|
|
35
|
+
"--name": value => {
|
|
36
|
+
args.name = value;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
onUnknown: rejectUnknown,
|
|
40
|
+
// This command accepts no positional arguments.
|
|
41
|
+
onPositional: rejectUnknown,
|
|
34
42
|
});
|
|
35
43
|
return args;
|
|
36
44
|
}
|
|
@@ -182,7 +190,7 @@ export async function runConvert(argv) {
|
|
|
182
190
|
raw = readFileSync(args.input, "utf-8");
|
|
183
191
|
}
|
|
184
192
|
catch (error) {
|
|
185
|
-
throw new Error(`Could not read ${args.input}: ${error
|
|
193
|
+
throw new Error(`Could not read ${args.input}: ${formatUnknownError(error)}`);
|
|
186
194
|
}
|
|
187
195
|
}
|
|
188
196
|
else {
|
|
@@ -196,7 +204,7 @@ export async function runConvert(argv) {
|
|
|
196
204
|
parsed = JSON.parse(raw);
|
|
197
205
|
}
|
|
198
206
|
catch (error) {
|
|
199
|
-
throw new Error(`Input is not valid JSON — ${error
|
|
207
|
+
throw new Error(`Input is not valid JSON — ${formatUnknownError(error)}`);
|
|
200
208
|
}
|
|
201
209
|
const { source, warnings } = convertSample(parsed, {
|
|
202
210
|
...(args.key !== undefined ? { key: args.key } : {}),
|
package/dist-cli/data-sources.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
8
8
|
import { basename, resolve } from "node:path";
|
|
9
9
|
import * as v from "valibot";
|
|
10
|
+
import { formatUnknownError } from "./errors.js";
|
|
10
11
|
const DEV_SHELL_DATA_SOURCE_TYPES = [
|
|
11
12
|
"built-in",
|
|
12
13
|
"worker",
|
|
@@ -79,7 +80,7 @@ function readSource(file) {
|
|
|
79
80
|
parsed = JSON.parse(readFileSync(file, "utf-8"));
|
|
80
81
|
}
|
|
81
82
|
catch (error) {
|
|
82
|
-
throw new Error(`${file}: not valid JSON — ${error
|
|
83
|
+
throw new Error(`${file}: not valid JSON — ${formatUnknownError(error)}`);
|
|
83
84
|
}
|
|
84
85
|
if (Array.isArray(parsed)) {
|
|
85
86
|
throw new Error(`${file}: must be a JSON object`);
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
import { existsSync, readFileSync } from "node:fs";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { basename, dirname, join, resolve } from "node:path";
|
|
11
|
-
import { buildBlockRegistry,
|
|
11
|
+
import { buildBlockRegistry, } from "./build-block-registry.js";
|
|
12
12
|
import { readDataSources } from "./data-sources.js";
|
|
13
|
+
import { formatUnknownErrorWithStack } from "./errors.js";
|
|
13
14
|
import { materializeWorkerSchemaDataSources } from "./materialize.js";
|
|
14
15
|
import { BLOCK_BASE_PORT, parsePort, SHELL_PORT, validateBlockPortRange, validateShellPort, } from "./ports.js";
|
|
15
16
|
import { installProcessSignalHandlers, ProcessSupervisor, } from "./process-supervisor.js";
|
|
16
|
-
import {
|
|
17
|
+
import { parseCliArgs } from "./utils.js";
|
|
18
|
+
import { writeBlockViteConfig } from "./vite-block-server.js";
|
|
17
19
|
import { blockCapabilities, findWorkerDir, generateWorkerManifest, } from "./worker-manifest.js";
|
|
18
20
|
const dim = "\x1b[2m";
|
|
19
21
|
const bold = "\x1b[1m";
|
|
@@ -58,18 +60,43 @@ export function parseWorkerLaunchArgs(argv) {
|
|
|
58
60
|
shellPort: SHELL_PORT,
|
|
59
61
|
blockBasePort: BLOCK_BASE_PORT,
|
|
60
62
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
let hasPositionalWorker = false;
|
|
64
|
+
parseCliArgs({
|
|
65
|
+
argv,
|
|
66
|
+
handlers: {
|
|
67
|
+
"--worker": value => {
|
|
68
|
+
if (value.length === 0) {
|
|
69
|
+
throw new Error("--worker requires a path to a worker directory.");
|
|
70
|
+
}
|
|
71
|
+
// Reject --worker after a positional worker path.
|
|
72
|
+
if (hasPositionalWorker) {
|
|
73
|
+
throw new Error("Cannot combine --worker with a positional worker path.");
|
|
74
|
+
}
|
|
75
|
+
args.worker = value;
|
|
76
|
+
},
|
|
77
|
+
"--port": value => {
|
|
78
|
+
args.shellPort = parsePort("--port", value);
|
|
79
|
+
},
|
|
80
|
+
"--block-base-port": value => {
|
|
81
|
+
args.blockBasePort = parsePort("--block-base-port", value);
|
|
82
|
+
},
|
|
67
83
|
},
|
|
68
|
-
|
|
69
|
-
|
|
84
|
+
onUnknown: arg => {
|
|
85
|
+
throw new Error(`Unknown dev shell option "${arg}". Supported: --worker <dir>, ` +
|
|
86
|
+
`--port <port>, --block-base-port <port>.`);
|
|
70
87
|
},
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
onPositional: arg => {
|
|
89
|
+
// The published launcher passes its optional worker path positionally.
|
|
90
|
+
// Reject a second positional path.
|
|
91
|
+
if (hasPositionalWorker) {
|
|
92
|
+
throw new Error("Only one positional worker path may be provided.");
|
|
93
|
+
}
|
|
94
|
+
// Reject a positional path after --worker.
|
|
95
|
+
if (args.worker !== undefined) {
|
|
96
|
+
throw new Error("Cannot combine --worker with a positional worker path.");
|
|
97
|
+
}
|
|
98
|
+
hasPositionalWorker = true;
|
|
99
|
+
args.worker = arg;
|
|
73
100
|
},
|
|
74
101
|
});
|
|
75
102
|
return args;
|
|
@@ -188,7 +215,7 @@ export async function launchDevShell(options) {
|
|
|
188
215
|
printSummary(args, plan.registry);
|
|
189
216
|
}
|
|
190
217
|
catch (error) {
|
|
191
|
-
console.error(`Failed to start dev shell
|
|
218
|
+
console.error(`Failed to start dev shell:\n${formatUnknownErrorWithStack(error)}`);
|
|
192
219
|
process.exitCode = 1;
|
|
193
220
|
run.shutdown("SIGTERM");
|
|
194
221
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Format an unknown error as a message without a stack trace. */
|
|
2
|
+
export function formatUnknownError(error) {
|
|
3
|
+
return error instanceof Error ? error.message : String(error);
|
|
4
|
+
}
|
|
5
|
+
/** Format an unknown error with its stack when one is available. */
|
|
6
|
+
export function formatUnknownErrorWithStack(error) {
|
|
7
|
+
return error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
8
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
6
|
-
import { makeChangeLogger } from "./block-server.js";
|
|
6
|
+
import { makeChangeLogger } from "./vite-block-server.js";
|
|
7
7
|
const SHUTDOWN_GRACE_MS = 1500;
|
|
8
8
|
const dim = "\x1b[2m";
|
|
9
9
|
const reset = "\x1b[0m";
|
|
@@ -17,7 +17,7 @@ export class ProcessSupervisor {
|
|
|
17
17
|
}
|
|
18
18
|
addResource(resource) {
|
|
19
19
|
if (this.shuttingDown) {
|
|
20
|
-
closeResource(resource);
|
|
20
|
+
void closeResource(resource);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
this.resources.push(resource);
|
|
@@ -49,7 +49,11 @@ export class ProcessSupervisor {
|
|
|
49
49
|
this.shutdown("SIGTERM");
|
|
50
50
|
});
|
|
51
51
|
proc.on("exit", code => {
|
|
52
|
-
|
|
52
|
+
// Retain an unexpectedly failed process until cleanup. Its PID may
|
|
53
|
+
// still identify a detached process group with live descendants.
|
|
54
|
+
if (!this.shuttingDown && (code === 0 || code === null)) {
|
|
55
|
+
this.processes.delete(proc);
|
|
56
|
+
}
|
|
53
57
|
if (this.shuttingDown || code === 0 || code === null) {
|
|
54
58
|
return;
|
|
55
59
|
}
|
|
@@ -61,6 +65,9 @@ export class ProcessSupervisor {
|
|
|
61
65
|
}
|
|
62
66
|
shutdown(signal) {
|
|
63
67
|
if (this.shuttingDown) {
|
|
68
|
+
if (signal !== "exit") {
|
|
69
|
+
this.forceShutdown();
|
|
70
|
+
}
|
|
64
71
|
return;
|
|
65
72
|
}
|
|
66
73
|
this.shuttingDown = true;
|
|
@@ -68,44 +75,82 @@ export class ProcessSupervisor {
|
|
|
68
75
|
(this.processes.size > 0 || this.resources.length > 0)) {
|
|
69
76
|
console.log(`\n${dim}Shutting down...${reset}`);
|
|
70
77
|
}
|
|
71
|
-
for (const resource of this.resources) {
|
|
72
|
-
closeResource(resource);
|
|
73
|
-
}
|
|
74
78
|
for (const [proc, detached] of this.processes) {
|
|
75
79
|
killProcess(proc, detached, "SIGTERM");
|
|
76
80
|
}
|
|
77
81
|
if (signal === "exit") {
|
|
82
|
+
for (const resource of this.resources) {
|
|
83
|
+
void closeResource(resource);
|
|
84
|
+
}
|
|
78
85
|
return;
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
void this.finishShutdown();
|
|
88
|
+
}
|
|
89
|
+
async finishShutdown() {
|
|
90
|
+
const resourceCleanup = Promise.all(this.resources.map(resource => closeResource(resource)));
|
|
91
|
+
const processCleanup = Promise.all([...this.processes.keys()].map(proc => waitForExit(proc)));
|
|
92
|
+
let finished = false;
|
|
93
|
+
await Promise.race([
|
|
94
|
+
Promise.all([resourceCleanup, processCleanup]).then(() => {
|
|
95
|
+
finished = true;
|
|
96
|
+
}),
|
|
97
|
+
delay(SHUTDOWN_GRACE_MS),
|
|
98
|
+
]);
|
|
99
|
+
if (!finished) {
|
|
100
|
+
this.forceShutdown();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// A process can exit before its descendants do. Re-signal every
|
|
104
|
+
// remaining process group even after the direct child has exited.
|
|
105
|
+
this.forceKillProcesses();
|
|
106
|
+
process.exit(process.exitCode ?? 0);
|
|
107
|
+
}
|
|
108
|
+
forceShutdown() {
|
|
109
|
+
this.forceKillProcesses();
|
|
110
|
+
process.exit(process.exitCode ?? 130);
|
|
111
|
+
}
|
|
112
|
+
forceKillProcesses() {
|
|
113
|
+
for (const [proc, detached] of this.processes) {
|
|
114
|
+
killProcess(proc, detached, "SIGKILL", true);
|
|
115
|
+
}
|
|
87
116
|
}
|
|
88
117
|
}
|
|
89
|
-
function closeResource(resource) {
|
|
118
|
+
async function closeResource(resource) {
|
|
90
119
|
try {
|
|
91
|
-
resource();
|
|
120
|
+
await resource();
|
|
92
121
|
}
|
|
93
122
|
catch { }
|
|
94
123
|
}
|
|
95
|
-
function killProcess(proc, detached, signal) {
|
|
96
|
-
|
|
124
|
+
function killProcess(proc, detached, signal, force = false) {
|
|
125
|
+
const pid = proc.pid;
|
|
126
|
+
if (pid === undefined) {
|
|
97
127
|
return;
|
|
98
128
|
}
|
|
99
129
|
try {
|
|
100
130
|
if (detached && process.platform !== "win32") {
|
|
101
|
-
process.kill(-
|
|
131
|
+
process.kill(-pid, signal);
|
|
132
|
+
return;
|
|
102
133
|
}
|
|
103
|
-
|
|
134
|
+
if (force || isProcessRunning(proc)) {
|
|
104
135
|
proc.kill(signal);
|
|
105
136
|
}
|
|
106
137
|
}
|
|
107
138
|
catch { }
|
|
108
139
|
}
|
|
140
|
+
function isProcessRunning(proc) {
|
|
141
|
+
return proc.exitCode === null && proc.signalCode === null;
|
|
142
|
+
}
|
|
143
|
+
function waitForExit(proc) {
|
|
144
|
+
if (proc.exitCode !== null || proc.signalCode !== null) {
|
|
145
|
+
return Promise.resolve();
|
|
146
|
+
}
|
|
147
|
+
return new Promise(resolve => {
|
|
148
|
+
proc.once("exit", () => resolve());
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function delay(milliseconds) {
|
|
152
|
+
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
153
|
+
}
|
|
109
154
|
export function installProcessSignalHandlers(run) {
|
|
110
155
|
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
111
156
|
process.on(signal, () => run.shutdown(signal));
|
|
@@ -15,6 +15,7 @@ import { fileURLToPath } from "node:url";
|
|
|
15
15
|
import { runConvert } from "./convert.js";
|
|
16
16
|
import { readDataSources } from "./data-sources.js";
|
|
17
17
|
import { launchDevShell } from "./dev-shell-launcher.js";
|
|
18
|
+
import { formatUnknownErrorWithStack } from "./errors.js";
|
|
18
19
|
import { copyPrebuiltDataSources } from "./prebuilt.js";
|
|
19
20
|
import { serveUi } from "./serve-ui.js";
|
|
20
21
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -50,7 +51,11 @@ const createShellLaunch = async ({ args, plan, log }) => {
|
|
|
50
51
|
}
|
|
51
52
|
return {
|
|
52
53
|
processes: [],
|
|
53
|
-
resources: [
|
|
54
|
+
resources: [
|
|
55
|
+
() => new Promise(resolve => {
|
|
56
|
+
server.close(() => resolve());
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
54
59
|
};
|
|
55
60
|
};
|
|
56
61
|
async function main() {
|
|
@@ -68,6 +73,6 @@ async function main() {
|
|
|
68
73
|
});
|
|
69
74
|
}
|
|
70
75
|
main().catch(error => {
|
|
71
|
-
console.error(error
|
|
76
|
+
console.error(formatUnknownErrorWithStack(error));
|
|
72
77
|
process.exitCode = 1;
|
|
73
78
|
});
|
package/dist-cli/serve-ui.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
11
11
|
import { createServer } from "node:http";
|
|
12
12
|
import { extname, join, normalize, resolve, sep } from "node:path";
|
|
13
|
+
import { formatUnknownError } from "./errors.js";
|
|
13
14
|
const CONTENT_TYPES = {
|
|
14
15
|
".html": "text/html; charset=utf-8",
|
|
15
16
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -73,7 +74,7 @@ export function serveUi(distDir, port, config, addPrebuiltData) {
|
|
|
73
74
|
}
|
|
74
75
|
catch (error) {
|
|
75
76
|
res.writeHead(500, { "Content-Type": CONTENT_TYPES[".json"] });
|
|
76
|
-
res.end(JSON.stringify({ error: error
|
|
77
|
+
res.end(JSON.stringify({ error: formatUnknownError(error) }));
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
79
80
|
res.writeHead(200, { "Content-Type": CONTENT_TYPES[".json"] });
|
package/dist-cli/utils.js
CHANGED
|
@@ -24,11 +24,7 @@ export function claimUniqueKey(base, used) {
|
|
|
24
24
|
used.add(key);
|
|
25
25
|
return key;
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
* Parse long options in both `--name value` and `--name=value` forms.
|
|
29
|
-
* Unknown options are passed to `onUnknown`. Callers can ignore or reject them.
|
|
30
|
-
*/
|
|
31
|
-
export function parseLongOptions(argv, handlers, onUnknown = () => { }) {
|
|
27
|
+
export function parseCliArgs({ argv, handlers, onUnknown, onPositional, }) {
|
|
32
28
|
const takeValue = (name, index) => {
|
|
33
29
|
const value = argv[index];
|
|
34
30
|
if (value === undefined || value.startsWith("--")) {
|
|
@@ -42,7 +38,12 @@ export function parseLongOptions(argv, handlers, onUnknown = () => { }) {
|
|
|
42
38
|
const name = separator === -1 ? arg : arg.slice(0, separator);
|
|
43
39
|
const handler = handlers[name];
|
|
44
40
|
if (handler === undefined) {
|
|
45
|
-
|
|
41
|
+
if (arg.startsWith("-")) {
|
|
42
|
+
onUnknown(arg);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
onPositional(arg);
|
|
46
|
+
}
|
|
46
47
|
continue;
|
|
47
48
|
}
|
|
48
49
|
const value = separator === -1 ? takeValue(name, ++index) : arg.slice(separator + 1);
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provides shared Vite server setup for both dev shell launchers. It
|
|
3
|
-
*
|
|
2
|
+
* Provides shared Vite server setup for both dev shell launchers. It generates a
|
|
3
|
+
* Vite config for each block and formats Vite change logs.
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { relative, resolve } from "node:path";
|
|
7
|
-
import { BLOCK_BASE_PORT } from "./ports.js";
|
|
8
|
-
/** The registry for a worker's blocks, assuming sequential port assignment. */
|
|
9
|
-
export function buildBlockRegistry(blocks, basePort = BLOCK_BASE_PORT) {
|
|
10
|
-
return blocks.map((capability, index) => ({
|
|
11
|
-
key: capability.key,
|
|
12
|
-
name: capability.key,
|
|
13
|
-
url: `http://localhost:${basePort + index}/`,
|
|
14
|
-
}));
|
|
15
|
-
}
|
|
16
7
|
const ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
|
|
17
8
|
const VITE_CHANGE_PATTERN = /\b(page reload|hmr update)\s+(.+)$/;
|
|
18
9
|
/**
|
|
@@ -116,6 +107,11 @@ export default {
|
|
|
116
107
|
...resolved,
|
|
117
108
|
root: here("${toRoot}"),
|
|
118
109
|
cacheDir: here("${toCache}"),
|
|
110
|
+
server: {
|
|
111
|
+
...(resolved.server ?? {}),
|
|
112
|
+
// Block servers are local development dependencies of the shell.
|
|
113
|
+
host: "127.0.0.1",
|
|
114
|
+
},
|
|
119
115
|
define: {
|
|
120
116
|
...(resolved.define ?? {}),
|
|
121
117
|
// Initialization handshake scenarios fixture uses this key to identify the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notionhq/custom-blocks-dev-shell",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
4
4
|
"description": "Local preview shell for Notion custom block workers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
"@types/react": "^19.2.14",
|
|
35
35
|
"@types/react-dom": "^19.2.3",
|
|
36
36
|
"@vitejs/plugin-react": "^6.0.1",
|
|
37
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
37
38
|
"tailwindcss": "^4.2.4",
|
|
38
39
|
"typescript": "^6.0.3",
|
|
39
40
|
"vite": "^8.0.10",
|
|
40
41
|
"vitest": "^4.1.5",
|
|
41
|
-
"@notionhq/custom-blocks-
|
|
42
|
-
"@notionhq/custom-blocks-
|
|
42
|
+
"@notionhq/custom-blocks-protocol": "0.1.0",
|
|
43
|
+
"@notionhq/custom-blocks-host": "0.0.0"
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
46
|
"dev": "vite",
|