@kubb/studio 5.12.1 → 5.12.2
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/index.cjs +158 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +157 -5
- package/dist/index.js.map +1 -1
- package/dist/{protocol-CG1bPO_H.d.ts → protocol-DhNrwhqp.d.cts} +34 -2
- package/dist/{protocol-CG1bPO_H.d.cts → protocol-DhNrwhqp.d.ts} +34 -2
- package/dist/protocol.cjs +4 -0
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +2 -2
- package/dist/protocol.d.ts +2 -2
- package/dist/protocol.js +4 -0
- package/dist/protocol.js.map +1 -1
- package/package.json +5 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as InstalledExtensions, L as PublishedSnapshot, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, q as SnapshotUploadMetadata, s as AgentPermission, u as ConfigEdit } from "./protocol-DhNrwhqp.cjs";
|
|
2
2
|
import { Config, Hookable, KubbHooks } from "@kubb/core";
|
|
3
3
|
//#region src/connect.d.ts
|
|
4
4
|
/**
|
|
@@ -45,7 +45,7 @@ declare global {
|
|
|
45
45
|
* A finished command and what it did, such as `applied 2/3 edits to kubb.config.ts`.
|
|
46
46
|
*/
|
|
47
47
|
'studio:command': [ctx: {
|
|
48
|
-
command: 'generate' | 'saveConfig' | 'readFiles' | 'readInput' | 'readDiff';
|
|
48
|
+
command: 'generate' | 'saveConfig' | 'installExtension' | 'updateExtensions' | 'readFiles' | 'readInput' | 'readDiff';
|
|
49
49
|
info: string;
|
|
50
50
|
/**
|
|
51
51
|
* The Studio user who asked for the command, when Studio names one.
|
|
@@ -97,6 +97,8 @@ type ConnectAgentOptions = {
|
|
|
97
97
|
* What Studio may do in this project. Every permission is off unless granted.
|
|
98
98
|
*/
|
|
99
99
|
permissions?: Partial<AgentPermissions>;
|
|
100
|
+
/** The CLI entry `installExtension` runs `kubb add` with. Found through the project's `kubb` or `@kubb/cli` dependency when omitted. */
|
|
101
|
+
kubbBin?: string;
|
|
100
102
|
/**
|
|
101
103
|
* Receives the `studio:*` hooks and the `kubb:*` hooks of every generation.
|
|
102
104
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as InstalledExtensions, L as PublishedSnapshot, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, q as SnapshotUploadMetadata, s as AgentPermission, u as ConfigEdit } from "./protocol-DhNrwhqp.js";
|
|
2
2
|
import { Config, Hookable, KubbHooks } from "@kubb/core";
|
|
3
3
|
//#region src/connect.d.ts
|
|
4
4
|
/**
|
|
@@ -45,7 +45,7 @@ declare global {
|
|
|
45
45
|
* A finished command and what it did, such as `applied 2/3 edits to kubb.config.ts`.
|
|
46
46
|
*/
|
|
47
47
|
'studio:command': [ctx: {
|
|
48
|
-
command: 'generate' | 'saveConfig' | 'readFiles' | 'readInput' | 'readDiff';
|
|
48
|
+
command: 'generate' | 'saveConfig' | 'installExtension' | 'updateExtensions' | 'readFiles' | 'readInput' | 'readDiff';
|
|
49
49
|
info: string;
|
|
50
50
|
/**
|
|
51
51
|
* The Studio user who asked for the command, when Studio names one.
|
|
@@ -97,6 +97,8 @@ type ConnectAgentOptions = {
|
|
|
97
97
|
* What Studio may do in this project. Every permission is off unless granted.
|
|
98
98
|
*/
|
|
99
99
|
permissions?: Partial<AgentPermissions>;
|
|
100
|
+
/** The CLI entry `installExtension` runs `kubb add` with. Found through the project's `kubb` or `@kubb/cli` dependency when omitted. */
|
|
101
|
+
kubbBin?: string;
|
|
100
102
|
/**
|
|
101
103
|
* Receives the `studio:*` hooks and the `kubb:*` hooks of every generation.
|
|
102
104
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { AGENT_INSTANCE_HEADER, AGENT_SOCKET_PATH, AgentCloseCode, AgentMessage, AgentPermission, MAX_SNAPSHOT_BYTES, generationEventTypes } from "./protocol.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { createHash, hash, randomUUID } from "node:crypto";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import path, { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
7
|
import process$1 from "node:process";
|
|
7
8
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
8
|
-
import {
|
|
9
|
-
import { Readable, Transform } from "node:stream";
|
|
10
|
-
import { existsSync } from "node:fs";
|
|
9
|
+
import { x } from "tinyexec";
|
|
11
10
|
import { mkdir, mkdir as mkdir$1, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
12
11
|
import { Diagnostics, Hookable, cacheStorage, checkoutGitInput, createKubb, fsStorage, getInputKind, isPackageName, isPublicAddress, readInstalledPackages, resolveCacheDir, resolveMeta } from "@kubb/core";
|
|
13
12
|
import { RpcTarget, newWebSocketRpcSession } from "capnweb";
|
|
14
13
|
import { detectCodeFormat, parseExpression, parseModule } from "magicast";
|
|
14
|
+
import { pathToFileURL } from "node:url";
|
|
15
15
|
import { structuredPatch } from "diff";
|
|
16
16
|
import { stripVTControlCharacters } from "node:util";
|
|
17
17
|
import { ast } from "@kubb/ast";
|
|
@@ -19,6 +19,7 @@ import dns from "node:dns";
|
|
|
19
19
|
import http from "node:http";
|
|
20
20
|
import https from "node:https";
|
|
21
21
|
import net from "node:net";
|
|
22
|
+
import { Readable, Transform } from "node:stream";
|
|
22
23
|
import { ofetch } from "ofetch";
|
|
23
24
|
import { gzipSync } from "node:zlib";
|
|
24
25
|
//#endregion
|
|
@@ -201,7 +202,7 @@ function getElapsedMs(hrStart) {
|
|
|
201
202
|
}
|
|
202
203
|
//#endregion
|
|
203
204
|
//#region package.json
|
|
204
|
-
var version = "5.12.
|
|
205
|
+
var version = "5.12.2";
|
|
205
206
|
//#endregion
|
|
206
207
|
//#region src/resolveConfig.ts
|
|
207
208
|
/**
|
|
@@ -2013,6 +2014,43 @@ var IncompatibleAgentError = class extends Error {
|
|
|
2013
2014
|
this.name = "IncompatibleAgentError";
|
|
2014
2015
|
}
|
|
2015
2016
|
};
|
|
2017
|
+
const INSTALL_TIMEOUT_MS = 3e5;
|
|
2018
|
+
/** `owner/slug` or `slug`, as `kubb add` takes it. Checked before it becomes an argument. */
|
|
2019
|
+
const REGISTRY_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\/[a-z0-9]+(?:-[a-z0-9]+)*)?$/;
|
|
2020
|
+
/** The CLI the project depends on, so `kubb add` installs next to what the config imports. */
|
|
2021
|
+
function findKubbBin(root) {
|
|
2022
|
+
const require = createRequire(path.resolve(root, "package.json"));
|
|
2023
|
+
const names = ["kubb", "@kubb/cli"];
|
|
2024
|
+
return (require.resolve.paths("kubb") ?? []).flatMap((dir) => names.map((name) => path.join(dir, name, "bin", "kubb.js"))).find((bin) => existsSync(bin));
|
|
2025
|
+
}
|
|
2026
|
+
/** Runs a `kubb` command without a shell, and keeps the end of its output for the failure reason. */
|
|
2027
|
+
async function runKubb({ bin, args, cwd, signal }) {
|
|
2028
|
+
try {
|
|
2029
|
+
const { stdout, stderr, exitCode } = await x(process$1.execPath, [bin, ...args], {
|
|
2030
|
+
signal,
|
|
2031
|
+
timeout: INSTALL_TIMEOUT_MS,
|
|
2032
|
+
throwOnError: false,
|
|
2033
|
+
nodeOptions: {
|
|
2034
|
+
cwd,
|
|
2035
|
+
env: {
|
|
2036
|
+
...process$1.env,
|
|
2037
|
+
NO_COLOR: "1",
|
|
2038
|
+
FORCE_COLOR: "0"
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
});
|
|
2042
|
+
const output = `${stdout}\n${stderr}`.trim().split("\n").slice(-20).join("\n");
|
|
2043
|
+
return {
|
|
2044
|
+
failed: exitCode !== 0,
|
|
2045
|
+
output: output || `kubb ${args[0]} exited with ${exitCode ?? "a signal"}`
|
|
2046
|
+
};
|
|
2047
|
+
} catch (error) {
|
|
2048
|
+
return {
|
|
2049
|
+
failed: true,
|
|
2050
|
+
output: `kubb ${args[0]} did not run: ${getErrorMessage(error)}`
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2016
2054
|
function emit(hooks, name, ...args) {
|
|
2017
2055
|
return Promise.resolve(hooks.callHook(name, ...args)).catch(() => {});
|
|
2018
2056
|
}
|
|
@@ -2083,6 +2121,8 @@ var Agent = class extends RpcTarget {
|
|
|
2083
2121
|
...permissions,
|
|
2084
2122
|
allowWrite: false,
|
|
2085
2123
|
allowConfigEdit: false,
|
|
2124
|
+
allowInstall: false,
|
|
2125
|
+
allowUpdate: false,
|
|
2086
2126
|
allowRead: true,
|
|
2087
2127
|
allowReadAst: true
|
|
2088
2128
|
} : permissions;
|
|
@@ -2234,6 +2274,8 @@ var Agent = class extends RpcTarget {
|
|
|
2234
2274
|
message: "Connection is closed"
|
|
2235
2275
|
});
|
|
2236
2276
|
if (this.#session.active) return this.#refuse({ message: AgentMessage.GENERATION_IN_PROGRESS });
|
|
2277
|
+
if (this.#session.install) return this.#refuse({ message: AgentMessage.INSTALL_IN_PROGRESS });
|
|
2278
|
+
if (this.#session.saving) return this.#refuse({ message: AgentMessage.SAVE_IN_PROGRESS });
|
|
2237
2279
|
const settled = Promise.withResolvers();
|
|
2238
2280
|
this.#session.active = {
|
|
2239
2281
|
jobId: input.jobId,
|
|
@@ -2374,7 +2416,9 @@ var Agent = class extends RpcTarget {
|
|
|
2374
2416
|
await this.#warn({ message: "Ignored save: editing kubb.config.ts was not granted" });
|
|
2375
2417
|
return refuse("the agent was not granted permission to edit kubb.config.ts");
|
|
2376
2418
|
}
|
|
2377
|
-
|
|
2419
|
+
const busy = this.#busy();
|
|
2420
|
+
if (busy) return refuse(busy);
|
|
2421
|
+
this.#session.saving = true;
|
|
2378
2422
|
try {
|
|
2379
2423
|
const { outcomes, changed } = await writeConfigEdits({
|
|
2380
2424
|
filePath: configFile,
|
|
@@ -2390,6 +2434,110 @@ var Agent = class extends RpcTarget {
|
|
|
2390
2434
|
} catch (error) {
|
|
2391
2435
|
await emit(this.#options.hooks, "studio:error", { error: toError(error) });
|
|
2392
2436
|
return refuse(getErrorMessage(error));
|
|
2437
|
+
} finally {
|
|
2438
|
+
this.#session.saving = false;
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Installs a registry extension into the project with `kubb add <id> --yes`, which also adds a
|
|
2443
|
+
* plugin to `kubb.config.ts`. Studio calls `connect()` again afterwards to see the result.
|
|
2444
|
+
*/
|
|
2445
|
+
async installExtension(input) {
|
|
2446
|
+
this.#assertConnected();
|
|
2447
|
+
const { root, configFile, kubbBin = findKubbBin(root) } = this.#options;
|
|
2448
|
+
const refuse = async (reason, permission) => {
|
|
2449
|
+
await this.#warn({
|
|
2450
|
+
message: `Ignored install: ${reason}`,
|
|
2451
|
+
permission
|
|
2452
|
+
});
|
|
2453
|
+
return {
|
|
2454
|
+
installed: false,
|
|
2455
|
+
reason
|
|
2456
|
+
};
|
|
2457
|
+
};
|
|
2458
|
+
if (typeof input?.id !== "string" || !REGISTRY_ID.test(input.id)) return refuse("the message carried no registry id");
|
|
2459
|
+
if (!this.#permissions.allowInstall) return refuse("installing extensions was not granted", AgentPermission.INSTALL);
|
|
2460
|
+
if (!this.#permissions.allowConfigEdit) return refuse("editing kubb.config.ts was not granted", AgentPermission.CONFIG_EDIT);
|
|
2461
|
+
const busy = this.#busy();
|
|
2462
|
+
if (busy) return refuse(busy);
|
|
2463
|
+
if (!kubbBin) return refuse("kubb is not installed in the project");
|
|
2464
|
+
const { failed, output } = await this.#runKubb({
|
|
2465
|
+
bin: kubbBin,
|
|
2466
|
+
args: [
|
|
2467
|
+
"add",
|
|
2468
|
+
input.id,
|
|
2469
|
+
"--yes",
|
|
2470
|
+
"--config",
|
|
2471
|
+
configFile
|
|
2472
|
+
]
|
|
2473
|
+
});
|
|
2474
|
+
await this.#logCommand("installExtension", `${failed ? "failed to install" : "installed"} ${input.id}`, input.requestedBy, failed);
|
|
2475
|
+
return failed ? {
|
|
2476
|
+
installed: false,
|
|
2477
|
+
reason: output
|
|
2478
|
+
} : { installed: true };
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Moves installed extensions to the registry's version with `kubb update [ids] --yes`, which
|
|
2482
|
+
* installs packages and leaves `kubb.config.ts` alone. Studio calls `connect()` again afterwards.
|
|
2483
|
+
*/
|
|
2484
|
+
async updateExtensions(input) {
|
|
2485
|
+
this.#assertConnected();
|
|
2486
|
+
const { root, kubbBin = findKubbBin(root) } = this.#options;
|
|
2487
|
+
const refuse = async (reason, permission) => {
|
|
2488
|
+
await this.#warn({
|
|
2489
|
+
message: `Ignored update: ${reason}`,
|
|
2490
|
+
permission
|
|
2491
|
+
});
|
|
2492
|
+
return {
|
|
2493
|
+
updated: false,
|
|
2494
|
+
reason
|
|
2495
|
+
};
|
|
2496
|
+
};
|
|
2497
|
+
const ids = input?.ids ?? [];
|
|
2498
|
+
if (!Array.isArray(ids) || !ids.every((id) => typeof id === "string" && REGISTRY_ID.test(id))) return refuse("the message carried an invalid registry id");
|
|
2499
|
+
if (!this.#permissions.allowUpdate) return refuse("updating extensions was not granted", AgentPermission.UPDATE);
|
|
2500
|
+
const busy = this.#busy();
|
|
2501
|
+
if (busy) return refuse(busy);
|
|
2502
|
+
if (!kubbBin) return refuse("kubb is not installed in the project");
|
|
2503
|
+
const { failed, output } = await this.#runKubb({
|
|
2504
|
+
bin: kubbBin,
|
|
2505
|
+
args: [
|
|
2506
|
+
"update",
|
|
2507
|
+
...ids,
|
|
2508
|
+
"--yes"
|
|
2509
|
+
]
|
|
2510
|
+
});
|
|
2511
|
+
await this.#logCommand("updateExtensions", `${failed ? "failed to update" : "updated"} ${ids.join(", ") || "all extensions"}`, input?.requestedBy, failed);
|
|
2512
|
+
return failed ? {
|
|
2513
|
+
updated: false,
|
|
2514
|
+
reason: output
|
|
2515
|
+
} : { updated: true };
|
|
2516
|
+
}
|
|
2517
|
+
/** Why a command that touches the project cannot start right now. */
|
|
2518
|
+
#busy() {
|
|
2519
|
+
if (this.#session.active) return "a generation is in progress";
|
|
2520
|
+
if (this.#session.install) return "an install or update is in progress";
|
|
2521
|
+
if (this.#session.saving) return "a save is in progress";
|
|
2522
|
+
}
|
|
2523
|
+
/** Runs `kubb` in the project while holding off saves and generations, and ends it when the socket closes. */
|
|
2524
|
+
async #runKubb({ bin, args }) {
|
|
2525
|
+
const controller = new AbortController();
|
|
2526
|
+
const settled = Promise.withResolvers();
|
|
2527
|
+
this.#session.install = {
|
|
2528
|
+
abort: () => controller.abort(),
|
|
2529
|
+
settled: settled.promise
|
|
2530
|
+
};
|
|
2531
|
+
try {
|
|
2532
|
+
return await runKubb({
|
|
2533
|
+
bin,
|
|
2534
|
+
args,
|
|
2535
|
+
cwd: this.#options.root,
|
|
2536
|
+
signal: controller.signal
|
|
2537
|
+
});
|
|
2538
|
+
} finally {
|
|
2539
|
+
this.#session.install = void 0;
|
|
2540
|
+
settled.resolve();
|
|
2393
2541
|
}
|
|
2394
2542
|
}
|
|
2395
2543
|
/**
|
|
@@ -2574,6 +2722,8 @@ async function runSession({ options, openRpc, url, instanceId }) {
|
|
|
2574
2722
|
await emit(hooks, "studio:warn", { message: "Canceled the running generation: the connection to Kubb Studio closed" });
|
|
2575
2723
|
}
|
|
2576
2724
|
await active?.settled;
|
|
2725
|
+
session.install?.abort();
|
|
2726
|
+
await session.install?.settled;
|
|
2577
2727
|
await agent.clear();
|
|
2578
2728
|
return {
|
|
2579
2729
|
...close,
|
|
@@ -2642,6 +2792,8 @@ async function runAgent({ options, openRpc }) {
|
|
|
2642
2792
|
permissions: {
|
|
2643
2793
|
allowWrite: false,
|
|
2644
2794
|
allowConfigEdit: false,
|
|
2795
|
+
allowInstall: false,
|
|
2796
|
+
allowUpdate: false,
|
|
2645
2797
|
allowExec: false,
|
|
2646
2798
|
allowRead: false,
|
|
2647
2799
|
allowReadAst: false,
|