callman-core 1.35.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 +238 -98
- 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 +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/runner/requestRunner.d.ts.map +1 -1
- package/dist/runner/requestRunner.js +33 -0
- package/dist/runner/requestRunner.js.map +1 -1
- package/dist/runner/runCollection.d.ts.map +1 -1
- package/dist/runner/runCollection.js +46 -9
- package/dist/runner/runCollection.js.map +1 -1
- package/dist/runner/runRequestWithDataset.d.ts.map +1 -1
- package/dist/runner/runRequestWithDataset.js +3 -2
- 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 +2 -0
- package/dist/script/chain.d.ts.map +1 -1
- package/dist/script/chain.js +2 -0
- package/dist/script/chain.js.map +1 -1
- package/dist/script/errors.js +6 -6
- package/dist/script/errors.js.map +1 -1
- package/dist/script/executor.d.ts.map +1 -1
- package/dist/script/executor.js +284 -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 +19 -4
- package/dist/script/features/variables.d.ts.map +1 -1
- package/dist/script/features/variables.js +22 -6
- 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/legacy.d.ts +1 -0
- package/dist/script/legacy.d.ts.map +1 -1
- package/dist/script/legacy.js +12 -2
- 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 +24 -8
- 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 +33 -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 +22 -1
- package/dist/types/index.d.ts.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-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 +17 -5
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/runner/requestRunner.js +33 -0
- package/dist-cjs/runner/requestRunner.js.map +1 -1
- package/dist-cjs/runner/runCollection.js +46 -9
- package/dist-cjs/runner/runCollection.js.map +1 -1
- package/dist-cjs/runner/runRequestWithDataset.js +3 -2
- 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 +2 -0
- package/dist-cjs/script/chain.js.map +1 -1
- package/dist-cjs/script/errors.js +6 -6
- package/dist-cjs/script/errors.js.map +1 -1
- package/dist-cjs/script/executor.js +284 -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 +22 -6
- 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/legacy.js +14 -3
- 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 +24 -8
- 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/replaceIn.js +111 -0
- package/dist-cjs/variables/replaceIn.js.map +1 -0
- 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,27 +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, collectionValues) => {
|
|
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
56
|
let variablesApi = null;
|
|
50
|
-
if (extensions.kafka) {
|
|
51
|
-
const kafkaEnabled = featurePolicy ? featurePolicy.kafka : true;
|
|
52
|
-
if (kafkaEnabled) {
|
|
53
|
-
const api = buildKafkaApi(extensions.kafka, capabilities.allowDeferredKafkaTests ?? false);
|
|
54
|
-
pm.kafka = api;
|
|
55
|
-
scopeShortcuts.kafka = api;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
// Disabled kafka — replace with feature-policy guarded value
|
|
59
|
-
// (handled at the test-collector level via DisabledFeatureDependencyError).
|
|
60
|
-
// We still expose the binding so user scripts don't crash at scope lookup.
|
|
61
|
-
void isInsideTestCallback;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
57
|
if (extensions.redis) {
|
|
65
58
|
const api = buildRedisApi({
|
|
66
59
|
capability: extensions.redis,
|
|
@@ -102,9 +95,13 @@ const buildSandboxDFeatures = (capabilities, isInsideTestCallback, envValues, gl
|
|
|
102
95
|
{
|
|
103
96
|
const api = buildVariablesApi(envValues, globalValues, {
|
|
104
97
|
collectionVariables: collectionValues,
|
|
98
|
+
...(live ? { live } : {}),
|
|
99
|
+
...(capabilities.iterationData ? { iterationData: capabilities.iterationData.values } : {}),
|
|
105
100
|
...(capabilities.localVariables ? { local: capabilities.localVariables.values } : {}),
|
|
106
101
|
});
|
|
107
102
|
pm.variables = api;
|
|
103
|
+
// Postman exposes pm.iterationData in every script (empty outside a data run).
|
|
104
|
+
pm.iterationData = buildIterationDataApi(capabilities.iterationData?.values);
|
|
108
105
|
variablesApi = api;
|
|
109
106
|
if (extensions.variables) {
|
|
110
107
|
scopeShortcuts.variables = api;
|
|
@@ -197,7 +194,16 @@ const normalizeSendBody = (body) => {
|
|
|
197
194
|
if (isPlainRecord(body)) {
|
|
198
195
|
const mode = body.mode;
|
|
199
196
|
if (mode === "raw") {
|
|
200
|
-
|
|
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" };
|
|
201
207
|
}
|
|
202
208
|
if (mode === "urlencoded" && Array.isArray(body.urlencoded)) {
|
|
203
209
|
const params = new URLSearchParams();
|
|
@@ -254,7 +260,33 @@ const resolveSendTemplates = (value, resolve) => {
|
|
|
254
260
|
}
|
|
255
261
|
return value;
|
|
256
262
|
};
|
|
257
|
-
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 }) => {
|
|
258
290
|
// Host-injected executor (desktop's real engine) takes precedence; backend
|
|
259
291
|
// and CLI omit it and fall back to the built-in bare-axios client.
|
|
260
292
|
const run = executor ?? executeRequest;
|
|
@@ -263,20 +295,60 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
263
295
|
// pm.environment.set writes made earlier in this script). No resolver
|
|
264
296
|
// wired → identity passthrough so behaviour is unchanged.
|
|
265
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
|
+
};
|
|
266
315
|
return (options, callback) => {
|
|
267
316
|
const promise = (async () => {
|
|
268
|
-
const rawOptions =
|
|
269
|
-
? { url: options, method: "GET" }
|
|
270
|
-
: isPlainRecord(options)
|
|
271
|
-
? options
|
|
272
|
-
: {};
|
|
317
|
+
const rawOptions = toDefinition(options);
|
|
273
318
|
// Resolve templates up-front against the live scope, then normalize.
|
|
274
319
|
const normalized = resolveSendTemplates(rawOptions, resolve);
|
|
275
|
-
const url =
|
|
320
|
+
const url = urlFrom(normalized.url);
|
|
276
321
|
const method = String(normalized.method ?? "GET").toUpperCase();
|
|
277
322
|
const headerInput = normalized.header ?? normalized.headers;
|
|
278
323
|
const headers = normalizeSendHeaderInput(headerInput);
|
|
279
|
-
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
|
+
}
|
|
280
352
|
if (impliedContentType &&
|
|
281
353
|
!Object.keys(headers).some((k) => k.toLowerCase() === "content-type")) {
|
|
282
354
|
headers["Content-Type"] = impliedContentType;
|
|
@@ -284,6 +356,14 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
284
356
|
const timeoutMs = typeof normalized.timeout === "number" && normalized.timeout > 0
|
|
285
357
|
? Number(normalized.timeout)
|
|
286
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
|
+
}
|
|
287
367
|
const result = await run({
|
|
288
368
|
method,
|
|
289
369
|
url,
|
|
@@ -292,21 +372,47 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
292
372
|
body: data,
|
|
293
373
|
timeoutMs,
|
|
294
374
|
});
|
|
295
|
-
const bodyText = typeof result.
|
|
296
|
-
? result.
|
|
297
|
-
:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
+
}
|
|
305
411
|
return {
|
|
306
412
|
code: result.status,
|
|
307
413
|
status: result.status,
|
|
308
414
|
statusText: "",
|
|
309
|
-
headers:
|
|
415
|
+
headers: responseHeaders,
|
|
310
416
|
body: result.data,
|
|
311
417
|
responseTime: result.duration,
|
|
312
418
|
duration: result.duration,
|
|
@@ -323,7 +429,7 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
323
429
|
if (typeof callback === "function") {
|
|
324
430
|
promise.then((response) => {
|
|
325
431
|
try {
|
|
326
|
-
callback(null, response);
|
|
432
|
+
callback(null, response, undefined);
|
|
327
433
|
}
|
|
328
434
|
catch (callbackError) {
|
|
329
435
|
// Surface callback throws to the host log; suppressing
|
|
@@ -333,7 +439,7 @@ const createPmSendRequest = (tracker, executor, resolveTemplate) => {
|
|
|
333
439
|
}
|
|
334
440
|
}, (error) => {
|
|
335
441
|
try {
|
|
336
|
-
callback(error instanceof Error ? error : new Error(String(error)), null);
|
|
442
|
+
callback(error instanceof Error ? error : new Error(String(error)), null, undefined);
|
|
337
443
|
}
|
|
338
444
|
catch (callbackError) {
|
|
339
445
|
// eslint-disable-next-line no-console
|
|
@@ -378,8 +484,12 @@ const buildPm = (capabilities, logs, collectors, sandboxDPm) => {
|
|
|
378
484
|
// interpolates {{var}} exactly like pm.variables.replaceIn(...).
|
|
379
485
|
const variablesApi = sandboxDPm.variables;
|
|
380
486
|
pm.sendRequest = createPmSendRequest(collectors.sendRequestTracker, capabilities.extensions?.sendRequest?.execute, variablesApi
|
|
381
|
-
? (template) => variablesApi.replaceIn(template)
|
|
382
|
-
: 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
|
+
});
|
|
383
493
|
}
|
|
384
494
|
const extensions = capabilities.extensions ?? {};
|
|
385
495
|
if (extensions.log) {
|
|
@@ -393,7 +503,7 @@ const buildPm = (capabilities, logs, collectors, sandboxDPm) => {
|
|
|
393
503
|
}
|
|
394
504
|
return pm;
|
|
395
505
|
};
|
|
396
|
-
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, }) => {
|
|
397
507
|
const exposeLabels = capabilities.workflowContext &&
|
|
398
508
|
capabilities.exposeLabelsAsGlobals !== false;
|
|
399
509
|
const labelGlobals = exposeLabels
|
|
@@ -412,7 +522,6 @@ const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environme
|
|
|
412
522
|
expect,
|
|
413
523
|
console: consoleApi,
|
|
414
524
|
db: sandboxDShortcuts.db,
|
|
415
|
-
kafka: sandboxDShortcuts.kafka,
|
|
416
525
|
redis: sandboxDShortcuts.redis,
|
|
417
526
|
random: sandboxDShortcuts.random,
|
|
418
527
|
counter: sandboxDShortcuts.counter,
|
|
@@ -420,14 +529,26 @@ const buildScopeBindings = ({ pm, capabilities, consoleApi, envValues, environme
|
|
|
420
529
|
CryptoJS: sandboxDShortcuts.CryptoJS,
|
|
421
530
|
lodash,
|
|
422
531
|
timers,
|
|
532
|
+
extraGlobals,
|
|
423
533
|
labelGlobals,
|
|
424
534
|
};
|
|
425
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)/;
|
|
426
537
|
export const executeScript = async (input) => {
|
|
427
538
|
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
428
539
|
const filename = input.filename ?? DEFAULT_FILENAME;
|
|
429
540
|
const stage = input.stage ?? DEFAULT_STAGE;
|
|
430
|
-
|
|
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;
|
|
431
552
|
const extensions = capabilities.extensions ?? {};
|
|
432
553
|
// Empty / whitespace-only scripts short-circuit with an empty success.
|
|
433
554
|
if (!input.script.trim()) {
|
|
@@ -442,9 +563,6 @@ export const executeScript = async (input) => {
|
|
|
442
563
|
if (extensions.counter) {
|
|
443
564
|
passthrough.counterSnapshot = extensions.counter.snapshot;
|
|
444
565
|
}
|
|
445
|
-
if (capabilities.allowDeferredKafkaTests) {
|
|
446
|
-
passthrough.deferredTestNames = [];
|
|
447
|
-
}
|
|
448
566
|
if (capabilities.localVariables) {
|
|
449
567
|
passthrough.localVariables = { ...capabilities.localVariables.values };
|
|
450
568
|
}
|
|
@@ -470,23 +588,46 @@ export const executeScript = async (input) => {
|
|
|
470
588
|
: buildCollectionVariablesApi({}, null);
|
|
471
589
|
const infoApi = buildInfoApi(capabilities.info, stage);
|
|
472
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
|
+
});
|
|
473
596
|
const requestBundle = capabilities.request
|
|
474
|
-
?
|
|
597
|
+
? runtime.sdk
|
|
598
|
+
? buildSdkRequestApi(runtime.sdk, capabilities.request)
|
|
599
|
+
: buildRequestApi(capabilities.request)
|
|
475
600
|
: undefined;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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);
|
|
482
611
|
const logCollector = extensions.log
|
|
483
|
-
? createLogCollector()
|
|
612
|
+
? createLogCollector(typeof extensions.log === "object" ? { onEntry: extensions.log.onEntry } : {})
|
|
484
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
|
+
}
|
|
485
619
|
// Sandbox D feature bundle — depends on env/globals being constructed first
|
|
486
620
|
// (cryptojs/random/counter don't, but variables/db do).
|
|
487
|
-
const sandboxD = buildSandboxDFeatures(capabilities, () => tests.isInsideCallback(), environmentApi?.values ?? capabilities.environment?.values ?? {}, globalsApi?.values ?? capabilities.globals?.values ?? {}, capabilities.response ?? null, collectionVariablesApi.values
|
|
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
|
+
});
|
|
488
626
|
const sendRequestTracker = buildSendRequestPendingTracker();
|
|
489
|
-
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
|
+
});
|
|
490
631
|
const pm = buildPm(capabilities, { pmLog: logCollector.pmLog }, {
|
|
491
632
|
test: tests,
|
|
492
633
|
expect,
|
|
@@ -498,9 +639,88 @@ export const executeScript = async (input) => {
|
|
|
498
639
|
request: requestBundle,
|
|
499
640
|
response: responseApi ?? undefined,
|
|
500
641
|
sendRequestTracker,
|
|
642
|
+
runtime,
|
|
501
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
|
+
}
|
|
502
721
|
const bindings = buildScopeBindings({
|
|
503
722
|
pm,
|
|
723
|
+
extraGlobals,
|
|
504
724
|
capabilities,
|
|
505
725
|
consoleApi: logCollector.consoleApi,
|
|
506
726
|
envValues: environmentApi?.values,
|
|
@@ -515,6 +735,8 @@ export const executeScript = async (input) => {
|
|
|
515
735
|
clearTimeout: timerFeature.api.clearTimeout,
|
|
516
736
|
setInterval: timerFeature.api.setInterval,
|
|
517
737
|
clearInterval: timerFeature.api.clearInterval,
|
|
738
|
+
setImmediate: timerFeature.api.setImmediate,
|
|
739
|
+
clearImmediate: timerFeature.api.clearImmediate,
|
|
518
740
|
},
|
|
519
741
|
});
|
|
520
742
|
let compiled;
|
|
@@ -537,9 +759,6 @@ export const executeScript = async (input) => {
|
|
|
537
759
|
if (sandboxD.counterSnapshotFn) {
|
|
538
760
|
result.counterSnapshot = sandboxD.counterSnapshotFn();
|
|
539
761
|
}
|
|
540
|
-
if (capabilities.allowDeferredKafkaTests) {
|
|
541
|
-
result.deferredTestNames = [];
|
|
542
|
-
}
|
|
543
762
|
if (capabilities.localVariables) {
|
|
544
763
|
result.localVariables = { ...capabilities.localVariables.values };
|
|
545
764
|
}
|
|
@@ -585,9 +804,6 @@ export const executeScript = async (input) => {
|
|
|
585
804
|
if (sandboxD.counterSnapshotFn) {
|
|
586
805
|
result.counterSnapshot = sandboxD.counterSnapshotFn();
|
|
587
806
|
}
|
|
588
|
-
if (capabilities.allowDeferredKafkaTests) {
|
|
589
|
-
result.deferredTestNames = [...tests.deferredTestNames];
|
|
590
|
-
}
|
|
591
807
|
// Only surface executionControl when the host actually wired the
|
|
592
808
|
// capability — keeps the result shape unchanged for callers that
|
|
593
809
|
// don't know about pm.execution yet.
|
|
@@ -597,6 +813,10 @@ export const executeScript = async (input) => {
|
|
|
597
813
|
if (capabilities.localVariables) {
|
|
598
814
|
result.localVariables = sandboxD.variablesApi.localSnapshot?.() ?? {};
|
|
599
815
|
}
|
|
816
|
+
const visualization = visualizerFeature.payload();
|
|
817
|
+
if (visualization) {
|
|
818
|
+
result.visualizer = visualization;
|
|
819
|
+
}
|
|
600
820
|
return result;
|
|
601
821
|
};
|
|
602
822
|
// Standalone parse-only check — exposed so the desktop's
|