@kubb/studio 5.12.0 → 5.12.1
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 +127 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +124 -8
- package/dist/index.js.map +1 -1
- package/dist/{protocol-Dn1jdnFB.d.ts → protocol-CG1bPO_H.d.cts} +10 -3
- package/dist/{protocol-Dn1jdnFB.d.cts → protocol-CG1bPO_H.d.ts} +10 -3
- package/dist/protocol.cjs +1 -0
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.js +1 -0
- package/dist/protocol.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ let node_process = require("node:process");
|
|
|
30
30
|
node_process = __toESM(node_process, 1);
|
|
31
31
|
let node_timers_promises = require("node:timers/promises");
|
|
32
32
|
let node_url = require("node:url");
|
|
33
|
+
let node_stream = require("node:stream");
|
|
33
34
|
let node_fs = require("node:fs");
|
|
34
35
|
let node_fs_promises = require("node:fs/promises");
|
|
35
36
|
let _kubb_core = require("@kubb/core");
|
|
@@ -39,6 +40,14 @@ let node_module = require("node:module");
|
|
|
39
40
|
let diff = require("diff");
|
|
40
41
|
let node_util = require("node:util");
|
|
41
42
|
let _kubb_ast = require("@kubb/ast");
|
|
43
|
+
let node_dns = require("node:dns");
|
|
44
|
+
node_dns = __toESM(node_dns, 1);
|
|
45
|
+
let node_http = require("node:http");
|
|
46
|
+
node_http = __toESM(node_http, 1);
|
|
47
|
+
let node_https = require("node:https");
|
|
48
|
+
node_https = __toESM(node_https, 1);
|
|
49
|
+
let node_net = require("node:net");
|
|
50
|
+
node_net = __toESM(node_net, 1);
|
|
42
51
|
let ofetch = require("ofetch");
|
|
43
52
|
let node_zlib = require("node:zlib");
|
|
44
53
|
//#region ../../internals/utils/src/casing.ts
|
|
@@ -220,7 +229,7 @@ function getElapsedMs(hrStart) {
|
|
|
220
229
|
}
|
|
221
230
|
//#endregion
|
|
222
231
|
//#region package.json
|
|
223
|
-
var version = "5.12.
|
|
232
|
+
var version = "5.12.1";
|
|
224
233
|
//#endregion
|
|
225
234
|
//#region src/resolveConfig.ts
|
|
226
235
|
/**
|
|
@@ -1866,6 +1875,106 @@ function createGenerationStream(hooks, jobId) {
|
|
|
1866
1875
|
};
|
|
1867
1876
|
}
|
|
1868
1877
|
//#endregion
|
|
1878
|
+
//#region src/publicFetch.ts
|
|
1879
|
+
const MAX_REDIRECTS = 5;
|
|
1880
|
+
const MAX_BYTES = 52428800;
|
|
1881
|
+
const REDIRECTS = /* @__PURE__ */ new Set([
|
|
1882
|
+
301,
|
|
1883
|
+
302,
|
|
1884
|
+
303,
|
|
1885
|
+
307,
|
|
1886
|
+
308
|
|
1887
|
+
]);
|
|
1888
|
+
const NO_BODY = /* @__PURE__ */ new Set([
|
|
1889
|
+
204,
|
|
1890
|
+
205,
|
|
1891
|
+
304
|
|
1892
|
+
]);
|
|
1893
|
+
function notPublic(host) {
|
|
1894
|
+
return /* @__PURE__ */ new Error(`${host} is not a public address, so a managed agent does not fetch from it`);
|
|
1895
|
+
}
|
|
1896
|
+
function createLookup(blocked) {
|
|
1897
|
+
return (hostname, options, callback) => {
|
|
1898
|
+
node_dns.default.lookup(hostname, {
|
|
1899
|
+
...options,
|
|
1900
|
+
all: true
|
|
1901
|
+
}, (error, addresses) => {
|
|
1902
|
+
if (error) return callback(error, "", 0);
|
|
1903
|
+
const found = addresses;
|
|
1904
|
+
if (!found.length || found.some(({ address }) => !(0, _kubb_core.isPublicAddress)(address, blocked))) return callback(notPublic(hostname), "", 0);
|
|
1905
|
+
return options.all ? callback(null, found) : callback(null, found[0].address, found[0].family);
|
|
1906
|
+
});
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
function request({ url, blocked, signal }) {
|
|
1910
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return Promise.reject(/* @__PURE__ */ new Error(`Only http and https URLs are fetched, not ${url.protocol}`));
|
|
1911
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
1912
|
+
if (node_net.default.isIP(host) && !(0, _kubb_core.isPublicAddress)(host, blocked)) return Promise.reject(notPublic(host));
|
|
1913
|
+
return new Promise((resolve, reject) => {
|
|
1914
|
+
const req = (url.protocol === "https:" ? node_https.default.request : node_http.default.request)(url, {
|
|
1915
|
+
method: "GET",
|
|
1916
|
+
lookup: createLookup(blocked),
|
|
1917
|
+
signal: signal ?? void 0,
|
|
1918
|
+
headers: { "accept-encoding": "identity" }
|
|
1919
|
+
}, (res) => {
|
|
1920
|
+
const headers = new Headers();
|
|
1921
|
+
for (const [key, value] of Object.entries(res.headers)) for (const item of [value].flat()) if (item !== void 0) headers.append(key, item);
|
|
1922
|
+
let total = 0;
|
|
1923
|
+
const limit = new node_stream.Transform({ transform(chunk, _encoding, done) {
|
|
1924
|
+
total += chunk.length;
|
|
1925
|
+
done(total > MAX_BYTES ? /* @__PURE__ */ new Error("The response is larger than 50 MB") : null, chunk);
|
|
1926
|
+
} });
|
|
1927
|
+
res.on("error", (error) => limit.destroy(error));
|
|
1928
|
+
res.pipe(limit);
|
|
1929
|
+
const body = NO_BODY.has(res.statusCode ?? 0) ? null : node_stream.Readable.toWeb(limit);
|
|
1930
|
+
resolve(new Response(body, {
|
|
1931
|
+
status: res.statusCode,
|
|
1932
|
+
statusText: res.statusMessage,
|
|
1933
|
+
headers
|
|
1934
|
+
}));
|
|
1935
|
+
});
|
|
1936
|
+
req.on("error", reject);
|
|
1937
|
+
req.end();
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Builds a `fetch` that only reaches addresses `blocked` does not list. It follows redirects itself
|
|
1942
|
+
* and checks every hop, and takes GET requests only, since that is all a spec load needs.
|
|
1943
|
+
*/
|
|
1944
|
+
function createPublicFetch(blocked) {
|
|
1945
|
+
const publicFetch = async (input, init) => {
|
|
1946
|
+
if (typeof input !== "string" && !(input instanceof URL)) throw new TypeError("A managed agent fetches by URL only");
|
|
1947
|
+
if (init?.method && init.method.toUpperCase() !== "GET") throw new TypeError("A managed agent only sends GET requests");
|
|
1948
|
+
let url = new URL(input);
|
|
1949
|
+
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
1950
|
+
const response = await request({
|
|
1951
|
+
url,
|
|
1952
|
+
blocked,
|
|
1953
|
+
signal: init?.signal
|
|
1954
|
+
});
|
|
1955
|
+
const location = response.headers.get("location");
|
|
1956
|
+
if (!REDIRECTS.has(response.status) || !location) return response;
|
|
1957
|
+
await response.body?.cancel();
|
|
1958
|
+
url = new URL(location, url);
|
|
1959
|
+
}
|
|
1960
|
+
throw new Error(`Stopped after ${MAX_REDIRECTS} redirects from ${String(input)}`);
|
|
1961
|
+
};
|
|
1962
|
+
return publicFetch;
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Runs `run` with the global `fetch` limited to public addresses, then puts the original back.
|
|
1966
|
+
* A managed agent runs one job at a time, so nothing else shares the window.
|
|
1967
|
+
*/
|
|
1968
|
+
async function withPublicFetch(run) {
|
|
1969
|
+
const original = globalThis.fetch;
|
|
1970
|
+
globalThis.fetch = createPublicFetch();
|
|
1971
|
+
try {
|
|
1972
|
+
return await run();
|
|
1973
|
+
} finally {
|
|
1974
|
+
globalThis.fetch = original;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
//#endregion
|
|
1869
1978
|
//#region src/url.ts
|
|
1870
1979
|
/**
|
|
1871
1980
|
* Hosted Kubb Studio URL, used when a host passes none.
|
|
@@ -1902,6 +2011,11 @@ const OPEN_TIMEOUT_MS = 5e3;
|
|
|
1902
2011
|
const MAX_RETRY_DELAY_MS = 3e4;
|
|
1903
2012
|
const DISK_SNAPSHOT_MAX_FILES = 1e4;
|
|
1904
2013
|
const SANDBOX_GENERATION_TTL_MS = 9e5;
|
|
2014
|
+
const MANAGED_INPUT_KINDS = /* @__PURE__ */ new Set([
|
|
2015
|
+
"inline",
|
|
2016
|
+
"url",
|
|
2017
|
+
"git"
|
|
2018
|
+
]);
|
|
1905
2019
|
/** Extensions `kubb` ships with, so they count as installed without being a direct dependency. */
|
|
1906
2020
|
const BUILT_IN_PACKAGES = [
|
|
1907
2021
|
"@kubb/adapter-oas",
|
|
@@ -1988,6 +2102,9 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
1988
2102
|
get #sandbox() {
|
|
1989
2103
|
return this.#session.info?.sandbox === true;
|
|
1990
2104
|
}
|
|
2105
|
+
get #managed() {
|
|
2106
|
+
return this.#session.info?.managed === true;
|
|
2107
|
+
}
|
|
1991
2108
|
get #permissions() {
|
|
1992
2109
|
const { permissions } = this.#options;
|
|
1993
2110
|
return this.#sandbox ? {
|
|
@@ -2183,8 +2300,9 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2183
2300
|
*/
|
|
2184
2301
|
async #generate({ input, root, outputRoot, signal }) {
|
|
2185
2302
|
const { jobId, config: patch } = input;
|
|
2186
|
-
const studioInput = this.#sandbox ? patch?.input : void 0;
|
|
2303
|
+
const studioInput = this.#sandbox || this.#managed ? patch?.input : void 0;
|
|
2187
2304
|
if (this.#sandbox && (typeof studioInput !== "string" || !studioInput.trim() || (0, _kubb_core.getInputKind)(studioInput) !== "inline")) return this.#refuse({ message: require_protocol.AgentMessage.SANDBOX_INPUT_ONLY });
|
|
2305
|
+
if (this.#managed && studioInput !== void 0 && !MANAGED_INPUT_KINDS.has((0, _kubb_core.getInputKind)(studioInput))) return this.#refuse({ message: require_protocol.AgentMessage.MANAGED_INPUT_KIND });
|
|
2188
2306
|
const [configs, extensions] = await Promise.all([this.#options.loadConfigs(), this.#installedExtensions()]);
|
|
2189
2307
|
const config = pickConfig(configs, patch?.config);
|
|
2190
2308
|
if (!config) return this.#refuse({ message: require_protocol.AgentMessage.CONFIG_ENTRY_NOT_FOUND });
|
|
@@ -2213,12 +2331,13 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2213
2331
|
throw error;
|
|
2214
2332
|
});
|
|
2215
2333
|
const activePlugins = plugins ?? config.plugins;
|
|
2216
|
-
if (patch?.input && !this.#sandbox) await emit(this.#options.hooks, "kubb:warn", { message: "Ignored the spec from Studio: generating from a Studio spec is only available to a sandbox agent" });
|
|
2217
|
-
const
|
|
2334
|
+
if (patch?.input && !this.#sandbox && !this.#managed) await emit(this.#options.hooks, "kubb:warn", { message: "Ignored the spec from Studio: generating from a Studio spec is only available to a sandbox or managed agent" });
|
|
2335
|
+
const checkout = this.#managed && studioInput !== void 0 && (0, _kubb_core.getInputKind)(studioInput) === "git" ? await (0, _kubb_core.checkoutGitInput)(studioInput, signal, { publicOnly: true }).catch((error) => this.#refuse({ message: getErrorMessage(error) })) : void 0;
|
|
2336
|
+
const run = () => generate({
|
|
2218
2337
|
config: {
|
|
2219
2338
|
...config,
|
|
2220
2339
|
root,
|
|
2221
|
-
input: studioInput ?? config.input,
|
|
2340
|
+
input: checkout?.path ?? studioInput ?? config.input,
|
|
2222
2341
|
storage: outputRoot ? stagingStorage({
|
|
2223
2342
|
root,
|
|
2224
2343
|
directory: outputRoot
|
|
@@ -2230,11 +2349,12 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2230
2349
|
hooks: this.#options.hooks,
|
|
2231
2350
|
signal,
|
|
2232
2351
|
allowExec: this.#permissions.allowWrite && this.#permissions.allowExec
|
|
2233
|
-
})
|
|
2352
|
+
});
|
|
2353
|
+
const files = await (this.#managed ? withPublicFetch(run) : run()).catch(async (error) => {
|
|
2234
2354
|
await this.#generations.drop(jobId);
|
|
2235
2355
|
await this.#logCommand("generate", getErrorMessage(error), input.requestedBy, true);
|
|
2236
2356
|
throw error;
|
|
2237
|
-
});
|
|
2357
|
+
}).finally(() => checkout?.dispose());
|
|
2238
2358
|
const output = await this.#generations.keep({
|
|
2239
2359
|
jobId,
|
|
2240
2360
|
files,
|