@elench/testkit 0.1.81 → 0.1.83
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/README.md +64 -27
- package/lib/cli/agents/index.mjs +64 -0
- package/lib/cli/agents/investigate.mjs +75 -0
- package/lib/cli/agents/investigation-context.mjs +102 -0
- package/lib/cli/agents/investigation-context.test.mjs +144 -0
- package/lib/cli/agents/prompt-builder.mjs +25 -0
- package/lib/cli/agents/providers/claude.mjs +74 -0
- package/lib/cli/agents/providers/claude.test.mjs +95 -0
- package/lib/cli/agents/providers/codex.mjs +83 -0
- package/lib/cli/agents/providers/codex.test.mjs +93 -0
- package/lib/cli/agents/providers/shared.mjs +134 -0
- package/lib/cli/command-helpers.mjs +53 -25
- package/lib/cli/command-helpers.test.mjs +122 -0
- package/lib/cli/commands/investigate.mjs +87 -0
- package/lib/cli/commands/investigate.test.mjs +83 -0
- package/lib/cli/entrypoint.mjs +3 -0
- package/lib/cli/presentation/colors.mjs +12 -0
- package/lib/cli/presentation/events-reporter.mjs +135 -0
- package/lib/cli/presentation/events-reporter.test.mjs +73 -0
- package/lib/cli/presentation/summary-box.mjs +11 -11
- package/lib/cli/presentation/summary-box.test.mjs +17 -0
- package/lib/cli/presentation/tree-reporter.mjs +159 -0
- package/lib/cli/presentation/tree-reporter.test.mjs +166 -0
- package/lib/cli/tui/run-app.mjs +1 -0
- package/lib/cli/tui/run-session-app.mjs +370 -0
- package/lib/cli/tui/run-session-app.test.mjs +50 -0
- package/lib/cli/tui/run-session-state.mjs +481 -0
- package/lib/cli/tui/run-tree-state.mjs +1 -0
- package/lib/cli/tui/run-tree-state.test.mjs +324 -0
- package/lib/config-api/auth-fixtures.mjs +767 -0
- package/lib/config-api/index.d.ts +92 -108
- package/lib/config-api/index.mjs +22 -12
- package/lib/config-api/index.test.mjs +103 -210
- package/lib/discovery/index.mjs +1 -1
- package/lib/index.d.ts +34 -10
- package/lib/runner/orchestrator.mjs +1 -0
- package/lib/runtime/index.d.ts +177 -27
- package/lib/runtime/index.mjs +68 -3
- package/lib/runtime-src/k6/http-assertions.js +31 -1
- package/lib/runtime-src/k6/http-checks.js +120 -0
- package/lib/runtime-src/k6/http-checks.test.mjs +120 -0
- package/lib/runtime-src/k6/http-suite-runtime.js +151 -0
- package/lib/runtime-src/k6/http.js +285 -56
- package/lib/runtime-src/k6/http.test.mjs +205 -0
- package/lib/runtime-src/k6/scenario-suite.js +13 -110
- package/lib/runtime-src/k6/suite.js +13 -107
- package/lib/runtime-src/shared/error-body.mjs +42 -0
- package/lib/runtime-src/shared/http-parsing.mjs +68 -0
- package/lib/runtime-src/shared/http-parsing.test.mjs +69 -0
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +5 -5
- package/lib/config-api/profiles.mjs +0 -640
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createHttpClient, getEnv } from "./http.js";
|
|
2
|
+
import { resolveHttpProfile } from "../../config-api/runtime.mjs";
|
|
3
|
+
|
|
4
|
+
export function normalizeSuiteArgs(configOrRun, maybeRun) {
|
|
5
|
+
if (typeof configOrRun === "function") {
|
|
6
|
+
return { config: {}, run: configOrRun };
|
|
7
|
+
}
|
|
8
|
+
if (typeof maybeRun !== "function") {
|
|
9
|
+
throw new Error("suite factory requires a run callback");
|
|
10
|
+
}
|
|
11
|
+
return { config: configOrRun || {}, run: maybeRun };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function mergeProfileConfig(config) {
|
|
15
|
+
if (!config?.profile) return config || {};
|
|
16
|
+
|
|
17
|
+
const profile = resolveHttpProfile(config.profile) || {};
|
|
18
|
+
return {
|
|
19
|
+
...profile,
|
|
20
|
+
...config,
|
|
21
|
+
auth: config.auth ?? profile.auth ?? null,
|
|
22
|
+
headers: config.headers ?? profile.headers,
|
|
23
|
+
rawHeaders: config.rawHeaders ?? profile.rawHeaders,
|
|
24
|
+
options: config.options ?? profile.options,
|
|
25
|
+
env: config.env ?? profile.env,
|
|
26
|
+
__testkitAuthProfile: config.__testkitAuthProfile ?? profile.__testkitAuthProfile ?? null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveRuntimeConfig(config, sessionBundle = null) {
|
|
31
|
+
const resolvedConfig = mergeProfileConfig(config);
|
|
32
|
+
const env = {
|
|
33
|
+
...(resolvedConfig.env || getEnv()),
|
|
34
|
+
rawEnv: __ENV,
|
|
35
|
+
};
|
|
36
|
+
const auth = resolvedConfig.auth || null;
|
|
37
|
+
const profileMeta = resolvedConfig.__testkitAuthProfile || null;
|
|
38
|
+
const client = createHttpClient({
|
|
39
|
+
baseUrl: env.BASE,
|
|
40
|
+
defaultActor: profileMeta?.primaryActor || sessionBundle?.primaryActor || null,
|
|
41
|
+
routeHeaders: env.routeParams,
|
|
42
|
+
sessionBundle,
|
|
43
|
+
getHeaders(context) {
|
|
44
|
+
return {
|
|
45
|
+
...callHeaders(auth?.headers, sessionBundle, env, context.actorName),
|
|
46
|
+
...callHeaders(resolvedConfig.headers, sessionBundle, env, context.actorName),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
getRawHeaders(context) {
|
|
50
|
+
return callHeaders(resolvedConfig.rawHeaders, sessionBundle, env, context.actorName);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
auth,
|
|
56
|
+
client,
|
|
57
|
+
env,
|
|
58
|
+
profileMeta,
|
|
59
|
+
resolvedConfig,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function createSuiteActors(sessionBundle, client, profileMeta) {
|
|
64
|
+
const actorNames = profileMeta?.actorNames || Object.keys(sessionBundle?.actors || {});
|
|
65
|
+
const entries = actorNames.map((actorName) => {
|
|
66
|
+
const actorRecord = sessionBundle?.actors?.[actorName] || null;
|
|
67
|
+
const actorClient = client.as(actorName);
|
|
68
|
+
return {
|
|
69
|
+
email: actorRecord?.email || null,
|
|
70
|
+
headers: actorClient.headers(),
|
|
71
|
+
index: Number(actorRecord?.actorIndex ?? 0),
|
|
72
|
+
key: actorName,
|
|
73
|
+
name: actorRecord?.name || null,
|
|
74
|
+
organizationKey: actorRecord?.organizationKey || null,
|
|
75
|
+
organizationName: actorRecord?.organizationName || null,
|
|
76
|
+
rawHeaders: actorClient.rawHeaders(),
|
|
77
|
+
rawReq: actorClient.rawReq,
|
|
78
|
+
req: actorClient,
|
|
79
|
+
session: actorRecord?.session || null,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const byName = new Map(entries.map((entry, index) => [actorNames[index], entry]));
|
|
83
|
+
const primaryName = profileMeta?.primaryActor || sessionBundle?.primaryActor || null;
|
|
84
|
+
const primary = primaryName ? byName.get(primaryName) || null : null;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
actor: primary,
|
|
88
|
+
actors: {
|
|
89
|
+
names: actorNames,
|
|
90
|
+
primary,
|
|
91
|
+
get(name) {
|
|
92
|
+
const actor = byName.get(name);
|
|
93
|
+
if (!actor) {
|
|
94
|
+
throw new Error(`Unknown testkit actor "${name}"`);
|
|
95
|
+
}
|
|
96
|
+
return actor;
|
|
97
|
+
},
|
|
98
|
+
has(name) {
|
|
99
|
+
return byName.has(name);
|
|
100
|
+
},
|
|
101
|
+
list() {
|
|
102
|
+
return entries.slice();
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function formatFatalSuiteError(phase, error) {
|
|
109
|
+
if (error instanceof Error) {
|
|
110
|
+
return `Uncaught testkit suite error during ${phase}: ${error.message}`;
|
|
111
|
+
}
|
|
112
|
+
return `Uncaught testkit suite error during ${phase}: ${String(error)}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function buildRuntimeExceptionDetail(phase, error) {
|
|
116
|
+
const message =
|
|
117
|
+
error instanceof Error ? error.message : String(error);
|
|
118
|
+
const stack = error instanceof Error && typeof error.stack === "string" ? error.stack : "";
|
|
119
|
+
const location = extractLocationFromStack(stack);
|
|
120
|
+
return {
|
|
121
|
+
kind: "runtime-exception",
|
|
122
|
+
key: location ? `${location.path}:${location.line}:${location.column}` : `runtime-exception:${phase}:${message}`,
|
|
123
|
+
title: "Uncaught runtime exception",
|
|
124
|
+
message: `Uncaught testkit suite error during ${phase}: ${message}`,
|
|
125
|
+
location,
|
|
126
|
+
stack,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function callHeaders(builder, sessionBundle, env, actorName) {
|
|
131
|
+
if (typeof builder !== "function") return {};
|
|
132
|
+
return builder(sessionBundle, { actor: actorName || null, env }) || {};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function extractLocationFromStack(stack) {
|
|
136
|
+
if (!stack) return null;
|
|
137
|
+
const matches = [...String(stack).matchAll(/(file:\/\/[^\s)]+|\/[^\s):]+):(\d+):(\d+)/g)].map((match) => ({
|
|
138
|
+
path: normalizeStackPath(match[1]),
|
|
139
|
+
line: Number(match[2]),
|
|
140
|
+
column: Number(match[3]),
|
|
141
|
+
}));
|
|
142
|
+
return matches[0] || null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function normalizeStackPath(rawPath) {
|
|
146
|
+
if (typeof rawPath !== "string") return rawPath;
|
|
147
|
+
if (rawPath.startsWith("file://")) {
|
|
148
|
+
return rawPath.slice("file://".length);
|
|
149
|
+
}
|
|
150
|
+
return rawPath;
|
|
151
|
+
}
|
|
@@ -24,8 +24,10 @@ export function getEnv() {
|
|
|
24
24
|
export function createHttpClient(config) {
|
|
25
25
|
const {
|
|
26
26
|
baseUrl,
|
|
27
|
+
defaultActor = null,
|
|
27
28
|
routeHeaders = {},
|
|
28
29
|
defaultHeaders = { "Content-Type": "application/json" },
|
|
30
|
+
sessionBundle = null,
|
|
29
31
|
getHeaders = null,
|
|
30
32
|
getRawHeaders = null,
|
|
31
33
|
} = config;
|
|
@@ -34,81 +36,280 @@ export function createHttpClient(config) {
|
|
|
34
36
|
throw new Error("baseUrl is required");
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
function buildHeaders(builder,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...
|
|
39
|
+
function buildHeaders(builder, context, extraHeaders = {}, options = {}) {
|
|
40
|
+
const { includeDefaultHeaders = true, contentTypeJson = true } = options;
|
|
41
|
+
const resolvedHeaders = {
|
|
42
|
+
...(includeDefaultHeaders ? defaultHeaders : {}),
|
|
43
|
+
...safeHeaders(builder, context),
|
|
41
44
|
...routeHeaders,
|
|
42
45
|
...extraHeaders,
|
|
43
46
|
};
|
|
47
|
+
|
|
48
|
+
if (contentTypeJson === false) {
|
|
49
|
+
delete resolvedHeaders["Content-Type"];
|
|
50
|
+
delete resolvedHeaders["content-type"];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return resolvedHeaders;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildHeaderContext(actorName = null) {
|
|
57
|
+
return {
|
|
58
|
+
actor: actorName && sessionBundle?.actors ? sessionBundle.actors[actorName] || null : null,
|
|
59
|
+
actorName,
|
|
60
|
+
sessionBundle,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ensureKnownActor(actorName) {
|
|
65
|
+
if (!actorName || !sessionBundle?.actors) return;
|
|
66
|
+
if (!sessionBundle.actors[actorName]) {
|
|
67
|
+
throw new Error(`Unknown testkit actor "${actorName}"`);
|
|
68
|
+
}
|
|
44
69
|
}
|
|
45
70
|
|
|
46
|
-
function
|
|
71
|
+
function resolvedHeadersFor(actorName, extraHeaders = {}) {
|
|
72
|
+
ensureKnownActor(actorName);
|
|
73
|
+
const headerContext = buildHeaderContext(actorName);
|
|
74
|
+
return buildHeaders(getHeaders, headerContext, extraHeaders);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function resolvedRawHeadersFor(actorName = null, extraHeaders = {}) {
|
|
78
|
+
ensureKnownActor(actorName);
|
|
79
|
+
const headerContext = buildHeaderContext(actorName);
|
|
80
|
+
return buildHeaders(getRawHeaders, headerContext, extraHeaders);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function requestAs(actorName, method, path, body, extraHeaders = {}, options = {}) {
|
|
84
|
+
ensureKnownActor(actorName);
|
|
47
85
|
const url = `${baseUrl}${path}`;
|
|
48
|
-
const
|
|
49
|
-
|
|
86
|
+
const headerContext = buildHeaderContext(actorName);
|
|
87
|
+
const headers = buildHeaders(getHeaders, headerContext, extraHeaders, {
|
|
88
|
+
contentTypeJson: options.contentTypeJson !== false,
|
|
89
|
+
includeDefaultHeaders: options.includeDefaultHeaders !== false,
|
|
90
|
+
});
|
|
91
|
+
return runHttpRequest(method, path, url, body, headers, headerContext.actor, options);
|
|
50
92
|
}
|
|
51
93
|
|
|
52
|
-
function
|
|
94
|
+
function rawAs(actorName, method, path, body, extraHeaders = {}, options = {}) {
|
|
95
|
+
ensureKnownActor(actorName);
|
|
53
96
|
const url = `${baseUrl}${path}`;
|
|
54
|
-
const
|
|
55
|
-
|
|
97
|
+
const headerContext = buildHeaderContext(actorName);
|
|
98
|
+
const headers = buildHeaders(getRawHeaders, headerContext, extraHeaders, {
|
|
99
|
+
contentTypeJson: options.contentTypeJson !== false,
|
|
100
|
+
includeDefaultHeaders: options.includeDefaultHeaders !== false,
|
|
101
|
+
});
|
|
102
|
+
return runHttpRequest(method, path, url, body, headers, headerContext.actor, options);
|
|
56
103
|
}
|
|
57
104
|
|
|
58
|
-
function
|
|
59
|
-
return
|
|
60
|
-
"GET",
|
|
61
|
-
path,
|
|
62
|
-
`${baseUrl}${path}`,
|
|
63
|
-
null,
|
|
64
|
-
buildHeaders(getHeaders, setupData, extraHeaders)
|
|
65
|
-
);
|
|
105
|
+
function raw(method, path, body, extraHeaders = {}) {
|
|
106
|
+
return rawAs(null, method, path, body, extraHeaders);
|
|
66
107
|
}
|
|
67
108
|
|
|
109
|
+
function requestMultipart(actorName, method, path, payload, extraHeaders = {}, options = {}) {
|
|
110
|
+
const body = buildMultipartBody(payload);
|
|
111
|
+
return requestAs(actorName, method, path, body, extraHeaders, {
|
|
112
|
+
...options,
|
|
113
|
+
contentTypeJson: false,
|
|
114
|
+
includeDefaultHeaders: false,
|
|
115
|
+
serialize: "raw",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function rawMultipart(actorName, method, path, payload, extraHeaders = {}, options = {}) {
|
|
120
|
+
const body = buildMultipartBody(payload);
|
|
121
|
+
return rawAs(actorName, method, path, body, extraHeaders, {
|
|
122
|
+
...options,
|
|
123
|
+
contentTypeJson: false,
|
|
124
|
+
includeDefaultHeaders: false,
|
|
125
|
+
serialize: "raw",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function createActorClient(actorName) {
|
|
130
|
+
const actorRawReq = createRawInvoker(actorName);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
headers(extraHeaders = {}) {
|
|
134
|
+
return resolvedHeadersFor(actorName, extraHeaders);
|
|
135
|
+
},
|
|
136
|
+
rawHeaders(extraHeaders = {}) {
|
|
137
|
+
return resolvedRawHeadersFor(actorName, extraHeaders);
|
|
138
|
+
},
|
|
139
|
+
rawReq: actorRawReq,
|
|
140
|
+
delete(path, extraHeaders = {}) {
|
|
141
|
+
return requestAs(actorName, "DELETE", path, null, extraHeaders);
|
|
142
|
+
},
|
|
143
|
+
get(path, extraHeaders = {}) {
|
|
144
|
+
return requestAs(actorName, "GET", path, null, extraHeaders);
|
|
145
|
+
},
|
|
146
|
+
patch(path, body, extraHeaders = {}) {
|
|
147
|
+
return requestAs(actorName, "PATCH", path, body, extraHeaders);
|
|
148
|
+
},
|
|
149
|
+
post(path, body, extraHeaders = {}) {
|
|
150
|
+
return requestAs(actorName, "POST", path, body, extraHeaders);
|
|
151
|
+
},
|
|
152
|
+
put(path, body, extraHeaders = {}) {
|
|
153
|
+
return requestAs(actorName, "PUT", path, body, extraHeaders);
|
|
154
|
+
},
|
|
155
|
+
request(method, path, body, extraHeaders = {}) {
|
|
156
|
+
return requestAs(actorName, method, path, body, extraHeaders);
|
|
157
|
+
},
|
|
158
|
+
raw(method, path, body, extraHeaders = {}) {
|
|
159
|
+
return actorRawReq(method, path, body, extraHeaders);
|
|
160
|
+
},
|
|
161
|
+
rawDelete(path, extraHeaders = {}) {
|
|
162
|
+
return actorRawReq.delete(path, extraHeaders);
|
|
163
|
+
},
|
|
164
|
+
rawGet(path, extraHeaders = {}) {
|
|
165
|
+
return actorRawReq.get(path, extraHeaders);
|
|
166
|
+
},
|
|
167
|
+
rawPatch(path, body, extraHeaders = {}) {
|
|
168
|
+
return actorRawReq.patch(path, body, extraHeaders);
|
|
169
|
+
},
|
|
170
|
+
rawPost(path, body, extraHeaders = {}) {
|
|
171
|
+
return actorRawReq.post(path, body, extraHeaders);
|
|
172
|
+
},
|
|
173
|
+
rawPut(path, body, extraHeaders = {}) {
|
|
174
|
+
return actorRawReq.put(path, body, extraHeaders);
|
|
175
|
+
},
|
|
176
|
+
multipart: {
|
|
177
|
+
post(path, payload, extraHeaders = {}) {
|
|
178
|
+
return requestMultipart(actorName, "POST", path, payload, extraHeaders);
|
|
179
|
+
},
|
|
180
|
+
put(path, payload, extraHeaders = {}) {
|
|
181
|
+
return requestMultipart(actorName, "PUT", path, payload, extraHeaders);
|
|
182
|
+
},
|
|
183
|
+
patch(path, payload, extraHeaders = {}) {
|
|
184
|
+
return requestMultipart(actorName, "PATCH", path, payload, extraHeaders);
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
rawMultipart: {
|
|
188
|
+
post(path, payload, extraHeaders = {}) {
|
|
189
|
+
return actorRawReq.multipart.post(path, payload, extraHeaders);
|
|
190
|
+
},
|
|
191
|
+
put(path, payload, extraHeaders = {}) {
|
|
192
|
+
return actorRawReq.multipart.put(path, payload, extraHeaders);
|
|
193
|
+
},
|
|
194
|
+
patch(path, payload, extraHeaders = {}) {
|
|
195
|
+
return actorRawReq.multipart.patch(path, payload, extraHeaders);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function createRawInvoker(defaultRawActor = null) {
|
|
202
|
+
const invoker = (method, path, body, extraHeaders = {}) =>
|
|
203
|
+
rawAs(defaultRawActor, method, path, body, extraHeaders);
|
|
204
|
+
|
|
205
|
+
invoker.request = (method, path, body, extraHeaders = {}) =>
|
|
206
|
+
rawAs(defaultRawActor, method, path, body, extraHeaders);
|
|
207
|
+
invoker.get = (path, extraHeaders = {}) => rawAs(defaultRawActor, "GET", path, null, extraHeaders);
|
|
208
|
+
invoker.post = (path, body, extraHeaders = {}) => rawAs(defaultRawActor, "POST", path, body, extraHeaders);
|
|
209
|
+
invoker.put = (path, body, extraHeaders = {}) => rawAs(defaultRawActor, "PUT", path, body, extraHeaders);
|
|
210
|
+
invoker.patch = (path, body, extraHeaders = {}) => rawAs(defaultRawActor, "PATCH", path, body, extraHeaders);
|
|
211
|
+
invoker.delete = (path, extraHeaders = {}) =>
|
|
212
|
+
rawAs(defaultRawActor, "DELETE", path, null, extraHeaders);
|
|
213
|
+
invoker.headers = (extraHeaders = {}) => resolvedRawHeadersFor(defaultRawActor, extraHeaders);
|
|
214
|
+
invoker.as = (actorName) => {
|
|
215
|
+
ensureKnownActor(actorName);
|
|
216
|
+
return createRawInvoker(actorName);
|
|
217
|
+
};
|
|
218
|
+
invoker.multipart = {
|
|
219
|
+
post(path, payload, extraHeaders = {}) {
|
|
220
|
+
return rawMultipart(defaultRawActor, "POST", path, payload, extraHeaders);
|
|
221
|
+
},
|
|
222
|
+
put(path, payload, extraHeaders = {}) {
|
|
223
|
+
return rawMultipart(defaultRawActor, "PUT", path, payload, extraHeaders);
|
|
224
|
+
},
|
|
225
|
+
patch(path, payload, extraHeaders = {}) {
|
|
226
|
+
return rawMultipart(defaultRawActor, "PATCH", path, payload, extraHeaders);
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return invoker;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const defaultClient = createActorClient(defaultActor);
|
|
234
|
+
const rawClient = createRawInvoker(null);
|
|
235
|
+
|
|
68
236
|
return {
|
|
69
237
|
rawHttp: http,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
238
|
+
headers(extraHeaders = {}) {
|
|
239
|
+
return resolvedHeadersFor(defaultActor, extraHeaders);
|
|
240
|
+
},
|
|
241
|
+
rawHeaders(actorName = null, extraHeaders = {}) {
|
|
242
|
+
return resolvedRawHeadersFor(actorName, extraHeaders);
|
|
243
|
+
},
|
|
244
|
+
as(actorName) {
|
|
245
|
+
ensureKnownActor(actorName);
|
|
246
|
+
return createActorClient(actorName);
|
|
74
247
|
},
|
|
75
|
-
|
|
76
|
-
|
|
248
|
+
request: defaultClient.request,
|
|
249
|
+
raw: rawClient,
|
|
250
|
+
get(path, extraHeaders = {}) {
|
|
251
|
+
return defaultClient.get(path, extraHeaders);
|
|
77
252
|
},
|
|
78
|
-
|
|
79
|
-
return
|
|
253
|
+
put(path, body, extraHeaders = {}) {
|
|
254
|
+
return defaultClient.put(path, body, extraHeaders);
|
|
80
255
|
},
|
|
81
|
-
|
|
82
|
-
return
|
|
256
|
+
post(path, body, extraHeaders = {}) {
|
|
257
|
+
return defaultClient.post(path, body, extraHeaders);
|
|
83
258
|
},
|
|
84
|
-
|
|
85
|
-
return
|
|
259
|
+
patch(path, body, extraHeaders = {}) {
|
|
260
|
+
return defaultClient.patch(path, body, extraHeaders);
|
|
261
|
+
},
|
|
262
|
+
delete(path, extraHeaders = {}) {
|
|
263
|
+
return defaultClient.delete(path, extraHeaders);
|
|
86
264
|
},
|
|
87
265
|
rawGet(path, extraHeaders = {}) {
|
|
88
|
-
return
|
|
266
|
+
return rawClient.get(path, extraHeaders);
|
|
89
267
|
},
|
|
90
268
|
rawPost(path, body, extraHeaders = {}) {
|
|
91
|
-
return
|
|
269
|
+
return rawClient.post(path, body, extraHeaders);
|
|
92
270
|
},
|
|
93
271
|
rawPut(path, body, extraHeaders = {}) {
|
|
94
|
-
return
|
|
272
|
+
return rawClient.put(path, body, extraHeaders);
|
|
95
273
|
},
|
|
96
274
|
rawPatch(path, body, extraHeaders = {}) {
|
|
97
|
-
return
|
|
275
|
+
return rawClient.patch(path, body, extraHeaders);
|
|
98
276
|
},
|
|
99
277
|
rawDelete(path, extraHeaders = {}) {
|
|
100
|
-
return
|
|
278
|
+
return rawClient.delete(path, extraHeaders);
|
|
279
|
+
},
|
|
280
|
+
multipart: {
|
|
281
|
+
post(path, payload, extraHeaders = {}) {
|
|
282
|
+
return requestMultipart(defaultActor, "POST", path, payload, extraHeaders);
|
|
283
|
+
},
|
|
284
|
+
put(path, payload, extraHeaders = {}) {
|
|
285
|
+
return requestMultipart(defaultActor, "PUT", path, payload, extraHeaders);
|
|
286
|
+
},
|
|
287
|
+
patch(path, payload, extraHeaders = {}) {
|
|
288
|
+
return requestMultipart(defaultActor, "PATCH", path, payload, extraHeaders);
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
rawMultipart: {
|
|
292
|
+
post(path, payload, extraHeaders = {}) {
|
|
293
|
+
return rawClient.multipart.post(path, payload, extraHeaders);
|
|
294
|
+
},
|
|
295
|
+
put(path, payload, extraHeaders = {}) {
|
|
296
|
+
return rawClient.multipart.put(path, payload, extraHeaders);
|
|
297
|
+
},
|
|
298
|
+
patch(path, payload, extraHeaders = {}) {
|
|
299
|
+
return rawClient.multipart.patch(path, payload, extraHeaders);
|
|
300
|
+
},
|
|
101
301
|
},
|
|
102
|
-
getWithHeaders,
|
|
103
302
|
};
|
|
104
303
|
}
|
|
105
304
|
|
|
106
|
-
export function makeReq(baseUrl, routeHeaders = {}, getHeaders = null) {
|
|
305
|
+
export function makeReq(baseUrl, sessionBundle = null, routeHeaders = {}, getHeaders = null, defaultActor = null) {
|
|
107
306
|
return createHttpClient({
|
|
108
307
|
baseUrl,
|
|
109
308
|
routeHeaders,
|
|
309
|
+
sessionBundle,
|
|
310
|
+
defaultActor,
|
|
110
311
|
getHeaders,
|
|
111
|
-
})
|
|
312
|
+
});
|
|
112
313
|
}
|
|
113
314
|
|
|
114
315
|
export function makeRawReq(baseUrl, routeHeaders = {}, getRawHeaders = null) {
|
|
@@ -119,15 +320,7 @@ export function makeRawReq(baseUrl, routeHeaders = {}, getRawHeaders = null) {
|
|
|
119
320
|
}).raw;
|
|
120
321
|
}
|
|
121
322
|
|
|
122
|
-
|
|
123
|
-
return createHttpClient({
|
|
124
|
-
baseUrl,
|
|
125
|
-
routeHeaders,
|
|
126
|
-
getHeaders,
|
|
127
|
-
}).getWithHeaders;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function runHttpRequest(method, path, url, body, headers) {
|
|
323
|
+
function runHttpRequest(method, path, url, body, headers, actorRecord = null, requestOptions = {}) {
|
|
131
324
|
const ordinal = nextTraceOrdinal();
|
|
132
325
|
const requestId = buildRequestId(ordinal);
|
|
133
326
|
const finalHeaders = {
|
|
@@ -140,16 +333,18 @@ function runHttpRequest(method, path, url, body, headers) {
|
|
|
140
333
|
method,
|
|
141
334
|
path,
|
|
142
335
|
url,
|
|
336
|
+
actorRecord,
|
|
143
337
|
requestHeaders: finalHeaders,
|
|
144
338
|
});
|
|
145
|
-
const
|
|
339
|
+
const transportOptions = { headers: finalHeaders };
|
|
146
340
|
|
|
147
341
|
let rawResponse;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
else if (method === "
|
|
151
|
-
else if (method === "
|
|
152
|
-
else if (method === "
|
|
342
|
+
const requestBody = serializeRequestBody(body, requestOptions.serialize || "json");
|
|
343
|
+
if (method === "GET") rawResponse = http.get(url, transportOptions);
|
|
344
|
+
else if (method === "PUT") rawResponse = http.put(url, requestBody, transportOptions);
|
|
345
|
+
else if (method === "POST") rawResponse = http.post(url, requestBody, transportOptions);
|
|
346
|
+
else if (method === "PATCH") rawResponse = http.patch(url, requestBody, transportOptions);
|
|
347
|
+
else if (method === "DELETE") rawResponse = http.del(url, null, transportOptions);
|
|
153
348
|
else throw new Error(`unsupported method: ${method}`);
|
|
154
349
|
|
|
155
350
|
finalizeTrace(trace, rawResponse);
|
|
@@ -190,7 +385,10 @@ export function summarizeHttpTrace(response) {
|
|
|
190
385
|
const trace = getHttpTrace(response);
|
|
191
386
|
if (!trace) return null;
|
|
192
387
|
return {
|
|
388
|
+
actorName: trace.actorName,
|
|
193
389
|
id: trace.id,
|
|
390
|
+
organizationKey: trace.organizationKey,
|
|
391
|
+
organizationName: trace.organizationName,
|
|
194
392
|
requestId: trace.requestId,
|
|
195
393
|
method: trace.method,
|
|
196
394
|
path: trace.path,
|
|
@@ -235,9 +433,12 @@ export function toBodyPreview(response) {
|
|
|
235
433
|
return truncate(rawBody, TRACE_PREVIEW_LIMIT);
|
|
236
434
|
}
|
|
237
435
|
|
|
238
|
-
function createTrace({ ordinal, requestId, method, path, url, requestHeaders }) {
|
|
436
|
+
function createTrace({ ordinal, requestId, method, path, url, actorRecord, requestHeaders }) {
|
|
239
437
|
return {
|
|
438
|
+
actorName: actorRecord?.actorName || null,
|
|
240
439
|
id: `${traceState.phase}-${String(ordinal).padStart(3, "0")}`,
|
|
440
|
+
organizationKey: actorRecord?.organizationKey || null,
|
|
441
|
+
organizationName: actorRecord?.organizationName || null,
|
|
241
442
|
requestId,
|
|
242
443
|
startedAt: new Date().toISOString(),
|
|
243
444
|
method,
|
|
@@ -342,9 +543,9 @@ function normalizeLabel(value, fallback) {
|
|
|
342
543
|
return normalized.length > 0 ? normalized : fallback;
|
|
343
544
|
}
|
|
344
545
|
|
|
345
|
-
function safeHeaders(builder,
|
|
546
|
+
function safeHeaders(builder, context) {
|
|
346
547
|
if (typeof builder !== "function") return {};
|
|
347
|
-
return builder(
|
|
548
|
+
return builder(context) || {};
|
|
348
549
|
}
|
|
349
550
|
|
|
350
551
|
function createWrappedResponse(rawResponse, trace) {
|
|
@@ -381,3 +582,31 @@ function decodeQueryComponent(value) {
|
|
|
381
582
|
return String(value || "");
|
|
382
583
|
}
|
|
383
584
|
}
|
|
585
|
+
|
|
586
|
+
function serializeRequestBody(body, mode = "json") {
|
|
587
|
+
if (body == null) return body;
|
|
588
|
+
if (mode === "raw") return body;
|
|
589
|
+
if (typeof body === "string") return body;
|
|
590
|
+
return JSON.stringify(body);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function buildMultipartBody(payload = {}) {
|
|
594
|
+
const fields = payload?.fields || {};
|
|
595
|
+
const files = Array.isArray(payload?.files) ? payload.files : [];
|
|
596
|
+
const body = { ...fields };
|
|
597
|
+
|
|
598
|
+
for (const fileEntry of files) {
|
|
599
|
+
if (!fileEntry || typeof fileEntry !== "object") {
|
|
600
|
+
throw new Error("multipart file entries must be objects");
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const field = String(fileEntry.field || "").trim();
|
|
604
|
+
if (!field) {
|
|
605
|
+
throw new Error("multipart file entries require a field name");
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
body[field] = http.file(fileEntry.data, fileEntry.filename, fileEntry.contentType);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return body;
|
|
612
|
+
}
|