callman-core 1.34.0 → 1.36.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/ai-packs/feature-policy.md +1 -6
- package/ai-packs/pm-api.md +246 -97
- package/ai-packs/sandbox-globals.md +6 -5
- package/dist/ai/prompts/fragments.d.ts.map +1 -1
- package/dist/ai/prompts/fragments.js +0 -1
- package/dist/ai/prompts/fragments.js.map +1 -1
- package/dist/ai/prompts/unified.js +1 -1
- package/dist/ai/prompts/unified.js.map +1 -1
- package/dist/ai/types.d.ts +1 -1
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/runner/requestRunner.d.ts.map +1 -1
- package/dist/runner/requestRunner.js +339 -1
- package/dist/runner/requestRunner.js.map +1 -1
- package/dist/runner/runCollection.d.ts +1 -1
- package/dist/runner/runCollection.d.ts.map +1 -1
- package/dist/runner/runCollection.js +60 -7
- package/dist/runner/runCollection.js.map +1 -1
- package/dist/runner/runRequestWithDataset.d.ts.map +1 -1
- package/dist/runner/runRequestWithDataset.js +5 -0
- package/dist/runner/runRequestWithDataset.js.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.js +7 -0
- package/dist/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist/scenario-runner/runScenario.d.ts.map +1 -1
- package/dist/scenario-runner/runScenario.js +4 -0
- package/dist/scenario-runner/runScenario.js.map +1 -1
- package/dist/scenario-runner/types.d.ts +11 -0
- package/dist/scenario-runner/types.d.ts.map +1 -1
- package/dist/script/chain.d.ts +56 -0
- package/dist/script/chain.d.ts.map +1 -0
- package/dist/script/chain.js +121 -0
- package/dist/script/chain.js.map +1 -0
- package/dist/script/errors.d.ts.map +1 -1
- package/dist/script/errors.js +6 -4
- package/dist/script/errors.js.map +1 -1
- package/dist/script/executor.d.ts.map +1 -1
- package/dist/script/executor.js +298 -64
- package/dist/script/executor.js.map +1 -1
- package/dist/script/features/collectionVariables.d.ts +4 -4
- package/dist/script/features/collectionVariables.d.ts.map +1 -1
- package/dist/script/features/collectionVariables.js +20 -11
- package/dist/script/features/collectionVariables.js.map +1 -1
- package/dist/script/features/environment.d.ts +4 -4
- package/dist/script/features/environment.d.ts.map +1 -1
- package/dist/script/features/environment.js +20 -11
- package/dist/script/features/environment.js.map +1 -1
- package/dist/script/features/feature-policy.d.ts +1 -1
- package/dist/script/features/feature-policy.d.ts.map +1 -1
- package/dist/script/features/feature-policy.js +2 -2
- package/dist/script/features/feature-policy.js.map +1 -1
- package/dist/script/features/info.d.ts.map +1 -1
- package/dist/script/features/info.js +6 -3
- package/dist/script/features/info.js.map +1 -1
- package/dist/script/features/iterationData.d.ts +12 -0
- package/dist/script/features/iterationData.d.ts.map +1 -0
- package/dist/script/features/iterationData.js +28 -0
- package/dist/script/features/iterationData.js.map +1 -0
- package/dist/script/features/legacyPostman.d.ts +14 -0
- package/dist/script/features/legacyPostman.d.ts.map +1 -0
- package/dist/script/features/legacyPostman.js +106 -0
- package/dist/script/features/legacyPostman.js.map +1 -0
- package/dist/script/features/log.d.ts +35 -8
- package/dist/script/features/log.d.ts.map +1 -1
- package/dist/script/features/log.js +343 -27
- package/dist/script/features/log.js.map +1 -1
- package/dist/script/features/tests.d.ts +7 -8
- package/dist/script/features/tests.d.ts.map +1 -1
- package/dist/script/features/tests.js +90 -64
- package/dist/script/features/tests.js.map +1 -1
- package/dist/script/features/timers.d.ts +7 -1
- package/dist/script/features/timers.d.ts.map +1 -1
- package/dist/script/features/timers.js +17 -5
- package/dist/script/features/timers.js.map +1 -1
- package/dist/script/features/variables.d.ts +25 -4
- package/dist/script/features/variables.d.ts.map +1 -1
- package/dist/script/features/variables.js +26 -9
- package/dist/script/features/variables.js.map +1 -1
- package/dist/script/features/visualizer.d.ts +15 -0
- package/dist/script/features/visualizer.d.ts.map +1 -0
- package/dist/script/features/visualizer.js +52 -0
- package/dist/script/features/visualizer.js.map +1 -0
- package/dist/script/isolated-runner.d.ts +4 -1
- package/dist/script/isolated-runner.d.ts.map +1 -1
- package/dist/script/isolated-runner.js +26 -2
- package/dist/script/isolated-runner.js.map +1 -1
- package/dist/script/layers.d.ts +46 -0
- package/dist/script/layers.d.ts.map +1 -0
- package/dist/script/layers.js +52 -0
- package/dist/script/layers.js.map +1 -0
- package/dist/script/legacy.d.ts +6 -1
- package/dist/script/legacy.d.ts.map +1 -1
- package/dist/script/legacy.js +15 -5
- package/dist/script/legacy.js.map +1 -1
- package/dist/script/pm-api-declarations.d.ts +45 -0
- package/dist/script/pm-api-declarations.d.ts.map +1 -0
- package/dist/script/pm-api-declarations.js +1963 -0
- package/dist/script/pm-api-declarations.js.map +1 -0
- package/dist/script/pm-api-metadata.d.ts +3 -1
- package/dist/script/pm-api-metadata.d.ts.map +1 -1
- package/dist/script/pm-api-metadata.js +336 -106
- package/dist/script/pm-api-metadata.js.map +1 -1
- package/dist/script/pm-api-reference.d.ts.map +1 -1
- package/dist/script/pm-api-reference.js +32 -7
- package/dist/script/pm-api-reference.js.map +1 -1
- package/dist/script/postman/chaiCompat.d.ts +4 -0
- package/dist/script/postman/chaiCompat.d.ts.map +1 -0
- package/dist/script/postman/chaiCompat.js +176 -0
- package/dist/script/postman/chaiCompat.js.map +1 -0
- package/dist/script/postman/cookies.d.ts +36 -0
- package/dist/script/postman/cookies.d.ts.map +1 -0
- package/dist/script/postman/cookies.js +163 -0
- package/dist/script/postman/cookies.js.map +1 -0
- package/dist/script/postman/modules.d.ts +16 -0
- package/dist/script/postman/modules.d.ts.map +1 -0
- package/dist/script/postman/modules.js +114 -0
- package/dist/script/postman/modules.js.map +1 -0
- package/dist/script/postman/proxies.d.ts +13 -0
- package/dist/script/postman/proxies.d.ts.map +1 -0
- package/dist/script/postman/proxies.js +88 -0
- package/dist/script/postman/proxies.js.map +1 -0
- package/dist/script/postman/requestAdapter.d.ts +7 -0
- package/dist/script/postman/requestAdapter.d.ts.map +1 -0
- package/dist/script/postman/requestAdapter.js +223 -0
- package/dist/script/postman/requestAdapter.js.map +1 -0
- package/dist/script/postman/responseAdapter.d.ts +5 -0
- package/dist/script/postman/responseAdapter.d.ts.map +1 -0
- package/dist/script/postman/responseAdapter.js +78 -0
- package/dist/script/postman/responseAdapter.js.map +1 -0
- package/dist/script/postman/runtime.d.ts +22 -0
- package/dist/script/postman/runtime.d.ts.map +1 -0
- package/dist/script/postman/runtime.js +122 -0
- package/dist/script/postman/runtime.js.map +1 -0
- package/dist/script/scope.d.ts +5 -1
- package/dist/script/scope.d.ts.map +1 -1
- package/dist/script/scope.js +47 -5
- package/dist/script/scope.js.map +1 -1
- package/dist/script/types.d.ts +42 -14
- package/dist/script/types.d.ts.map +1 -1
- package/dist/script/worker-entry.js +9 -0
- package/dist/script/worker-entry.js.map +1 -1
- package/dist/script/worker-pool.d.ts +3 -1
- package/dist/script/worker-pool.d.ts.map +1 -1
- package/dist/script/worker-pool.js +23 -2
- package/dist/script/worker-pool.js.map +1 -1
- package/dist/templating/generator-metadata.d.ts +1 -0
- package/dist/templating/generator-metadata.d.ts.map +1 -1
- package/dist/templating/generator-metadata.js +14 -0
- package/dist/templating/generator-metadata.js.map +1 -1
- package/dist/templating/postman-dynamic-catalog.d.ts +7 -0
- package/dist/templating/postman-dynamic-catalog.d.ts.map +1 -0
- package/dist/templating/postman-dynamic-catalog.js +126 -0
- package/dist/templating/postman-dynamic-catalog.js.map +1 -0
- package/dist/templating/postman-generators.d.ts +9 -0
- package/dist/templating/postman-generators.d.ts.map +1 -1
- package/dist/templating/postman-generators.js +10 -1
- package/dist/templating/postman-generators.js.map +1 -1
- package/dist/types/index.d.ts +44 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/variables/envStore.d.ts +3 -0
- package/dist/variables/envStore.d.ts.map +1 -1
- package/dist/variables/envStore.js +5 -0
- package/dist/variables/envStore.js.map +1 -1
- package/dist/variables/replaceIn.d.ts +10 -0
- package/dist/variables/replaceIn.d.ts.map +1 -0
- package/dist/variables/replaceIn.js +106 -0
- package/dist/variables/replaceIn.js.map +1 -0
- package/dist/variables/resolver.d.ts.map +1 -1
- package/dist/variables/resolver.js +16 -2
- package/dist/variables/resolver.js.map +1 -1
- package/dist-cjs/ai/prompts/fragments.js +0 -1
- package/dist-cjs/ai/prompts/fragments.js.map +1 -1
- package/dist-cjs/ai/prompts/unified.js +1 -1
- package/dist-cjs/ai/prompts/unified.js.map +1 -1
- package/dist-cjs/ai/types.js +1 -1
- package/dist-cjs/ai/types.js.map +1 -1
- package/dist-cjs/index.js +23 -5
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/runner/requestRunner.js +339 -1
- package/dist-cjs/runner/requestRunner.js.map +1 -1
- package/dist-cjs/runner/runCollection.js +60 -7
- package/dist-cjs/runner/runCollection.js.map +1 -1
- package/dist-cjs/runner/runRequestWithDataset.js +5 -0
- package/dist-cjs/runner/runRequestWithDataset.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/request-executor.js +7 -0
- package/dist-cjs/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist-cjs/scenario-runner/runScenario.js +4 -0
- package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
- package/dist-cjs/script/chain.js +126 -0
- package/dist-cjs/script/chain.js.map +1 -0
- package/dist-cjs/script/errors.js +6 -4
- package/dist-cjs/script/errors.js.map +1 -1
- package/dist-cjs/script/executor.js +298 -64
- package/dist-cjs/script/executor.js.map +1 -1
- package/dist-cjs/script/features/collectionVariables.js +20 -11
- package/dist-cjs/script/features/collectionVariables.js.map +1 -1
- package/dist-cjs/script/features/environment.js +20 -11
- package/dist-cjs/script/features/environment.js.map +1 -1
- package/dist-cjs/script/features/feature-policy.js +2 -2
- package/dist-cjs/script/features/feature-policy.js.map +1 -1
- package/dist-cjs/script/features/info.js +6 -3
- package/dist-cjs/script/features/info.js.map +1 -1
- package/dist-cjs/script/features/iterationData.js +32 -0
- package/dist-cjs/script/features/iterationData.js.map +1 -0
- package/dist-cjs/script/features/legacyPostman.js +112 -0
- package/dist-cjs/script/features/legacyPostman.js.map +1 -0
- package/dist-cjs/script/features/log.js +347 -28
- package/dist-cjs/script/features/log.js.map +1 -1
- package/dist-cjs/script/features/tests.js +90 -64
- package/dist-cjs/script/features/tests.js.map +1 -1
- package/dist-cjs/script/features/timers.js +17 -5
- package/dist-cjs/script/features/timers.js.map +1 -1
- package/dist-cjs/script/features/variables.js +26 -9
- package/dist-cjs/script/features/variables.js.map +1 -1
- package/dist-cjs/script/features/visualizer.js +56 -0
- package/dist-cjs/script/features/visualizer.js.map +1 -0
- package/dist-cjs/script/isolated-runner.js +26 -2
- package/dist-cjs/script/isolated-runner.js.map +1 -1
- package/dist-cjs/script/layers.js +57 -0
- package/dist-cjs/script/layers.js.map +1 -0
- package/dist-cjs/script/legacy.js +20 -6
- package/dist-cjs/script/legacy.js.map +1 -1
- package/dist-cjs/script/pm-api-declarations.js +1969 -0
- package/dist-cjs/script/pm-api-declarations.js.map +1 -0
- package/dist-cjs/script/pm-api-metadata.js +336 -106
- package/dist-cjs/script/pm-api-metadata.js.map +1 -1
- package/dist-cjs/script/pm-api-reference.js +32 -7
- package/dist-cjs/script/pm-api-reference.js.map +1 -1
- package/dist-cjs/script/postman/chaiCompat.js +181 -0
- package/dist-cjs/script/postman/chaiCompat.js.map +1 -0
- package/dist-cjs/script/postman/cookies.js +170 -0
- package/dist-cjs/script/postman/cookies.js.map +1 -0
- package/dist-cjs/script/postman/modules.js +123 -0
- package/dist-cjs/script/postman/modules.js.map +1 -0
- package/dist-cjs/script/postman/proxies.js +93 -0
- package/dist-cjs/script/postman/proxies.js.map +1 -0
- package/dist-cjs/script/postman/requestAdapter.js +227 -0
- package/dist-cjs/script/postman/requestAdapter.js.map +1 -0
- package/dist-cjs/script/postman/responseAdapter.js +83 -0
- package/dist-cjs/script/postman/responseAdapter.js.map +1 -0
- package/dist-cjs/script/postman/runtime.js +132 -0
- package/dist-cjs/script/postman/runtime.js.map +1 -0
- package/dist-cjs/script/scope.js +47 -5
- package/dist-cjs/script/scope.js.map +1 -1
- package/dist-cjs/script/worker-entry.js +9 -0
- package/dist-cjs/script/worker-entry.js.map +1 -1
- package/dist-cjs/script/worker-pool.js +23 -2
- package/dist-cjs/script/worker-pool.js.map +1 -1
- package/dist-cjs/templating/generator-metadata.js +15 -1
- package/dist-cjs/templating/generator-metadata.js.map +1 -1
- package/dist-cjs/templating/postman-dynamic-catalog.js +129 -0
- package/dist-cjs/templating/postman-dynamic-catalog.js.map +1 -0
- package/dist-cjs/templating/postman-generators.js +13 -3
- package/dist-cjs/templating/postman-generators.js.map +1 -1
- package/dist-cjs/variables/envStore.js +5 -0
- package/dist-cjs/variables/envStore.js.map +1 -1
- package/dist-cjs/variables/replaceIn.js +111 -0
- package/dist-cjs/variables/replaceIn.js.map +1 -0
- package/dist-cjs/variables/resolver.js +16 -2
- package/dist-cjs/variables/resolver.js.map +1 -1
- package/package.json +12 -2
package/dist/script/executor.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Composes:
|
|
5
5
|
// - sandbox (vm.createContext + scope Proxy + reserved globals)
|
|
6
6
|
// - pm API (assertions + tests + env/globals + request/response + node + log)
|
|
7
|
-
// - sandbox-D extensions (db,
|
|
7
|
+
// - sandbox-D extensions (db, redis, random, counter, cryptojs, variables)
|
|
8
8
|
// - timeout (vm-level + outer Promise race)
|
|
9
9
|
// - error serialization (line/column attribution)
|
|
10
10
|
//
|
|
@@ -13,13 +13,19 @@
|
|
|
13
13
|
// distinguish "the sandbox itself blew up" should check `success === false`.
|
|
14
14
|
import { executeRequest } from "../request/executeRequest.js";
|
|
15
15
|
import { buildEnvironmentApi } from "./features/environment.js";
|
|
16
|
-
import {
|
|
16
|
+
import { splitSetCookieHeader } from "./legacy.js";
|
|
17
|
+
import { buildLegacyGlobals, scriptOptsOutOfLegacy } from "./features/legacyPostman.js";
|
|
18
|
+
import { createSandboxRequire, preloadScriptModules } from "./postman/modules.js";
|
|
19
|
+
import { buildPmCookies, createMemoryCookieJar, parseSetCookieLine } from "./postman/cookies.js";
|
|
20
|
+
import { buildVisualizerFeature } from "./features/visualizer.js";
|
|
21
|
+
import { buildSdkRequestApi } from "./postman/requestAdapter.js";
|
|
22
|
+
import { attachRequestAssertions, buildSdkResponseApi } from "./postman/responseAdapter.js";
|
|
23
|
+
import { loadPostmanRuntime, scriptNeedsSdk } from "./postman/runtime.js";
|
|
17
24
|
import { buildLabelGlobals, buildNodeApi } from "./features/node.js";
|
|
18
25
|
import { buildRequestApi } from "./features/request.js";
|
|
19
26
|
import { buildResponseApi } from "./features/response.js";
|
|
20
27
|
import { buildTestCollector } from "./features/tests.js";
|
|
21
28
|
import { createLogCollector, createSilentLogCollector, } from "./features/log.js";
|
|
22
|
-
import { buildKafkaApi } from "./features/kafka.js";
|
|
23
29
|
import { buildRedisApi } from "./features/redis.js";
|
|
24
30
|
import { buildRandomApi } from "./features/random.js";
|
|
25
31
|
import { buildCounterFeature } from "./features/counter.js";
|
|
@@ -28,6 +34,7 @@ import { buildVariablesApi } from "./features/variables.js";
|
|
|
28
34
|
import { buildDbApi } from "./features/db.js";
|
|
29
35
|
import { buildTimerFeature } from "./features/timers.js";
|
|
30
36
|
import { buildCollectionVariablesApi } from "./features/collectionVariables.js";
|
|
37
|
+
import { buildIterationDataApi } from "./features/iterationData.js";
|
|
31
38
|
import { buildInfoApi } from "./features/info.js";
|
|
32
39
|
import { buildExecutionFeature } from "./features/execution.js";
|
|
33
40
|
// Lodash is exposed unconditionally as the `_` global — Postman
|
|
@@ -40,26 +47,13 @@ import { toHostPromise, withAsyncTimeout } from "./timeout.js";
|
|
|
40
47
|
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
41
48
|
const DEFAULT_FILENAME = "callman-script.js";
|
|
42
49
|
const DEFAULT_STAGE = "script";
|
|
43
|
-
const buildSandboxDFeatures = (capabilities, isInsideTestCallback, envValues, globalValues, responseTemplateRoot) => {
|
|
50
|
+
const buildSandboxDFeatures = (capabilities, isInsideTestCallback, envValues, globalValues, responseTemplateRoot, collectionValues, live) => {
|
|
44
51
|
const extensions = capabilities.extensions ?? {};
|
|
45
52
|
const featurePolicy = capabilities.featurePolicy;
|
|
46
53
|
const pm = {};
|
|
47
54
|
const scopeShortcuts = {};
|
|
48
55
|
let counterSnapshotFn = null;
|
|
49
|
-
|
|
50
|
-
const kafkaEnabled = featurePolicy ? featurePolicy.kafka : true;
|
|
51
|
-
if (kafkaEnabled) {
|
|
52
|
-
const api = buildKafkaApi(extensions.kafka, capabilities.allowDeferredKafkaTests ?? false);
|
|
53
|
-
pm.kafka = api;
|
|
54
|
-
scopeShortcuts.kafka = api;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
// Disabled kafka — replace with feature-policy guarded value
|
|
58
|
-
// (handled at the test-collector level via DisabledFeatureDependencyError).
|
|
59
|
-
// We still expose the binding so user scripts don't crash at scope lookup.
|
|
60
|
-
void isInsideTestCallback;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
56
|
+
let variablesApi = null;
|
|
63
57
|
if (extensions.redis) {
|
|
64
58
|
const api = buildRedisApi({
|
|
65
59
|
capability: extensions.redis,
|
|
@@ -99,8 +93,16 @@ const buildSandboxDFeatures = (capabilities, isInsideTestCallback, envValues, gl
|
|
|
99
93
|
// (top-level `variables` identifier) is only registered when the
|
|
100
94
|
// extension was explicitly requested, to preserve the prior surface.
|
|
101
95
|
{
|
|
102
|
-
const api = buildVariablesApi(envValues, globalValues
|
|
96
|
+
const api = buildVariablesApi(envValues, globalValues, {
|
|
97
|
+
collectionVariables: collectionValues,
|
|
98
|
+
...(live ? { live } : {}),
|
|
99
|
+
...(capabilities.iterationData ? { iterationData: capabilities.iterationData.values } : {}),
|
|
100
|
+
...(capabilities.localVariables ? { local: capabilities.localVariables.values } : {}),
|
|
101
|
+
});
|
|
103
102
|
pm.variables = api;
|
|
103
|
+
// Postman exposes pm.iterationData in every script (empty outside a data run).
|
|
104
|
+
pm.iterationData = buildIterationDataApi(capabilities.iterationData?.values);
|
|
105
|
+
variablesApi = api;
|
|
104
106
|
if (extensions.variables) {
|
|
105
107
|
scopeShortcuts.variables = api;
|
|
106
108
|
}
|
|
@@ -118,7 +120,7 @@ const buildSandboxDFeatures = (capabilities, isInsideTestCallback, envValues, gl
|
|
|
118
120
|
pm.db = api;
|
|
119
121
|
scopeShortcuts.db = api;
|
|
120
122
|
}
|
|
121
|
-
return { pm, scopeShortcuts, counterSnapshotFn };
|
|
123
|
+
return { pm, scopeShortcuts, counterSnapshotFn, variablesApi: variablesApi };
|
|
122
124
|
};
|
|
123
125
|
const buildSendRequestPendingTracker = () => {
|
|
124
126
|
const pending = [];
|
|
@@ -192,7 +194,16 @@ const normalizeSendBody = (body) => {
|
|
|
192
194
|
if (isPlainRecord(body)) {
|
|
193
195
|
const mode = body.mode;
|
|
194
196
|
if (mode === "raw") {
|
|
195
|
-
|
|
197
|
+
// Postman picks the Content-Type from the raw language (Text → text/plain);
|
|
198
|
+
// without one axios would label a string body as form-urlencoded.
|
|
199
|
+
const language = String(body.options?.raw?.language ?? "text").toLowerCase();
|
|
200
|
+
const byLanguage = {
|
|
201
|
+
json: "application/json",
|
|
202
|
+
xml: "application/xml",
|
|
203
|
+
html: "text/html",
|
|
204
|
+
javascript: "application/javascript",
|
|
205
|
+
};
|
|
206
|
+
return { data: body.raw ?? "", impliedContentType: byLanguage[language] ?? "text/plain" };
|
|
196
207
|
}
|
|
197
208
|
if (mode === "urlencoded" && Array.isArray(body.urlencoded)) {
|
|
198
209
|
const params = new URLSearchParams();
|
|
@@ -249,7 +260,33 @@ const resolveSendTemplates = (value, resolve) => {
|
|
|
249
260
|
}
|
|
250
261
|
return value;
|
|
251
262
|
};
|
|
252
|
-
const
|
|
263
|
+
const MULTIPART_BOUNDARY_PREFIX = "----CallmanFormBoundary";
|
|
264
|
+
// Multipart is built as a STRING body so every host executor (axios, the
|
|
265
|
+
// desktop's engine over worker RPC) sends it the same way. Text parts only —
|
|
266
|
+
// a file part has no bytes to read inside the sandbox.
|
|
267
|
+
const buildMultipartBody = (entries) => {
|
|
268
|
+
const boundary = `${MULTIPART_BOUNDARY_PREFIX}${Math.random().toString(16).slice(2)}${Date.now().toString(16)}`;
|
|
269
|
+
const parts = [];
|
|
270
|
+
for (const entry of entries) {
|
|
271
|
+
if (entry.disabled === true)
|
|
272
|
+
continue;
|
|
273
|
+
const key = String(entry.key ?? "").trim();
|
|
274
|
+
if (!key)
|
|
275
|
+
continue;
|
|
276
|
+
if (entry.type === "file") {
|
|
277
|
+
throw new Error(`pm.sendRequest: file part "${key}" is not supported (the sandbox cannot read files).`);
|
|
278
|
+
}
|
|
279
|
+
parts.push(`--${boundary}\r\nContent-Disposition: form-data; name="${key.replace(/"/g, "%22")}"\r\n\r\n${String(entry.value ?? "")}\r\n`);
|
|
280
|
+
}
|
|
281
|
+
return { data: `${parts.join("")}--${boundary}--\r\n`, contentType: `multipart/form-data; boundary=${boundary}` };
|
|
282
|
+
};
|
|
283
|
+
const setCookieLines = (headers) => {
|
|
284
|
+
const raw = Object.entries(headers).find(([key]) => key.toLowerCase() === "set-cookie")?.[1];
|
|
285
|
+
if (raw === undefined || raw === null)
|
|
286
|
+
return [];
|
|
287
|
+
return Array.isArray(raw) ? raw.map(String) : String(raw).split(/\r?\n/);
|
|
288
|
+
};
|
|
289
|
+
const createPmSendRequest = (tracker, executor, resolveTemplate, context = { sdk: null, chai: null }) => {
|
|
253
290
|
// Host-injected executor (desktop's real engine) takes precedence; backend
|
|
254
291
|
// and CLI omit it and fall back to the built-in bare-axios client.
|
|
255
292
|
const run = executor ?? executeRequest;
|
|
@@ -258,20 +295,60 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
258
295
|
// pm.environment.set writes made earlier in this script). No resolver
|
|
259
296
|
// wired → identity passthrough so behaviour is unchanged.
|
|
260
297
|
const resolve = resolveTemplate ?? ((template) => template);
|
|
298
|
+
const { sdk, chai, jar } = context;
|
|
299
|
+
// Request objects (sdk.Request) and the Url/HeaderList inside them become the
|
|
300
|
+
// plain definition the rest of this function understands.
|
|
301
|
+
const toDefinition = (options) => {
|
|
302
|
+
if (typeof options === "string")
|
|
303
|
+
return { url: options, method: "GET" };
|
|
304
|
+
if (sdk && options && typeof options === "object" && sdk.Request.isRequest(options)) {
|
|
305
|
+
return options.toJSON();
|
|
306
|
+
}
|
|
307
|
+
return isPlainRecord(options) ? options : {};
|
|
308
|
+
};
|
|
309
|
+
const urlFrom = (input) => {
|
|
310
|
+
if (sdk && input && typeof input === "object" && !Array.isArray(input) && !("raw" in input) && "host" in input) {
|
|
311
|
+
return new sdk.Url(input).toString();
|
|
312
|
+
}
|
|
313
|
+
return normalizeSendUrl(input);
|
|
314
|
+
};
|
|
261
315
|
return (options, callback) => {
|
|
262
316
|
const promise = (async () => {
|
|
263
|
-
const rawOptions =
|
|
264
|
-
? { url: options, method: "GET" }
|
|
265
|
-
: isPlainRecord(options)
|
|
266
|
-
? options
|
|
267
|
-
: {};
|
|
317
|
+
const rawOptions = toDefinition(options);
|
|
268
318
|
// Resolve templates up-front against the live scope, then normalize.
|
|
269
319
|
const normalized = resolveSendTemplates(rawOptions, resolve);
|
|
270
|
-
const url =
|
|
320
|
+
const url = urlFrom(normalized.url);
|
|
271
321
|
const method = String(normalized.method ?? "GET").toUpperCase();
|
|
272
322
|
const headerInput = normalized.header ?? normalized.headers;
|
|
273
323
|
const headers = normalizeSendHeaderInput(headerInput);
|
|
274
|
-
const
|
|
324
|
+
const body = normalized.body;
|
|
325
|
+
let data;
|
|
326
|
+
let impliedContentType = null;
|
|
327
|
+
if (isPlainRecord(body) && body.mode === "formdata" && Array.isArray(body.formdata)) {
|
|
328
|
+
const multipart = buildMultipartBody(body.formdata);
|
|
329
|
+
data = multipart.data;
|
|
330
|
+
impliedContentType = multipart.contentType;
|
|
331
|
+
}
|
|
332
|
+
else if (isPlainRecord(body) && body.mode === "graphql" && isPlainRecord(body.graphql)) {
|
|
333
|
+
const graphql = body.graphql;
|
|
334
|
+
let variables = graphql.variables;
|
|
335
|
+
if (typeof variables === "string" && variables.trim()) {
|
|
336
|
+
try {
|
|
337
|
+
variables = JSON.parse(variables);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// leave the text as the user wrote it
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
data = JSON.stringify({ query: graphql.query, ...(variables ? { variables } : {}) });
|
|
344
|
+
impliedContentType = "application/json";
|
|
345
|
+
}
|
|
346
|
+
else if (isPlainRecord(body) && body.mode === "file") {
|
|
347
|
+
throw new Error("pm.sendRequest: body mode \"file\" is not supported (the sandbox cannot read files).");
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
({ data, impliedContentType } = normalizeSendBody(body));
|
|
351
|
+
}
|
|
275
352
|
if (impliedContentType &&
|
|
276
353
|
!Object.keys(headers).some((k) => k.toLowerCase() === "content-type")) {
|
|
277
354
|
headers["Content-Type"] = impliedContentType;
|
|
@@ -279,6 +356,14 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
279
356
|
const timeoutMs = typeof normalized.timeout === "number" && normalized.timeout > 0
|
|
280
357
|
? Number(normalized.timeout)
|
|
281
358
|
: undefined;
|
|
359
|
+
// Hosts that provide a persistent cookie jar get Postman's behaviour:
|
|
360
|
+
// matching cookies are sent, Set-Cookie responses are stored.
|
|
361
|
+
if (jar && !Object.keys(headers).some((key) => key.toLowerCase() === "cookie")) {
|
|
362
|
+
const stored = await jar.getAll(url);
|
|
363
|
+
if (stored.length > 0) {
|
|
364
|
+
headers.Cookie = stored.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
|
|
365
|
+
}
|
|
366
|
+
}
|
|
282
367
|
const result = await run({
|
|
283
368
|
method,
|
|
284
369
|
url,
|
|
@@ -287,21 +372,47 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
287
372
|
body: data,
|
|
288
373
|
timeoutMs,
|
|
289
374
|
});
|
|
290
|
-
const bodyText = typeof result.
|
|
291
|
-
? result.
|
|
292
|
-
:
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
375
|
+
const bodyText = typeof result.rawText === "string"
|
|
376
|
+
? result.rawText
|
|
377
|
+
: typeof result.data === "string"
|
|
378
|
+
? result.data
|
|
379
|
+
: (() => {
|
|
380
|
+
try {
|
|
381
|
+
return JSON.stringify(result.data ?? null);
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return String(result.data ?? "");
|
|
385
|
+
}
|
|
386
|
+
})();
|
|
387
|
+
const responseHeaders = (result.headers ?? {});
|
|
388
|
+
const cookieLines = setCookieLines(responseHeaders);
|
|
389
|
+
if (jar) {
|
|
390
|
+
for (const line of cookieLines) {
|
|
391
|
+
const cookie = parseSetCookieLine(line);
|
|
392
|
+
if (cookie)
|
|
393
|
+
await jar.set(url, cookie);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (sdk && chai) {
|
|
397
|
+
return buildSdkResponseApi(sdk, chai, {
|
|
398
|
+
ok: result.status >= 200 && result.status < 400,
|
|
399
|
+
status: result.status,
|
|
400
|
+
statusText: "",
|
|
401
|
+
headers: responseHeaders,
|
|
402
|
+
body: result.data,
|
|
403
|
+
jsonBody: result.data !== null && typeof result.data === "object" ? result.data : null,
|
|
404
|
+
rawBody: bodyText,
|
|
405
|
+
contentType: Object.entries(responseHeaders).find(([key]) => key.toLowerCase() === "content-type")?.[1] ?? "",
|
|
406
|
+
durationMs: result.duration ?? 0,
|
|
407
|
+
sizeBytes: bodyText.length,
|
|
408
|
+
cookies: cookieLines,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
300
411
|
return {
|
|
301
412
|
code: result.status,
|
|
302
413
|
status: result.status,
|
|
303
414
|
statusText: "",
|
|
304
|
-
headers:
|
|
415
|
+
headers: responseHeaders,
|
|
305
416
|
body: result.data,
|
|
306
417
|
responseTime: result.duration,
|
|
307
418
|
duration: result.duration,
|
|
@@ -318,7 +429,7 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
318
429
|
if (typeof callback === "function") {
|
|
319
430
|
promise.then((response) => {
|
|
320
431
|
try {
|
|
321
|
-
callback(null, response);
|
|
432
|
+
callback(null, response, undefined);
|
|
322
433
|
}
|
|
323
434
|
catch (callbackError) {
|
|
324
435
|
// Surface callback throws to the host log; suppressing
|
|
@@ -328,7 +439,7 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
328
439
|
}
|
|
329
440
|
}, (error) => {
|
|
330
441
|
try {
|
|
331
|
-
callback(error instanceof Error ? error : new Error(String(error)), null);
|
|
442
|
+
callback(error instanceof Error ? error : new Error(String(error)), null, undefined);
|
|
332
443
|
}
|
|
333
444
|
catch (callbackError) {
|
|
334
445
|
// eslint-disable-next-line no-console
|
|
@@ -373,8 +484,12 @@ const buildPm = (capabilities, logs, collectors, sandboxDPm) => {
|
|
|
373
484
|
// interpolates {{var}} exactly like pm.variables.replaceIn(...).
|
|
374
485
|
const variablesApi = sandboxDPm.variables;
|
|
375
486
|
pm.sendRequest = createPmSendRequest(collectors.sendRequestTracker, capabilities.extensions?.sendRequest?.execute, variablesApi
|
|
376
|
-
? (template) => variablesApi.replaceIn(template)
|
|
377
|
-
: undefined
|
|
487
|
+
? (template) => String(variablesApi.replaceIn(template))
|
|
488
|
+
: undefined, {
|
|
489
|
+
sdk: collectors.runtime?.sdk ?? null,
|
|
490
|
+
chai: collectors.runtime?.chai ?? null,
|
|
491
|
+
jar: capabilities.cookies?.jar,
|
|
492
|
+
});
|
|
378
493
|
}
|
|
379
494
|
const extensions = capabilities.extensions ?? {};
|
|
380
495
|
if (extensions.log) {
|
|
@@ -388,7 +503,7 @@ const buildPm = (capabilities, logs, collectors, sandboxDPm) => {
|
|
|
388
503
|
}
|
|
389
504
|
return pm;
|
|
390
505
|
};
|
|
391
|
-
const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environmentApi, request, response, expect, test, sandboxDShortcuts, timers, }) => {
|
|
506
|
+
const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environmentApi, request, response, expect, test, sandboxDShortcuts, timers, extraGlobals, }) => {
|
|
392
507
|
const exposeLabels = capabilities.workflowContext &&
|
|
393
508
|
capabilities.exposeLabelsAsGlobals !== false;
|
|
394
509
|
const labelGlobals = exposeLabels
|
|
@@ -407,7 +522,6 @@ const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environme
|
|
|
407
522
|
expect,
|
|
408
523
|
console: consoleApi,
|
|
409
524
|
db: sandboxDShortcuts.db,
|
|
410
|
-
kafka: sandboxDShortcuts.kafka,
|
|
411
525
|
redis: sandboxDShortcuts.redis,
|
|
412
526
|
random: sandboxDShortcuts.random,
|
|
413
527
|
counter: sandboxDShortcuts.counter,
|
|
@@ -415,14 +529,26 @@ const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environme
|
|
|
415
529
|
CryptoJS: sandboxDShortcuts.CryptoJS,
|
|
416
530
|
lodash,
|
|
417
531
|
timers,
|
|
532
|
+
extraGlobals,
|
|
418
533
|
labelGlobals,
|
|
419
534
|
};
|
|
420
535
|
};
|
|
536
|
+
const NUMERIC_STATUS_COMPARISON = /(?:\b(?:pm|cm|callman)\.response\.status\s*(?:===?|!==?|<=?|>=?)\s*\d{3}\b)|(?:\b\d{3}\s*(?:===?|!==?|<=?|>=?)\s*(?:pm|cm|callman)\.response\.status\b)|(?:expect\(\s*(?:pm|cm|callman)\.response\.status\s*\)[^;\n]*\b\d{3}\b)/;
|
|
421
537
|
export const executeScript = async (input) => {
|
|
422
538
|
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
423
539
|
const filename = input.filename ?? DEFAULT_FILENAME;
|
|
424
540
|
const stage = input.stage ?? DEFAULT_STAGE;
|
|
425
|
-
|
|
541
|
+
// A host may hand over several Set-Cookie headers joined into one string
|
|
542
|
+
// ("a=1; Path=/, b=2; …"); split them so each cookie is its own entry.
|
|
543
|
+
const capabilities = input.capabilities.response?.cookies?.some((line) => /,\s*[^;,=\s]+=/.test(line))
|
|
544
|
+
? {
|
|
545
|
+
...input.capabilities,
|
|
546
|
+
response: {
|
|
547
|
+
...input.capabilities.response,
|
|
548
|
+
cookies: input.capabilities.response.cookies.flatMap(splitSetCookieHeader),
|
|
549
|
+
},
|
|
550
|
+
}
|
|
551
|
+
: input.capabilities;
|
|
426
552
|
const extensions = capabilities.extensions ?? {};
|
|
427
553
|
// Empty / whitespace-only scripts short-circuit with an empty success.
|
|
428
554
|
if (!input.script.trim()) {
|
|
@@ -437,8 +563,8 @@ export const executeScript = async (input) => {
|
|
|
437
563
|
if (extensions.counter) {
|
|
438
564
|
passthrough.counterSnapshot = extensions.counter.snapshot;
|
|
439
565
|
}
|
|
440
|
-
if (capabilities.
|
|
441
|
-
passthrough.
|
|
566
|
+
if (capabilities.localVariables) {
|
|
567
|
+
passthrough.localVariables = { ...capabilities.localVariables.values };
|
|
442
568
|
}
|
|
443
569
|
return passthrough;
|
|
444
570
|
}
|
|
@@ -462,23 +588,46 @@ export const executeScript = async (input) => {
|
|
|
462
588
|
: buildCollectionVariablesApi({}, null);
|
|
463
589
|
const infoApi = buildInfoApi(capabilities.info, stage);
|
|
464
590
|
const executionFeature = buildExecutionFeature(capabilities.execution);
|
|
591
|
+
// pm.request / pm.response are real `postman-collection` objects and pm.expect
|
|
592
|
+
// is chai: load them before the (synchronous) sandbox is assembled.
|
|
593
|
+
const runtime = await loadPostmanRuntime({
|
|
594
|
+
sdk: scriptNeedsSdk(input.script, Boolean(capabilities.request || capabilities.response)),
|
|
595
|
+
});
|
|
465
596
|
const requestBundle = capabilities.request
|
|
466
|
-
?
|
|
597
|
+
? runtime.sdk
|
|
598
|
+
? buildSdkRequestApi(runtime.sdk, capabilities.request)
|
|
599
|
+
: buildRequestApi(capabilities.request)
|
|
467
600
|
: undefined;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
601
|
+
if (requestBundle && runtime.sdk) {
|
|
602
|
+
attachRequestAssertions(runtime.chai, requestBundle.api);
|
|
603
|
+
}
|
|
604
|
+
const responseApi = capabilities.response
|
|
605
|
+
? runtime.sdk
|
|
606
|
+
? buildSdkResponseApi(runtime.sdk, runtime.chai, capabilities.response)
|
|
607
|
+
: (buildResponseApi(capabilities.response) ?? undefined)
|
|
608
|
+
: undefined;
|
|
609
|
+
const expect = runtime.chai.expect;
|
|
610
|
+
const tests = buildTestCollector(stage);
|
|
474
611
|
const logCollector = extensions.log
|
|
475
|
-
? createLogCollector()
|
|
612
|
+
? createLogCollector(typeof extensions.log === "object" ? { onEntry: extensions.log.onEntry } : {})
|
|
476
613
|
: createSilentLogCollector();
|
|
614
|
+
// `pm.response.status` is Postman's reason phrase ("OK"); scripts written
|
|
615
|
+
// against Callman's old numeric status silently stop matching. Say so once.
|
|
616
|
+
if (extensions.log && NUMERIC_STATUS_COMPARISON.test(input.script)) {
|
|
617
|
+
logCollector.consoleApi.warn('pm.response.status is the reason phrase (e.g. "OK") like in Postman — compare pm.response.code for the numeric status.');
|
|
618
|
+
}
|
|
477
619
|
// Sandbox D feature bundle — depends on env/globals being constructed first
|
|
478
620
|
// (cryptojs/random/counter don't, but variables/db do).
|
|
479
|
-
const sandboxD = buildSandboxDFeatures(capabilities, () => tests.isInsideCallback(), environmentApi?.values ?? capabilities.environment?.values ?? {}, globalsApi?.values ?? capabilities.globals?.values ?? {}, capabilities.response ?? null
|
|
621
|
+
const sandboxD = buildSandboxDFeatures(capabilities, () => tests.isInsideCallback(), environmentApi?.values ?? capabilities.environment?.values ?? {}, globalsApi?.values ?? capabilities.globals?.values ?? {}, capabilities.response ?? null, collectionVariablesApi.values, {
|
|
622
|
+
...(environmentApi ? { environment: () => environmentApi.toObject() } : {}),
|
|
623
|
+
...(globalsApi ? { globals: () => globalsApi.toObject() } : {}),
|
|
624
|
+
collection: () => collectionVariablesApi.toObject(),
|
|
625
|
+
});
|
|
480
626
|
const sendRequestTracker = buildSendRequestPendingTracker();
|
|
481
|
-
const timerFeature = buildTimerFeature()
|
|
627
|
+
const timerFeature = buildTimerFeature((kind, error) => {
|
|
628
|
+
const detail = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
629
|
+
logCollector.consoleApi.error(`Uncaught error in ${kind === "timeout" ? "setTimeout" : "setInterval"} callback: ${detail}`);
|
|
630
|
+
});
|
|
482
631
|
const pm = buildPm(capabilities, { pmLog: logCollector.pmLog }, {
|
|
483
632
|
test: tests,
|
|
484
633
|
expect,
|
|
@@ -490,9 +639,88 @@ export const executeScript = async (input) => {
|
|
|
490
639
|
request: requestBundle,
|
|
491
640
|
response: responseApi ?? undefined,
|
|
492
641
|
sendRequestTracker,
|
|
642
|
+
runtime,
|
|
493
643
|
}, sandboxD.pm);
|
|
644
|
+
// Postman APIs Callman does not implement: fail with an explanation instead
|
|
645
|
+
// of "Cannot read properties of undefined".
|
|
646
|
+
const unsupportedApi = (name) => new Proxy(function unsupported() {
|
|
647
|
+
return undefined;
|
|
648
|
+
}, {
|
|
649
|
+
get: (_target, property) => {
|
|
650
|
+
if (property === Symbol.toPrimitive || property === "then" || property === "toJSON")
|
|
651
|
+
return undefined;
|
|
652
|
+
throw new Error(`${name} is not supported in Callman yet.`);
|
|
653
|
+
},
|
|
654
|
+
apply: () => {
|
|
655
|
+
throw new Error(`${name} is not supported in Callman yet.`);
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
for (const name of ["vault", "datasets", "mock", "state", "message"]) {
|
|
659
|
+
if (!(name in pm))
|
|
660
|
+
pm[name] = unsupportedApi(`pm.${name}`);
|
|
661
|
+
}
|
|
662
|
+
if (pm.execution && typeof pm.execution === "object" && !("runRequest" in pm.execution)) {
|
|
663
|
+
pm.execution.runRequest = async () => {
|
|
664
|
+
throw new Error("pm.execution.runRequest is not supported in Callman yet.");
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const visualizerFeature = buildVisualizerFeature();
|
|
668
|
+
pm.visualizer = visualizerFeature.api;
|
|
669
|
+
pm.getData = visualizerFeature.getData;
|
|
670
|
+
// pm.cookies (CookieList of the request's domain) + pm.cookies.jar().
|
|
671
|
+
pm.cookies = buildPmCookies({
|
|
672
|
+
sdk: runtime.sdk,
|
|
673
|
+
lines: capabilities.cookies?.snapshot ?? capabilities.response?.cookies ?? [],
|
|
674
|
+
jar: capabilities.cookies?.jar ?? createMemoryCookieJar(),
|
|
675
|
+
});
|
|
676
|
+
// require() / pm.require() and Postman's legacy globals (postman.*, tests[],
|
|
677
|
+
// responseBody…). Modules are loaded up front: the sandbox itself is sync.
|
|
678
|
+
const optsOutOfLegacy = scriptOptsOutOfLegacy(input.script);
|
|
679
|
+
const legacyEnabled = !optsOutOfLegacy && stage !== "script";
|
|
680
|
+
const legacyLibraries = legacyEnabled
|
|
681
|
+
? ["tv4", "cheerio"].filter((name) => new RegExp(`\\b${name}\\b`).test(input.script))
|
|
682
|
+
: [];
|
|
683
|
+
const wantsXml2Json = legacyEnabled && /\bxml2Json\b/.test(input.script);
|
|
684
|
+
const loadedModules = await preloadScriptModules([
|
|
685
|
+
input.script,
|
|
686
|
+
...legacyLibraries.map((name) => `require("${name}")`),
|
|
687
|
+
...(wantsXml2Json ? [`require("xml2js")`] : []),
|
|
688
|
+
].join("\n"), {
|
|
689
|
+
sdk: runtime.sdk,
|
|
690
|
+
chai: runtime.chai,
|
|
691
|
+
cryptoJs: sandboxD.scopeShortcuts.CryptoJS,
|
|
692
|
+
timers: timerFeature.api,
|
|
693
|
+
});
|
|
694
|
+
pm.require = createSandboxRequire(loadedModules, "pm.require");
|
|
695
|
+
const extraGlobals = {
|
|
696
|
+
require: createSandboxRequire(loadedModules),
|
|
697
|
+
};
|
|
698
|
+
if (legacyEnabled) {
|
|
699
|
+
Object.assign(extraGlobals, buildLegacyGlobals({
|
|
700
|
+
pm,
|
|
701
|
+
environmentApi,
|
|
702
|
+
globalsApi,
|
|
703
|
+
response: capabilities.response ?? null,
|
|
704
|
+
testFn: tests.test,
|
|
705
|
+
iterationDataValues: capabilities.iterationData?.values ?? {},
|
|
706
|
+
}));
|
|
707
|
+
for (const name of legacyLibraries) {
|
|
708
|
+
extraGlobals[name] = loadedModules.get(name);
|
|
709
|
+
}
|
|
710
|
+
if (wantsXml2Json) {
|
|
711
|
+
const xml2js = loadedModules.get("xml2js");
|
|
712
|
+
extraGlobals.xml2Json = (xml) => {
|
|
713
|
+
let out;
|
|
714
|
+
xml2js?.parseString(String(xml ?? ""), { explicitArray: false, async: false }, (_error, result) => {
|
|
715
|
+
out = result;
|
|
716
|
+
});
|
|
717
|
+
return out;
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
}
|
|
494
721
|
const bindings = buildScopeBindings({
|
|
495
722
|
pm,
|
|
723
|
+
extraGlobals,
|
|
496
724
|
capabilities,
|
|
497
725
|
consoleApi: logCollector.consoleApi,
|
|
498
726
|
envValues: environmentApi?.values,
|
|
@@ -507,6 +735,8 @@ export const executeScript = async (input) => {
|
|
|
507
735
|
clearTimeout: timerFeature.api.clearTimeout,
|
|
508
736
|
setInterval: timerFeature.api.setInterval,
|
|
509
737
|
clearInterval: timerFeature.api.clearInterval,
|
|
738
|
+
setImmediate: timerFeature.api.setImmediate,
|
|
739
|
+
clearImmediate: timerFeature.api.clearImmediate,
|
|
510
740
|
},
|
|
511
741
|
});
|
|
512
742
|
let compiled;
|
|
@@ -529,8 +759,8 @@ export const executeScript = async (input) => {
|
|
|
529
759
|
if (sandboxD.counterSnapshotFn) {
|
|
530
760
|
result.counterSnapshot = sandboxD.counterSnapshotFn();
|
|
531
761
|
}
|
|
532
|
-
if (capabilities.
|
|
533
|
-
result.
|
|
762
|
+
if (capabilities.localVariables) {
|
|
763
|
+
result.localVariables = { ...capabilities.localVariables.values };
|
|
534
764
|
}
|
|
535
765
|
return result;
|
|
536
766
|
}
|
|
@@ -574,15 +804,19 @@ export const executeScript = async (input) => {
|
|
|
574
804
|
if (sandboxD.counterSnapshotFn) {
|
|
575
805
|
result.counterSnapshot = sandboxD.counterSnapshotFn();
|
|
576
806
|
}
|
|
577
|
-
if (capabilities.allowDeferredKafkaTests) {
|
|
578
|
-
result.deferredTestNames = [...tests.deferredTestNames];
|
|
579
|
-
}
|
|
580
807
|
// Only surface executionControl when the host actually wired the
|
|
581
808
|
// capability — keeps the result shape unchanged for callers that
|
|
582
809
|
// don't know about pm.execution yet.
|
|
583
810
|
if (capabilities.execution) {
|
|
584
811
|
result.executionControl = executionFeature.getControl();
|
|
585
812
|
}
|
|
813
|
+
if (capabilities.localVariables) {
|
|
814
|
+
result.localVariables = sandboxD.variablesApi.localSnapshot?.() ?? {};
|
|
815
|
+
}
|
|
816
|
+
const visualization = visualizerFeature.payload();
|
|
817
|
+
if (visualization) {
|
|
818
|
+
result.visualizer = visualization;
|
|
819
|
+
}
|
|
586
820
|
return result;
|
|
587
821
|
};
|
|
588
822
|
// Standalone parse-only check — exposed so the desktop's
|