-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Expand file tree
/
Copy pathrun-script.ts
More file actions
150 lines (137 loc) · 5.13 KB
/
Copy pathrun-script.ts
File metadata and controls
150 lines (137 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import * as _ from 'es-toolkit/compat';
import {
InsomniaObject,
mergeClientCertificates,
mergeCookieJar,
mergeRequests,
mergeSettings,
type RequestContext,
} from '../../../insomnia-scripting-environment/src/objects';
import { defaultSecurityPolicy, prepareSandbox, ScriptSecurityPolicy } from './sandbox';
export const runScript = async ({
script,
context,
securityPolicy = defaultSecurityPolicy,
}: {
script: string;
context: RequestContext;
securityPolicy?: ScriptSecurityPolicy;
}): Promise<RequestContext> => {
const activePolicy = context.settings.scriptSandboxEnabled !== false ? securityPolicy : new ScriptSecurityPolicy([]);
const { executionContext, scriptConsole, maskNames, maskValues, bridgeOps } = await prepareSandbox(
script,
context,
activePolicy,
);
const AsyncFunction = (async () => {}).constructor;
const scriptParams = [
'insomnia', // insomnia scripting API object
'console', // log console
'_', // lodash library
'setTimeout', // proxied setTimeout tracked by the async task monitor
'__waitForAllTestsDone__', // Drains pm.test() assertions before the script exits
'__bridgeReset__', // Clears the async task list and re-enables monitoring
'__bridgeStop__', // Stops recording new promises into the task list
'__bridgeSettle__', // Awaits all tracked promises before returning
...maskNames, // Masked globals from the security policy (e.g. eval → undefined)
];
const strictMode = context.settings.scriptStrictModeEnabled !== false;
const scriptBody = [
`__bridgeReset__();`, // Start with a clean async task slate for this script run
`await (async function() {`, // IIFE gives the user script its own lexical scope
...(strictMode ? [` 'use strict';`] : []), // Strict mode: this === undefined, prevents silent errors
` const $ = insomnia;`, // Postman-compat alias for the insomnia scripting object
` ${script}`, // User script body
`})();`,
`await __waitForAllTestsDone__();`, // Wait for all pm.test() callbacks to resolve
`__bridgeStop__();`, // Stop tracking new promises (user script is done)
`await __bridgeSettle__();`, // Drain any fire-and-forget promises the script created
`return insomnia;`, // Return the (possibly mutated) insomnia context
].join('\n');
// const scriptBody = [
// `const $ = insomnia;`,
// `__bridgeReset__();`,
// `try {`,
// ` ${script}`,
// ` await __waitForAllTestsDone__();`,
// `} finally {`,
// ` __bridgeStop__();`,
// ` await __bridgeSettle__();`,
// `}`,
// `return insomnia;`,
// ].join('\n');
const executeScript = AsyncFunction(...scriptParams, scriptBody);
const mutatedInsomniaObject = await executeScript(
executionContext,
scriptConsole,
_,
proxiedSetTimeout,
bridgeOps.waitForAllTestsDone,
bridgeOps.resetAsyncTasks,
bridgeOps.stopMonitorAsyncTasks,
bridgeOps.asyncTasksAllSettled,
...maskValues,
);
if (mutatedInsomniaObject == null || !(mutatedInsomniaObject instanceof InsomniaObject)) {
throw new Error('insomnia object is invalid or script returns earlier than expected.');
}
const mutatedContextObject = mutatedInsomniaObject.toObject();
const updatedRequest = mergeRequests(context.request, mutatedContextObject.request);
const updatedSettings = mergeSettings(context.settings, mutatedContextObject.request);
const updatedCertificates = mergeClientCertificates(
mutatedContextObject.clientCertificates,
mutatedContextObject.request,
);
const updatedCookieJar = mergeCookieJar(context.cookieJar, mutatedContextObject.cookieJar);
return {
...context,
environment: {
id: context.environment.id,
name: context.environment.name,
data: mutatedContextObject.environment,
},
baseEnvironment: {
id: context.baseEnvironment.id,
name: context.baseEnvironment.name,
data: mutatedContextObject.baseEnvironment,
},
iterationData: context.iterationData
? {
name: context.iterationData.name,
data: mutatedContextObject.iterationData,
}
: undefined,
transientVariables: {
name: context.transientVariables?.name || 'transientVariables',
data: mutatedContextObject.variables,
},
request: updatedRequest,
execution: mutatedContextObject.execution,
settings: updatedSettings,
clientCertificates: updatedCertificates,
cookieJar: updatedCookieJar,
globals: context.globals && {
id: context.globals.id,
name: context.globals.name,
data: mutatedContextObject.globals,
},
baseGlobals: context.baseGlobals && {
id: context.baseGlobals.id,
name: context.baseGlobals.name,
data: mutatedContextObject.baseGlobals,
},
requestTestResults: mutatedContextObject.requestTestResults,
logs: scriptConsole.dumpLogsAsArray(),
parentFolders: mutatedContextObject.parentFolders,
};
};
function proxiedSetTimeout(callback: () => void, ms?: number | undefined) {
let resolveHdl: (value: unknown) => void;
new Promise(resolve => {
resolveHdl = resolve;
});
return setTimeout(() => {
callback();
resolveHdl(null);
}, ms);
}