@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.
@@ -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 outputs = { status: response.status, body: response.body, ...(response.headers ? { headers: response.headers } : {}), cookies: responseCookies(response.headers) };
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-alpha.8",
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": "alpha"
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-alpha.1 <0.2.0"
42
+ "@qaick/executor": ">=0.1.0 <0.2.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@qaick/executor": "0.1.0-alpha.2",
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"