norn-cli 1.3.7 → 1.3.9
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/CHANGELOG.md +20 -0
- package/dist/cli.js +103 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the "Norn" extension will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.9] - 2026-02-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`pwsh` Script Type**: Added `pwsh` as an alias for `powershell` in script commands
|
|
9
|
+
- `var x = run pwsh "./script.ps1"` now works alongside `run powershell`
|
|
10
|
+
- **Bare Variable Support in Property Assignments**: Variables can be assigned without `{{}}` syntax
|
|
11
|
+
- `payload.userId = dynamicUserId` now works (previously required `{{dynamicUserId}}`)
|
|
12
|
+
- **Request Body in Verbose Output**: CLI `-v` flag now shows the actual request body and headers sent
|
|
13
|
+
- Helps debug payload issues by showing exactly what was transmitted
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Script Output Capture**: Fixed variable shadowing bug that could affect JSON parsing of script output
|
|
17
|
+
|
|
18
|
+
## [1.3.8] - 2026-02-09
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Named Requests with Endpoint Syntax**: Fixed `run RequestName` failing when the named request uses `.nornapi` endpoint syntax
|
|
22
|
+
- `[PostFormWithEndpoint]` with `POST HttpBinPost Form` now works correctly when invoked via `run PostFormWithEndpoint`
|
|
23
|
+
- Endpoint is resolved and headers/body are properly applied
|
|
24
|
+
|
|
5
25
|
## [1.3.7] - 2026-02-09
|
|
6
26
|
|
|
7
27
|
### Fixed
|
package/dist/cli.js
CHANGED
|
@@ -26192,6 +26192,8 @@ async function sendRequestWithJar(request, jar, retryOptions) {
|
|
|
26192
26192
|
let currentMethod = request.method;
|
|
26193
26193
|
let currentBody = request.body;
|
|
26194
26194
|
let finalResponse = null;
|
|
26195
|
+
let sentRequestBody = void 0;
|
|
26196
|
+
let sentRequestHeaders = {};
|
|
26195
26197
|
try {
|
|
26196
26198
|
while (redirectCount <= maxRedirects) {
|
|
26197
26199
|
const existingCookies = await jar.getCookies(currentUrl);
|
|
@@ -26238,6 +26240,8 @@ async function sendRequestWithJar(request, jar, retryOptions) {
|
|
|
26238
26240
|
}
|
|
26239
26241
|
}
|
|
26240
26242
|
}
|
|
26243
|
+
sentRequestBody = data;
|
|
26244
|
+
sentRequestHeaders = { ...headers };
|
|
26241
26245
|
const response = await axios_default({
|
|
26242
26246
|
method: currentMethod,
|
|
26243
26247
|
url: currentUrl,
|
|
@@ -26290,7 +26294,9 @@ async function sendRequestWithJar(request, jar, retryOptions) {
|
|
|
26290
26294
|
headers: finalResponse.headers,
|
|
26291
26295
|
body: finalResponse.data,
|
|
26292
26296
|
duration: Date.now() - startTime,
|
|
26293
|
-
cookies
|
|
26297
|
+
cookies,
|
|
26298
|
+
requestBody: sentRequestBody,
|
|
26299
|
+
requestHeaders: sentRequestHeaders
|
|
26294
26300
|
};
|
|
26295
26301
|
if (attemptsMade > 1 || totalAttempts > 1) {
|
|
26296
26302
|
result.retryInfo = {
|
|
@@ -26453,23 +26459,25 @@ function isPwshAvailable() {
|
|
|
26453
26459
|
}
|
|
26454
26460
|
function parseRunCommand(line2) {
|
|
26455
26461
|
const trimmed = line2.trim();
|
|
26456
|
-
const captureMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*run\s+(bash|powershell|js)\s+(.+)$/i);
|
|
26462
|
+
const captureMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
|
|
26457
26463
|
if (captureMatch) {
|
|
26458
26464
|
const [, varName, type, rest] = captureMatch;
|
|
26459
26465
|
const { scriptPath, args } = parsePathAndArgs(rest);
|
|
26466
|
+
const normalizedType = type.toLowerCase() === "pwsh" ? "powershell" : type.toLowerCase();
|
|
26460
26467
|
return {
|
|
26461
|
-
type:
|
|
26468
|
+
type: normalizedType,
|
|
26462
26469
|
scriptPath,
|
|
26463
26470
|
args,
|
|
26464
26471
|
captureAs: varName
|
|
26465
26472
|
};
|
|
26466
26473
|
}
|
|
26467
|
-
const runMatch = trimmed.match(/^run\s+(bash|powershell|js)\s+(.+)$/i);
|
|
26474
|
+
const runMatch = trimmed.match(/^run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
|
|
26468
26475
|
if (runMatch) {
|
|
26469
26476
|
const [, type, rest] = runMatch;
|
|
26470
26477
|
const { scriptPath, args } = parsePathAndArgs(rest);
|
|
26478
|
+
const normalizedType = type.toLowerCase() === "pwsh" ? "powershell" : type.toLowerCase();
|
|
26471
26479
|
return {
|
|
26472
|
-
type:
|
|
26480
|
+
type: normalizedType,
|
|
26473
26481
|
scriptPath,
|
|
26474
26482
|
args
|
|
26475
26483
|
};
|
|
@@ -26507,7 +26515,7 @@ function parsePathAndArgs(rest) {
|
|
|
26507
26515
|
}
|
|
26508
26516
|
function isRunCommand(line2) {
|
|
26509
26517
|
const trimmed = line2.trim();
|
|
26510
|
-
return /^(var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)?run\s+(bash|powershell|js)\s+/i.test(trimmed);
|
|
26518
|
+
return /^(var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)?run\s+(bash|powershell|pwsh|js)\s+/i.test(trimmed);
|
|
26511
26519
|
}
|
|
26512
26520
|
async function runScript(type, scriptPath, args, workingDir, variables = {}, captureVar) {
|
|
26513
26521
|
const startTime = Date.now();
|
|
@@ -28021,9 +28029,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28021
28029
|
continue;
|
|
28022
28030
|
}
|
|
28023
28031
|
if (step.type === "propAssign") {
|
|
28024
|
-
const
|
|
28025
|
-
const substitutedContent = substituteVariables(bareResolved, runtimeVariables);
|
|
28026
|
-
const parsed = parsePropertyAssignment(substitutedContent);
|
|
28032
|
+
const parsed = parsePropertyAssignment(step.content);
|
|
28027
28033
|
if (!parsed) {
|
|
28028
28034
|
errors.push(`Step ${stepIdx + 1}: Invalid property assignment: ${step.content}`);
|
|
28029
28035
|
return {
|
|
@@ -28066,9 +28072,11 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28066
28072
|
duration: Date.now() - startTime
|
|
28067
28073
|
};
|
|
28068
28074
|
}
|
|
28069
|
-
|
|
28075
|
+
const bareResolvedValue = resolveBareVariables(parsed.value, runtimeVariables);
|
|
28076
|
+
const resolvedValue = substituteVariables(bareResolvedValue, runtimeVariables);
|
|
28077
|
+
let newValue = resolvedValue;
|
|
28070
28078
|
try {
|
|
28071
|
-
newValue = JSON.parse(
|
|
28079
|
+
newValue = JSON.parse(resolvedValue);
|
|
28072
28080
|
} catch {
|
|
28073
28081
|
}
|
|
28074
28082
|
const success = setNestedValue(jsonObj, parsed.propertyPath, newValue);
|
|
@@ -28305,9 +28313,9 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28305
28313
|
if (parsed.captureAs) {
|
|
28306
28314
|
let outputValue = result.output;
|
|
28307
28315
|
try {
|
|
28308
|
-
const
|
|
28309
|
-
if (typeof
|
|
28310
|
-
outputValue =
|
|
28316
|
+
const jsonParsed = JSON.parse(result.output);
|
|
28317
|
+
if (typeof jsonParsed === "object" && jsonParsed !== null) {
|
|
28318
|
+
outputValue = jsonParsed;
|
|
28311
28319
|
}
|
|
28312
28320
|
} catch {
|
|
28313
28321
|
}
|
|
@@ -28462,9 +28470,68 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28462
28470
|
let requestUrl = "";
|
|
28463
28471
|
let requestMethod = "";
|
|
28464
28472
|
try {
|
|
28465
|
-
let requestParsed
|
|
28466
|
-
if (apiDefinitions && apiDefinitions.
|
|
28467
|
-
|
|
28473
|
+
let requestParsed;
|
|
28474
|
+
if (apiDefinitions && apiDefinitions.endpoints.length > 0 && isApiRequestLine(namedRequest.content, apiDefinitions.endpoints)) {
|
|
28475
|
+
const apiRequest = parseApiRequest(
|
|
28476
|
+
namedRequest.content,
|
|
28477
|
+
apiDefinitions.endpoints,
|
|
28478
|
+
apiDefinitions.headerGroups
|
|
28479
|
+
);
|
|
28480
|
+
if (apiRequest) {
|
|
28481
|
+
const endpoint = getEndpoint(
|
|
28482
|
+
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
28483
|
+
apiRequest.endpointName
|
|
28484
|
+
);
|
|
28485
|
+
if (endpoint) {
|
|
28486
|
+
let resolvedPath = endpoint.path;
|
|
28487
|
+
resolvedPath = resolvedPath.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
28488
|
+
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
28489
|
+
});
|
|
28490
|
+
for (const [paramName, paramValue] of Object.entries(apiRequest.params)) {
|
|
28491
|
+
let resolvedValue = paramValue;
|
|
28492
|
+
if (runtimeVariables[paramValue] !== void 0) {
|
|
28493
|
+
resolvedValue = String(runtimeVariables[paramValue]);
|
|
28494
|
+
} else if (paramValue.startsWith("{{") && paramValue.endsWith("}}")) {
|
|
28495
|
+
const varName = paramValue.slice(2, -2);
|
|
28496
|
+
if (runtimeVariables[varName] !== void 0) {
|
|
28497
|
+
resolvedValue = String(runtimeVariables[varName]);
|
|
28498
|
+
}
|
|
28499
|
+
}
|
|
28500
|
+
resolvedPath = resolvedPath.replace(`{${paramName}}`, resolvedValue);
|
|
28501
|
+
}
|
|
28502
|
+
const combinedHeaders = {};
|
|
28503
|
+
for (const groupName of apiRequest.headerGroupNames) {
|
|
28504
|
+
const group = getHeaderGroup(apiDefinitions, groupName);
|
|
28505
|
+
if (group) {
|
|
28506
|
+
const resolvedHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
28507
|
+
Object.assign(combinedHeaders, resolvedHeaders);
|
|
28508
|
+
}
|
|
28509
|
+
}
|
|
28510
|
+
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
28511
|
+
let resolved = headerValue;
|
|
28512
|
+
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
28513
|
+
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
28514
|
+
});
|
|
28515
|
+
combinedHeaders[headerName] = resolved;
|
|
28516
|
+
}
|
|
28517
|
+
const bodyParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
28518
|
+
requestParsed = {
|
|
28519
|
+
method: apiRequest.method,
|
|
28520
|
+
url: resolvedPath,
|
|
28521
|
+
headers: combinedHeaders,
|
|
28522
|
+
body: bodyParsed.body
|
|
28523
|
+
};
|
|
28524
|
+
} else {
|
|
28525
|
+
throw new Error(`Unknown endpoint: ${apiRequest.endpointName}`);
|
|
28526
|
+
}
|
|
28527
|
+
} else {
|
|
28528
|
+
requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
28529
|
+
}
|
|
28530
|
+
} else {
|
|
28531
|
+
requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
28532
|
+
if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
|
|
28533
|
+
requestParsed = applyHeaderGroupsToRequest(requestParsed, namedRequest.content, apiDefinitions.headerGroups, runtimeVariables);
|
|
28534
|
+
}
|
|
28468
28535
|
}
|
|
28469
28536
|
requestUrl = requestParsed.url;
|
|
28470
28537
|
requestMethod = requestParsed.method;
|
|
@@ -28798,6 +28865,20 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28798
28865
|
if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
|
|
28799
28866
|
parsed = applyHeaderGroupsToRequest(parsed, step.content, apiDefinitions.headerGroups, runtimeVariables);
|
|
28800
28867
|
}
|
|
28868
|
+
if (parsed.body) {
|
|
28869
|
+
const bodyTrimmed = parsed.body.trim();
|
|
28870
|
+
const bareVarMatch = bodyTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)$/);
|
|
28871
|
+
if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
|
|
28872
|
+
const varValue = runtimeVariables[bareVarMatch[1]];
|
|
28873
|
+
if (typeof varValue === "object" && varValue !== null) {
|
|
28874
|
+
parsed.body = JSON.stringify(varValue);
|
|
28875
|
+
} else if (typeof varValue === "string") {
|
|
28876
|
+
parsed.body = varValue;
|
|
28877
|
+
} else {
|
|
28878
|
+
parsed.body = String(varValue);
|
|
28879
|
+
}
|
|
28880
|
+
}
|
|
28881
|
+
}
|
|
28801
28882
|
}
|
|
28802
28883
|
const { retryCount, backoffMs } = extractRetryOptions(step.content);
|
|
28803
28884
|
const retryOpts = retryCount ?? parsed.retryCount ? {
|
|
@@ -29316,11 +29397,13 @@ function formatRequestStep(step, options) {
|
|
|
29316
29397
|
colors,
|
|
29317
29398
|
redaction,
|
|
29318
29399
|
verbose,
|
|
29319
|
-
showDetails: !isSuccess,
|
|
29320
|
-
// Show request details on failure
|
|
29400
|
+
showDetails: !isSuccess || verbose,
|
|
29401
|
+
// Show request details on failure or verbose
|
|
29321
29402
|
index: requestIndex,
|
|
29322
29403
|
method: step.requestMethod,
|
|
29323
|
-
url: step.requestUrl
|
|
29404
|
+
url: step.requestUrl,
|
|
29405
|
+
requestBody: step.response.requestBody,
|
|
29406
|
+
requestHeaders: step.response.requestHeaders
|
|
29324
29407
|
});
|
|
29325
29408
|
}
|
|
29326
29409
|
function formatAssertionStep(step, options) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "norn-cli",
|
|
3
3
|
"displayName": "Norn - REST Client",
|
|
4
4
|
"description": "A powerful REST client for making HTTP requests with sequences, variables, scripts, and cookie support",
|
|
5
|
-
"version": "1.3.
|
|
5
|
+
"version": "1.3.9",
|
|
6
6
|
"publisher": "Norn-PeterKrustanov",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Peter Krastanov"
|