poe-code 4.0.15 → 4.0.17
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/commands/plan.d.ts +0 -6
- package/dist/cli/commands/plan.js +26 -156
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/traces.js +1 -0
- package/dist/cli/commands/traces.js.map +1 -1
- package/dist/cli/program.js +4 -0
- package/dist/cli/program.js.map +1 -1
- package/dist/index.js +35 -207
- package/dist/index.js.map +3 -3
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/plan-browser/dist/browser.d.ts +0 -1
- package/packages/plan-browser/dist/browser.js +1 -2
- package/packages/plan-browser/dist/explorer-config.d.ts +0 -1
- package/packages/plan-browser/dist/explorer-config.js +0 -13
- package/packages/toolcraft-openapi/dist/index.d.ts +1 -0
- package/packages/toolcraft-openapi/dist/network-error.js +6 -0
- package/packages/toolcraft-openapi/dist/runtime.d.ts +5 -2
- package/packages/toolcraft-openapi/dist/runtime.js +52 -7
- package/packages/toolcraft-openapi/dist/spec-cache.d.ts +41 -0
- package/packages/toolcraft-openapi/dist/spec-cache.js +376 -0
- package/packages/toolcraft-openapi/dist/spec-source.d.ts +26 -0
- package/packages/toolcraft-openapi/dist/spec-source.js +109 -8
|
@@ -4,6 +4,18 @@ import { parse as parseYaml } from "yaml";
|
|
|
4
4
|
import { UserError } from "toolcraft";
|
|
5
5
|
import { renderSourceSnippet } from "toolcraft/source-snippet";
|
|
6
6
|
import { classifyNetworkError } from "./network-error.js";
|
|
7
|
+
import { redactSensitiveQueryValues } from "./redaction.js";
|
|
8
|
+
export class OpenApiHttpStatusError extends UserError {
|
|
9
|
+
}
|
|
10
|
+
export class OpenApiTransportError extends UserError {
|
|
11
|
+
}
|
|
12
|
+
export class OpenApiTimeoutError extends OpenApiTransportError {
|
|
13
|
+
timeoutMs;
|
|
14
|
+
constructor(message, timeoutMs, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.timeoutMs = timeoutMs;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
7
19
|
export async function readOpenApiSourceText(input, services) {
|
|
8
20
|
const inputUrl = input instanceof URL ? input : tryParseUrl(input);
|
|
9
21
|
const sourceLabel = formatSourceLabel(input);
|
|
@@ -20,29 +32,118 @@ export async function readOpenApiSourceText(input, services) {
|
|
|
20
32
|
if (inputUrl.protocol !== "http:" && inputUrl.protocol !== "https:") {
|
|
21
33
|
throw new UserError(`Unsupported OpenAPI input URL protocol ${JSON.stringify(inputUrl.protocol)}.`);
|
|
22
34
|
}
|
|
35
|
+
const result = await fetchOpenApiHttpSource(inputUrl, services.fetch);
|
|
36
|
+
if (result.status === "not-modified") {
|
|
37
|
+
throw new UserError(`Failed to fetch ${JSON.stringify(inputUrl.toString())}: received 304 without a cached document.`);
|
|
38
|
+
}
|
|
39
|
+
return result.sourceText;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof UserError) {
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
throw new UserError(`Failed to read OpenAPI document ${JSON.stringify(sourceLabel)}: ${getErrorMessage(error)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function fetchOpenApiHttpSource(inputUrl, fetch, options = {}) {
|
|
49
|
+
validateTimeout(options.timeoutMs);
|
|
50
|
+
const url = inputUrl.toString();
|
|
51
|
+
const timeoutMs = options.timeoutMs;
|
|
52
|
+
const controller = timeoutMs === undefined || timeoutMs === 0 ? undefined : new AbortController();
|
|
53
|
+
const requestInit = createOpenApiRequestInit(options.etag, controller?.signal);
|
|
54
|
+
const request = async () => {
|
|
23
55
|
let response;
|
|
24
56
|
try {
|
|
25
|
-
response = await
|
|
57
|
+
response = requestInit === undefined ? await fetch(url) : await fetch(url, requestInit);
|
|
26
58
|
}
|
|
27
59
|
catch (error) {
|
|
28
|
-
throw
|
|
60
|
+
throw toTransportError(error, url) ?? error;
|
|
61
|
+
}
|
|
62
|
+
if (response.status === 304) {
|
|
63
|
+
return {
|
|
64
|
+
status: "not-modified",
|
|
65
|
+
...readResponseCacheHeaders(response)
|
|
66
|
+
};
|
|
29
67
|
}
|
|
30
68
|
if (!response.ok) {
|
|
31
69
|
const contentType = response.headers.get("content-type") ?? "";
|
|
32
70
|
const text = await response.text().catch(() => "");
|
|
33
71
|
const snippet = text.length === 0 ? "" : `\n body: ${truncate(text, 500)}`;
|
|
34
|
-
throw new
|
|
72
|
+
throw new OpenApiHttpStatusError(`Failed to fetch ${JSON.stringify(url)}: ` +
|
|
35
73
|
`${response.status} ${response.statusText}` +
|
|
36
74
|
(contentType ? ` (content-type: ${contentType})` : "") +
|
|
37
75
|
snippet);
|
|
38
76
|
}
|
|
39
|
-
|
|
77
|
+
try {
|
|
78
|
+
return {
|
|
79
|
+
status: "modified",
|
|
80
|
+
sourceText: await response.text(),
|
|
81
|
+
...readResponseCacheHeaders(response)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw (toTransportError(error, url) ??
|
|
86
|
+
new OpenApiTransportError(`Failed to read the OpenAPI response body from ${JSON.stringify(redactSensitiveQueryValues(url))}.`, { cause: error }));
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
if (controller === undefined || timeoutMs === undefined) {
|
|
90
|
+
return await request();
|
|
40
91
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
92
|
+
const timeoutCause = Object.assign(new Error("OpenAPI request timed out"), {
|
|
93
|
+
code: "ETIMEDOUT",
|
|
94
|
+
timeout: timeoutMs
|
|
95
|
+
});
|
|
96
|
+
const classified = classifyNetworkError(timeoutCause, url);
|
|
97
|
+
const timeoutError = new OpenApiTimeoutError(classified?.message ?? `OpenAPI request timed out after ${timeoutMs}ms.`, timeoutMs, { cause: timeoutCause });
|
|
98
|
+
let timeout;
|
|
99
|
+
try {
|
|
100
|
+
return await Promise.race([
|
|
101
|
+
request(),
|
|
102
|
+
new Promise((_resolve, reject) => {
|
|
103
|
+
timeout = setTimeout(() => {
|
|
104
|
+
reject(timeoutError);
|
|
105
|
+
controller.abort(timeoutError);
|
|
106
|
+
}, timeoutMs);
|
|
107
|
+
})
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
if (timeout !== undefined) {
|
|
112
|
+
clearTimeout(timeout);
|
|
44
113
|
}
|
|
45
|
-
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function toTransportError(error, url) {
|
|
117
|
+
if (error instanceof OpenApiTransportError) {
|
|
118
|
+
return error;
|
|
119
|
+
}
|
|
120
|
+
const classified = classifyNetworkError(error, url);
|
|
121
|
+
return classified === null
|
|
122
|
+
? null
|
|
123
|
+
: new OpenApiTransportError(classified.message, { cause: error });
|
|
124
|
+
}
|
|
125
|
+
function createOpenApiRequestInit(etag, signal) {
|
|
126
|
+
if (etag === undefined && signal === undefined) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
...(etag === undefined ? {} : { headers: { "If-None-Match": etag } }),
|
|
131
|
+
...(signal === undefined ? {} : { signal })
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function readResponseCacheHeaders(response) {
|
|
135
|
+
const etag = response.headers.get("etag") ?? undefined;
|
|
136
|
+
const cacheControl = response.headers.get("cache-control") ?? undefined;
|
|
137
|
+
const age = response.headers.get("age") ?? undefined;
|
|
138
|
+
return {
|
|
139
|
+
...(etag === undefined ? {} : { etag }),
|
|
140
|
+
...(cacheControl === undefined ? {} : { cacheControl }),
|
|
141
|
+
...(age === undefined ? {} : { age })
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function validateTimeout(timeoutMs) {
|
|
145
|
+
if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {
|
|
146
|
+
throw new UserError("OpenAPI fetch timeout must be a finite non-negative number.");
|
|
46
147
|
}
|
|
47
148
|
}
|
|
48
149
|
export function parseOpenApiDocument(sourceText, input) {
|