@qaick/http-executor 0.1.0-alpha.8 → 0.1.0
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/http-action-executor.js +24 -3
- package/package.json +4 -4
|
@@ -77,11 +77,13 @@ export class HttpActionExecutor {
|
|
|
77
77
|
}
|
|
78
78
|
const timeoutMs = typeof context.step.adapterConfig?.timeoutMs === 'number' ? context.step.adapterConfig.timeoutMs : undefined;
|
|
79
79
|
const response = await this.transport.request(request.url, { ...request, signal: context.signal, ...(timeoutMs !== undefined ? { timeoutMs } : {}) });
|
|
80
|
-
const
|
|
80
|
+
const cookies = responseCookies(response.headers);
|
|
81
|
+
const outputs = { status: response.status, body: response.body, ...(response.headers ? { headers: response.headers } : {}), cookies };
|
|
81
82
|
const responseHeadersName = context.step.adapterConfig?.responseHeadersName;
|
|
82
83
|
if (typeof responseHeadersName === 'string')
|
|
83
84
|
outputs[responseHeadersName] = response.headers ?? {};
|
|
84
85
|
if (response.status < 200 || response.status >= 300) {
|
|
86
|
+
debugFailedRequest(request, response.status);
|
|
85
87
|
throw new HttpActionError('HTTP_STATUS_ERROR', `HTTP Action returned status ${response.status}. ${requestDiagnostics(request, response)}`, { status: response.status });
|
|
86
88
|
}
|
|
87
89
|
const responseFields = isRecord(context.step.adapterConfig?.responseFields) ? context.step.adapterConfig.responseFields : undefined;
|
|
@@ -92,14 +94,19 @@ export class HttpActionExecutor {
|
|
|
92
94
|
if (typeof context.step.adapterConfig?.responseBodyName === 'string')
|
|
93
95
|
outputs[context.step.adapterConfig.responseBodyName] = response.body;
|
|
94
96
|
const finishedAt = new Date().toISOString();
|
|
95
|
-
return { outputs, evidence: { request: { url: request.url, method: request.method, headers: request.headers }, response: { status: response.status, headers: response.headers, body: response.body } }, timing: { startedAt, finishedAt, durationMs: Date.now() - startedMs } };
|
|
97
|
+
return { outputs, evidence: { request: { url: request.url, method: request.method, headers: request.headers }, response: { status: response.status, headers: response.headers, body: response.body, cookies } }, timing: { startedAt, finishedAt, durationMs: Date.now() - startedMs } };
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
function requestDiagnostics(request, response) {
|
|
99
101
|
const parsed = tryParseUrl(request.url);
|
|
100
102
|
const body = request.body === undefined ? undefined : typeof request.body === 'string' ? request.body : JSON.stringify(request.body) ?? '';
|
|
101
103
|
const responseBody = typeof response.body === 'string' ? response.body : JSON.stringify(response.body) ?? '';
|
|
102
|
-
return `Request diagnostics: method=${request.method} path=${parsed?.pathname ?? '(invalid)'} bodyBytes=${byteLength(body)} requestHeaderNames=${headerNames(request.headers).join(',') || '(none)'} responseHeaderNames=${headerNames(response.headers).join(',') || '(none)'} responseBodyBytes=${byteLength(responseBody)}.`;
|
|
104
|
+
return `Request diagnostics: method=${request.method} path=${parsed?.pathname ?? '(invalid)'} bodyBytes=${byteLength(body)} requestHeaderNames=${headerNames(request.headers).join(',') || '(none)'} requestCookieNames=${cookieNames(request.headers).join(',') || '(none)'} requestCookieValueLengths=${cookieValueLengths(request.headers) || '(none)'} requestAuthHeaderLengths=${authHeaderLengths(request.headers) || '(none)'} responseHeaderNames=${headerNames(response.headers).join(',') || '(none)'} responseBodyBytes=${byteLength(responseBody)}.`;
|
|
105
|
+
}
|
|
106
|
+
function debugFailedRequest(request, status) {
|
|
107
|
+
if (typeof process === 'undefined' || process.env.QAICK_HTTP_DEBUG_FULL_REQUEST !== '1')
|
|
108
|
+
return;
|
|
109
|
+
console.error('[QAICK_HTTP_DEBUG_FULL_REQUEST]', { status, request });
|
|
103
110
|
}
|
|
104
111
|
function tryParseUrl(value) {
|
|
105
112
|
try {
|
|
@@ -115,6 +122,20 @@ function headerNames(headers) {
|
|
|
115
122
|
function byteLength(value) {
|
|
116
123
|
return value === undefined ? 0 : new TextEncoder().encode(value).byteLength;
|
|
117
124
|
}
|
|
125
|
+
function cookieNames(headers) {
|
|
126
|
+
const cookie = Object.entries(headers ?? {}).find(([name]) => name.toLowerCase() === 'cookie')?.[1];
|
|
127
|
+
return cookie ? cookie.split(';').map(item => item.trim().split('=', 1)[0]).filter(Boolean) : [];
|
|
128
|
+
}
|
|
129
|
+
function cookieValueLengths(headers) {
|
|
130
|
+
const cookie = Object.entries(headers ?? {}).find(([name]) => name.toLowerCase() === 'cookie')?.[1];
|
|
131
|
+
return cookie ? cookie.split(';').map(item => item.trim()).filter(Boolean).map(item => {
|
|
132
|
+
const separator = item.indexOf('=');
|
|
133
|
+
return separator > 0 ? `${item.slice(0, separator)}:${item.length - separator - 1}` : `${item}:0`;
|
|
134
|
+
}).join(',') : '';
|
|
135
|
+
}
|
|
136
|
+
function authHeaderLengths(headers) {
|
|
137
|
+
return Object.entries(headers ?? {}).filter(([name]) => ['x-auth-token', 'x-xsrf-token'].includes(name.toLowerCase())).map(([name, value]) => `${name.toLowerCase()}:${value.length}`).join(',');
|
|
138
|
+
}
|
|
118
139
|
function responseCookies(headers) {
|
|
119
140
|
const raw = headers && Object.entries(headers).find(([name]) => name.toLowerCase() === 'set-cookie')?.[1];
|
|
120
141
|
const values = Array.isArray(raw) ? raw : raw ? raw.split(/\r?\n|,(?=\s*[^;,=\s]+=[^;,]*)/).map(item => item.trim()).filter(Boolean) : [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qaick/http-executor",
|
|
3
|
-
"version": "0.1.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Reusable QAick HTTP Action execution with browser and native Node transports.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"qaick",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public",
|
|
21
|
-
"tag": "
|
|
21
|
+
"tag": "latest"
|
|
22
22
|
},
|
|
23
23
|
"main": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"prepublishOnly": "npm run build"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@qaick/executor": ">=0.1.0
|
|
42
|
+
"@qaick/executor": ">=0.1.0 <0.2.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@qaick/executor": "0.1.0
|
|
45
|
+
"@qaick/executor": "0.1.0",
|
|
46
46
|
"@types/node": "^24.13.3",
|
|
47
47
|
"typescript": "~6.0.2",
|
|
48
48
|
"vitest": "^5.0.1"
|