@usebruno/js 0.50.0 → 0.52.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.
@@ -2,11 +2,28 @@ const addBruShimToContext = require('./shims/bru');
2
2
  const addBrunoRequestShimToContext = require('./shims/bruno-request');
3
3
  const addConsoleShimToContext = require('./shims/console');
4
4
  const addBrunoResponseShimToContext = require('./shims/bruno-response');
5
+ const addBrunoGrpcShimToContext = require('./shims/bruno-grpc');
5
6
  const addTestShimToContext = require('./shims/test');
6
7
  const addLibraryShimsToContext = require('./shims/lib');
7
8
  const addLocalModuleLoaderShimToContext = require('./shims/local-module');
8
9
  const { getRequireCode } = require('./shims/require');
9
- const { newQuickJSWASMModule, memoizePromiseFactory } = require('quickjs-emscripten');
10
+ const { newQuickJSWASMModuleFromVariant, newVariant, RELEASE_SYNC } = require('quickjs-emscripten');
11
+
12
+ // The engine prints its dispose-abort assertion to stderr on its own. Swallow
13
+ // that line on the CLI, where stderr is the user's screen and a handled trap
14
+ // would read as a crash; keep it in the app, whose console is not user facing.
15
+ const isElectronHost = Boolean(process.versions.electron);
16
+ const isContainedAbortLine = (line) =>
17
+ String(line).includes('list_empty(&rt->gc_obj_list)') && String(line).includes('JS_FreeRuntime');
18
+ const quietEngineVariant = newVariant(RELEASE_SYNC, {
19
+ emscriptenModule: {
20
+ printErr: (line) => {
21
+ if (isElectronHost || !isContainedAbortLine(line)) {
22
+ console.error(line);
23
+ }
24
+ }
25
+ }
26
+ });
10
27
 
11
28
  // execute `npm run sandbox:bundle-libraries` if the below file doesn't exist
12
29
  const getBundledCode = require('../bundle-browser-rollup');
@@ -16,8 +33,54 @@ const addCryptoUtilsShimToContext = require('./shims/lib/crypto-utils');
16
33
  const { wrapScriptInClosure, SANDBOX } = require('../../utils/sandbox');
17
34
 
18
35
  let QuickJSModule;
19
- const loader = memoizePromiseFactory(() => newQuickJSWASMModule());
20
- loader().then((mod) => (QuickJSModule = mod));
36
+ let quickJSModulePromise;
37
+ let quickJSModuleLoading = false;
38
+ let quickJSModuleRecycleCount = 0;
39
+
40
+ // Memoized WASM module for sync + async. reload swaps with no gap; failed
41
+ // reload restores the old memo, failed initial load clears it.
42
+ const loader = ({ reload = false } = {}) => {
43
+ if (!quickJSModulePromise || (reload && !quickJSModuleLoading)) {
44
+ const previousPromise = quickJSModulePromise;
45
+ quickJSModuleLoading = true;
46
+ quickJSModulePromise = newQuickJSWASMModuleFromVariant(quietEngineVariant)
47
+ .then((mod) => {
48
+ QuickJSModule = mod;
49
+ return mod;
50
+ })
51
+ .catch((loadError) => {
52
+ console.error(reload ? 'QuickJS module reload failed' : 'QuickJS module load failed', loadError);
53
+ quickJSModulePromise = reload ? previousPromise : null;
54
+ if (quickJSModulePromise) {
55
+ return quickJSModulePromise;
56
+ }
57
+ throw loadError;
58
+ })
59
+ .finally(() => {
60
+ quickJSModuleLoading = false;
61
+ });
62
+ }
63
+ return quickJSModulePromise;
64
+ };
65
+ loader().catch(() => {});
66
+
67
+ // On dispose WASM trap, recycle the module (old one keeps serving until ready).
68
+ const recycleQuickJSModuleOnAbort = (teardownError, ownerModule) => {
69
+ if (!(teardownError instanceof WebAssembly.RuntimeError)) {
70
+ return false;
71
+ }
72
+ // Skip if this module was already replaced.
73
+ if (!ownerModule || ownerModule === QuickJSModule) {
74
+ quickJSModuleRecycleCount += 1;
75
+ console.warn(
76
+ quickJSModuleRecycleCount === 1
77
+ ? 'QuickJS engine crashed during cleanup and was replaced; the run was not affected'
78
+ : `QuickJS engine replaced again (${quickJSModuleRecycleCount} this session)`
79
+ );
80
+ loader({ reload: true }).catch(() => {});
81
+ }
82
+ return true;
83
+ };
21
84
 
22
85
  const toNumber = (value) => {
23
86
  const num = Number(value);
@@ -57,8 +120,9 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
57
120
  externalScript = removeQuotes(externalScript);
58
121
  }
59
122
  let managedQuickJsContext;
123
+ const quickJsModule = QuickJSModule;
60
124
  try {
61
- managedQuickJsContext = createManagedQuickJsContext(QuickJSModule);
125
+ managedQuickJsContext = createManagedQuickJsContext(quickJsModule);
62
126
  const vm = managedQuickJsContext.vm;
63
127
  const { bru, req, res, ...variables } = externalContext;
64
128
 
@@ -88,7 +152,13 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
88
152
  } catch (error) {
89
153
  console.error('Error executing the script!', error);
90
154
  } finally {
91
- managedQuickJsContext?.dispose();
155
+ try {
156
+ managedQuickJsContext?.dispose();
157
+ } catch (teardownError) {
158
+ if (!recycleQuickJSModuleOnAbort(teardownError, quickJsModule)) {
159
+ console.error('Error disposing QuickJS context', teardownError);
160
+ }
161
+ }
92
162
  }
93
163
  };
94
164
 
@@ -99,9 +169,11 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
99
169
  externalScript = externalScript?.trim();
100
170
 
101
171
  let managedQuickJsContext;
172
+ let scriptError;
173
+ let quickJsModule;
102
174
  try {
103
- const module = await loader();
104
- managedQuickJsContext = createManagedQuickJsContext(module);
175
+ quickJsModule = await loader();
176
+ managedQuickJsContext = createManagedQuickJsContext(quickJsModule);
105
177
  const vm = managedQuickJsContext.vm;
106
178
 
107
179
  // add crypto utilities required by the crypto-js library in bundledCode
@@ -120,6 +192,7 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
120
192
 
121
193
  consoleFn && addConsoleShimToContext(vm, consoleFn);
122
194
  bru && addBruShimToContext(vm, bru);
195
+ bru?.grpc && addBrunoGrpcShimToContext(vm, bru.grpc);
123
196
  req && addBrunoRequestShimToContext(vm, req);
124
197
  res && addBrunoResponseShimToContext(vm, res);
125
198
  addLocalModuleLoaderShimToContext(vm, collectionPath);
@@ -137,22 +210,33 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
137
210
  promiseHandle.dispose();
138
211
  const resolvedHandle = vm.unwrapResult(resolvedResult);
139
212
  resolvedHandle.dispose();
140
- return;
141
213
  } catch (error) {
142
214
  error.__isQuickJS = true;
143
- throw error;
144
- } finally {
145
- // Wait for any in-flight async work (sendRequest, axios, cookie jar, timers,
146
- // un-awaited promises) to settle before tearing down the VM. Disposing while
147
- // a deferred is still pending lets its later host callback touch a freed
148
- // context, throwing `QuickJSUseAfterFree`.
215
+ scriptError = error;
216
+ }
217
+
218
+ // The run waits for every pending deferred before returning: un-awaited
219
+ // async work is the user's choice, and the run is not done until it is.
220
+ // The wait is unbounded by design; cancelling the request is the way out.
221
+ if (managedQuickJsContext) {
222
+ // No try/catch: every awaited settle promise is pre-caught at creation
223
+ // (trackPendingDeferreds), so this await cannot reject and skip dispose.
224
+ await managedQuickJsContext.waitForPendingDeferreds();
149
225
  try {
150
- await managedQuickJsContext?.waitForPendingDeferreds?.();
151
- managedQuickJsContext?.dispose();
226
+ managedQuickJsContext.dispose();
152
227
  } catch (teardownError) {
153
- throw teardownError;
228
+ const recycled = recycleQuickJSModuleOnAbort(teardownError, quickJsModule);
229
+ if (!scriptError && !recycled) {
230
+ scriptError = teardownError;
231
+ } else if (!recycled) {
232
+ console.error('Error disposing QuickJS context', teardownError);
233
+ }
154
234
  }
155
235
  }
236
+
237
+ if (scriptError) {
238
+ throw scriptError;
239
+ }
156
240
  };
157
241
 
158
242
  module.exports = {
@@ -7,207 +7,207 @@ const addBruShimToContext = (vm, bru) => {
7
7
  const bruRunnerObject = vm.newObject();
8
8
  const bruRunnerIterationDataObject = vm.newObject();
9
9
 
10
- let cwd = vm.newFunction('cwd', function () {
10
+ const cwd = vm.newFunction('cwd', function () {
11
11
  return marshallToVm(bru.cwd(), vm);
12
12
  });
13
13
  vm.setProp(bruObject, 'cwd', cwd);
14
14
  cwd.dispose();
15
15
 
16
- let getEnvName = vm.newFunction('getEnvName', function () {
16
+ const getEnvName = vm.newFunction('getEnvName', function () {
17
17
  return marshallToVm(bru.getEnvName(), vm);
18
18
  });
19
19
  vm.setProp(bruObject, 'getEnvName', getEnvName);
20
20
  getEnvName.dispose();
21
21
 
22
- let getCollectionName = vm.newFunction('getCollectionName', function () {
22
+ const getCollectionName = vm.newFunction('getCollectionName', function () {
23
23
  return marshallToVm(bru.getCollectionName(), vm);
24
24
  });
25
25
  vm.setProp(bruObject, 'getCollectionName', getCollectionName);
26
26
  getCollectionName.dispose();
27
27
 
28
- let isSafeMode = vm.newFunction('isSafeMode', function () {
28
+ const isSafeMode = vm.newFunction('isSafeMode', function () {
29
29
  return marshallToVm(bru.isSafeMode(), vm);
30
30
  });
31
31
  vm.setProp(bruObject, 'isSafeMode', isSafeMode);
32
32
  isSafeMode.dispose();
33
33
 
34
- let getProcessEnv = vm.newFunction('getProcessEnv', function (key) {
34
+ const getProcessEnv = vm.newFunction('getProcessEnv', function (key) {
35
35
  return marshallToVm(bru.getProcessEnv(vm.dump(key)), vm);
36
36
  });
37
37
  vm.setProp(bruObject, 'getProcessEnv', getProcessEnv);
38
38
  getProcessEnv.dispose();
39
39
 
40
- let interpolate = vm.newFunction('interpolate', function (str) {
40
+ const interpolate = vm.newFunction('interpolate', function (str) {
41
41
  return marshallToVm(bru.interpolate(vm.dump(str)), vm);
42
42
  });
43
43
  vm.setProp(bruObject, 'interpolate', interpolate);
44
44
  interpolate.dispose();
45
45
 
46
- let hasEnvVar = vm.newFunction('hasEnvVar', function (key) {
46
+ const hasEnvVar = vm.newFunction('hasEnvVar', function (key) {
47
47
  return marshallToVm(bru.hasEnvVar(vm.dump(key)), vm);
48
48
  });
49
49
  vm.setProp(bruObject, 'hasEnvVar', hasEnvVar);
50
50
  hasEnvVar.dispose();
51
51
 
52
- let getEnvVar = vm.newFunction('getEnvVar', function (key) {
52
+ const getEnvVar = vm.newFunction('getEnvVar', function (key) {
53
53
  return marshallToVm(bru.getEnvVar(vm.dump(key)), vm);
54
54
  });
55
55
  vm.setProp(bruObject, 'getEnvVar', getEnvVar);
56
56
  getEnvVar.dispose();
57
57
 
58
- let setEnvVar = vm.newFunction('setEnvVar', function (key, value) {
58
+ const setEnvVar = vm.newFunction('setEnvVar', function (key, value) {
59
59
  bru.setEnvVar(vm.dump(key), vm.dump(value));
60
60
  });
61
61
  vm.setProp(bruObject, 'setEnvVar', setEnvVar);
62
62
  setEnvVar.dispose();
63
63
 
64
- let deleteEnvVar = vm.newFunction('deleteEnvVar', function (key) {
64
+ const deleteEnvVar = vm.newFunction('deleteEnvVar', function (key) {
65
65
  bru.deleteEnvVar(vm.dump(key));
66
66
  });
67
67
  vm.setProp(bruObject, 'deleteEnvVar', deleteEnvVar);
68
68
  deleteEnvVar.dispose();
69
69
 
70
- let getAllEnvVars = vm.newFunction('getAllEnvVars', function () {
70
+ const getAllEnvVars = vm.newFunction('getAllEnvVars', function () {
71
71
  return marshallToVm(bru.getAllEnvVars(), vm);
72
72
  });
73
73
  vm.setProp(bruObject, 'getAllEnvVars', getAllEnvVars);
74
74
  getAllEnvVars.dispose();
75
75
 
76
- let deleteAllEnvVars = vm.newFunction('deleteAllEnvVars', function () {
76
+ const deleteAllEnvVars = vm.newFunction('deleteAllEnvVars', function () {
77
77
  bru.deleteAllEnvVars();
78
78
  });
79
79
  vm.setProp(bruObject, 'deleteAllEnvVars', deleteAllEnvVars);
80
80
  deleteAllEnvVars.dispose();
81
81
 
82
- let getGlobalEnvVar = vm.newFunction('getGlobalEnvVar', function (key) {
82
+ const getGlobalEnvVar = vm.newFunction('getGlobalEnvVar', function (key) {
83
83
  return marshallToVm(bru.getGlobalEnvVar(vm.dump(key)), vm);
84
84
  });
85
85
  vm.setProp(bruObject, 'getGlobalEnvVar', getGlobalEnvVar);
86
86
  getGlobalEnvVar.dispose();
87
87
 
88
- let getOauth2CredentialVar = vm.newFunction('getOauth2CredentialVar', function (key) {
88
+ const getOauth2CredentialVar = vm.newFunction('getOauth2CredentialVar', function (key) {
89
89
  return marshallToVm(bru.getOauth2CredentialVar(vm.dump(key)), vm);
90
90
  });
91
91
  vm.setProp(bruObject, 'getOauth2CredentialVar', getOauth2CredentialVar);
92
92
  getOauth2CredentialVar.dispose();
93
93
 
94
- let resetOauth2Credential = vm.newFunction('resetOauth2Credential', function (credentialId) {
94
+ const resetOauth2Credential = vm.newFunction('resetOauth2Credential', function (credentialId) {
95
95
  bru.resetOauth2Credential(vm.dump(credentialId));
96
96
  });
97
97
  vm.setProp(bruObject, 'resetOauth2Credential', resetOauth2Credential);
98
98
  resetOauth2Credential.dispose();
99
99
 
100
- let setGlobalEnvVar = vm.newFunction('setGlobalEnvVar', function (key, value) {
100
+ const setGlobalEnvVar = vm.newFunction('setGlobalEnvVar', function (key, value) {
101
101
  bru.setGlobalEnvVar(vm.dump(key), vm.dump(value));
102
102
  });
103
103
  vm.setProp(bruObject, 'setGlobalEnvVar', setGlobalEnvVar);
104
104
  setGlobalEnvVar.dispose();
105
105
 
106
- let deleteGlobalEnvVar = vm.newFunction('deleteGlobalEnvVar', function (key) {
106
+ const deleteGlobalEnvVar = vm.newFunction('deleteGlobalEnvVar', function (key) {
107
107
  bru.deleteGlobalEnvVar(vm.dump(key));
108
108
  });
109
109
  vm.setProp(bruObject, 'deleteGlobalEnvVar', deleteGlobalEnvVar);
110
110
  deleteGlobalEnvVar.dispose();
111
111
 
112
- let getAllGlobalEnvVars = vm.newFunction('getAllGlobalEnvVars', function () {
112
+ const getAllGlobalEnvVars = vm.newFunction('getAllGlobalEnvVars', function () {
113
113
  return marshallToVm(bru.getAllGlobalEnvVars(), vm);
114
114
  });
115
115
  vm.setProp(bruObject, 'getAllGlobalEnvVars', getAllGlobalEnvVars);
116
116
  getAllGlobalEnvVars.dispose();
117
117
 
118
- let hasGlobalEnvVar = vm.newFunction('hasGlobalEnvVar', function (key) {
118
+ const hasGlobalEnvVar = vm.newFunction('hasGlobalEnvVar', function (key) {
119
119
  return marshallToVm(bru.hasGlobalEnvVar(vm.dump(key)), vm);
120
120
  });
121
121
  vm.setProp(bruObject, 'hasGlobalEnvVar', hasGlobalEnvVar);
122
122
  hasGlobalEnvVar.dispose();
123
123
 
124
- let deleteAllGlobalEnvVars = vm.newFunction('deleteAllGlobalEnvVars', function () {
124
+ const deleteAllGlobalEnvVars = vm.newFunction('deleteAllGlobalEnvVars', function () {
125
125
  bru.deleteAllGlobalEnvVars();
126
126
  });
127
127
  vm.setProp(bruObject, 'deleteAllGlobalEnvVars', deleteAllGlobalEnvVars);
128
128
  deleteAllGlobalEnvVars.dispose();
129
129
 
130
- let hasVar = vm.newFunction('hasVar', function (key) {
130
+ const hasVar = vm.newFunction('hasVar', function (key) {
131
131
  return marshallToVm(bru.hasVar(vm.dump(key)), vm);
132
132
  });
133
133
  vm.setProp(bruObject, 'hasVar', hasVar);
134
134
  hasVar.dispose();
135
135
 
136
- let getVar = vm.newFunction('getVar', function (key) {
136
+ const getVar = vm.newFunction('getVar', function (key) {
137
137
  return marshallToVm(bru.getVar(vm.dump(key)), vm);
138
138
  });
139
139
  vm.setProp(bruObject, 'getVar', getVar);
140
140
  getVar.dispose();
141
141
 
142
- let setVar = vm.newFunction('setVar', function (key, value) {
142
+ const setVar = vm.newFunction('setVar', function (key, value) {
143
143
  bru.setVar(vm.dump(key), vm.dump(value));
144
144
  });
145
145
  vm.setProp(bruObject, 'setVar', setVar);
146
146
  setVar.dispose();
147
147
 
148
- let deleteVar = vm.newFunction('deleteVar', function (key) {
148
+ const deleteVar = vm.newFunction('deleteVar', function (key) {
149
149
  bru.deleteVar(vm.dump(key));
150
150
  });
151
151
  vm.setProp(bruObject, 'deleteVar', deleteVar);
152
152
  deleteVar.dispose();
153
153
 
154
- let deleteAllVars = vm.newFunction('deleteAllVars', function () {
154
+ const deleteAllVars = vm.newFunction('deleteAllVars', function () {
155
155
  bru.deleteAllVars();
156
156
  });
157
157
  vm.setProp(bruObject, 'deleteAllVars', deleteAllVars);
158
158
  deleteAllVars.dispose();
159
159
 
160
- let getAllVars = vm.newFunction('getAllVars', function () {
160
+ const getAllVars = vm.newFunction('getAllVars', function () {
161
161
  return marshallToVm(bru.getAllVars(), vm);
162
162
  });
163
163
  vm.setProp(bruObject, 'getAllVars', getAllVars);
164
164
  getAllVars.dispose();
165
165
 
166
- let setNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
166
+ const setNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
167
167
  bru.setNextRequest(vm.dump(nextRequest));
168
168
  });
169
169
  vm.setProp(bruObject, 'setNextRequest', setNextRequest);
170
170
  setNextRequest.dispose();
171
171
 
172
- let runnerSkipRequest = vm.newFunction('skipRequest', function () {
172
+ const runnerSkipRequest = vm.newFunction('skipRequest', function () {
173
173
  bru?.runner?.skipRequest();
174
174
  });
175
175
  vm.setProp(bruRunnerObject, 'skipRequest', runnerSkipRequest);
176
176
  runnerSkipRequest.dispose();
177
177
 
178
- let runnerStopExecution = vm.newFunction('stopExecution', function () {
178
+ const runnerStopExecution = vm.newFunction('stopExecution', function () {
179
179
  bru?.runner?.stopExecution();
180
180
  });
181
181
  vm.setProp(bruRunnerObject, 'stopExecution', runnerStopExecution);
182
182
  runnerStopExecution.dispose();
183
183
 
184
- let runnerSetNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
184
+ const runnerSetNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
185
185
  bru?.runner?.setNextRequest(vm.dump(nextRequest));
186
186
  });
187
187
  vm.setProp(bruRunnerObject, 'setNextRequest', runnerSetNextRequest);
188
188
  runnerSetNextRequest.dispose();
189
189
 
190
- let runnerIterationIndex = marshallToVm(bru?.runner?.iterationIndex, vm);
190
+ const runnerIterationIndex = marshallToVm(bru?.runner?.iterationIndex, vm);
191
191
  vm.setProp(bruRunnerObject, 'iterationIndex', runnerIterationIndex);
192
192
  runnerIterationIndex.dispose();
193
193
 
194
- let runnerTotalIterations = marshallToVm(bru?.runner?.totalIterations, vm);
194
+ const runnerTotalIterations = marshallToVm(bru?.runner?.totalIterations, vm);
195
195
  vm.setProp(bruRunnerObject, 'totalIterations', runnerTotalIterations);
196
196
  runnerTotalIterations.dispose();
197
197
 
198
- let runnerSetIterationData = vm.newFunction('set', function (key, value) {
198
+ const runnerSetIterationData = vm.newFunction('set', function (key, value) {
199
199
  bru?.runner?.iterationData?.set(vm.dump(key), vm.dump(value));
200
200
  });
201
201
  vm.setProp(bruRunnerIterationDataObject, 'set', runnerSetIterationData);
202
202
  runnerSetIterationData.dispose();
203
203
 
204
- let runnerUnsetIterationData = vm.newFunction('unset', function (key) {
204
+ const runnerUnsetIterationData = vm.newFunction('unset', function (key) {
205
205
  bru?.runner?.iterationData?.unset(vm.dump(key));
206
206
  });
207
207
  vm.setProp(bruRunnerIterationDataObject, 'unset', runnerUnsetIterationData);
208
208
  runnerUnsetIterationData.dispose();
209
209
 
210
- let runnerGetIterationData = vm.newFunction('get', function (key) {
210
+ const runnerGetIterationData = vm.newFunction('get', function (key) {
211
211
  if (key) {
212
212
  return marshallToVm(bru?.runner?.iterationData?.get(vm.dump(key)), vm);
213
213
  }
@@ -216,13 +216,13 @@ const addBruShimToContext = (vm, bru) => {
216
216
  vm.setProp(bruRunnerIterationDataObject, 'get', runnerGetIterationData);
217
217
  runnerGetIterationData.dispose();
218
218
 
219
- let runnerHasIterationData = vm.newFunction('has', function (key) {
219
+ const runnerHasIterationData = vm.newFunction('has', function (key) {
220
220
  return marshallToVm(bru?.runner?.iterationData?.has(vm.dump(key)), vm);
221
221
  });
222
222
  vm.setProp(bruRunnerIterationDataObject, 'has', runnerHasIterationData);
223
223
  runnerHasIterationData.dispose();
224
224
 
225
- let runnerStringifyIterationData = vm.newFunction('stringify', function () {
225
+ const runnerStringifyIterationData = vm.newFunction('stringify', function () {
226
226
  return marshallToVm(bru?.runner?.iterationData?.stringify(), vm);
227
227
  });
228
228
  vm.setProp(bruRunnerIterationDataObject, 'stringify', runnerStringifyIterationData);
@@ -231,7 +231,7 @@ const addBruShimToContext = (vm, bru) => {
231
231
  vm.setProp(bruRunnerObject, 'iterationData', bruRunnerIterationDataObject);
232
232
  bruRunnerIterationDataObject.dispose();
233
233
 
234
- let visualize = vm.newFunction('visualize', function (type, data) {
234
+ const visualize = vm.newFunction('visualize', function (type, data) {
235
235
  try {
236
236
  // Guard against missing handles: vm.dump() accesses .owner on the handle
237
237
  // to verify its VM context. When called with no args, the handles are
@@ -249,67 +249,67 @@ const addBruShimToContext = (vm, bru) => {
249
249
  vm.setProp(bruObject, 'visualize', visualize);
250
250
  visualize.dispose();
251
251
 
252
- let clearVisualizations = vm.newFunction('clearVisualizations', function () {
252
+ const clearVisualizations = vm.newFunction('clearVisualizations', function () {
253
253
  bru.clearVisualizations();
254
254
  });
255
255
  vm.setProp(bruObject, 'clearVisualizations', clearVisualizations);
256
256
  clearVisualizations.dispose();
257
257
 
258
- let getSecretVar = vm.newFunction('getSecretVar', function (key) {
258
+ const getSecretVar = vm.newFunction('getSecretVar', function (key) {
259
259
  return marshallToVm(bru.getSecretVar(vm.dump(key)), vm);
260
260
  });
261
261
  vm.setProp(bruObject, 'getSecretVar', getSecretVar);
262
262
  getSecretVar.dispose();
263
263
 
264
- let getRequestVar = vm.newFunction('getRequestVar', function (key) {
264
+ const getRequestVar = vm.newFunction('getRequestVar', function (key) {
265
265
  return marshallToVm(bru.getRequestVar(vm.dump(key)), vm);
266
266
  });
267
267
  vm.setProp(bruObject, 'getRequestVar', getRequestVar);
268
268
  getRequestVar.dispose();
269
269
 
270
- let getFolderVar = vm.newFunction('getFolderVar', function (key) {
270
+ const getFolderVar = vm.newFunction('getFolderVar', function (key) {
271
271
  return marshallToVm(bru.getFolderVar(vm.dump(key)), vm);
272
272
  });
273
273
  vm.setProp(bruObject, 'getFolderVar', getFolderVar);
274
274
  getFolderVar.dispose();
275
275
 
276
- let getCollectionVar = vm.newFunction('getCollectionVar', function (key) {
276
+ const getCollectionVar = vm.newFunction('getCollectionVar', function (key) {
277
277
  return marshallToVm(bru.getCollectionVar(vm.dump(key)), vm);
278
278
  });
279
279
  vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
280
280
  getCollectionVar.dispose();
281
281
 
282
- let setCollectionVar = vm.newFunction('setCollectionVar', function (key, value) {
282
+ const setCollectionVar = vm.newFunction('setCollectionVar', function (key, value) {
283
283
  bru.setCollectionVar(vm.dump(key), vm.dump(value));
284
284
  });
285
285
  vm.setProp(bruObject, 'setCollectionVar', setCollectionVar);
286
286
  setCollectionVar.dispose();
287
287
 
288
- let hasCollectionVar = vm.newFunction('hasCollectionVar', function (key) {
288
+ const hasCollectionVar = vm.newFunction('hasCollectionVar', function (key) {
289
289
  return marshallToVm(bru.hasCollectionVar(vm.dump(key)), vm);
290
290
  });
291
291
  vm.setProp(bruObject, 'hasCollectionVar', hasCollectionVar);
292
292
  hasCollectionVar.dispose();
293
293
 
294
- let deleteCollectionVar = vm.newFunction('deleteCollectionVar', function (key) {
294
+ const deleteCollectionVar = vm.newFunction('deleteCollectionVar', function (key) {
295
295
  bru.deleteCollectionVar(vm.dump(key));
296
296
  });
297
297
  vm.setProp(bruObject, 'deleteCollectionVar', deleteCollectionVar);
298
298
  deleteCollectionVar.dispose();
299
299
 
300
- let deleteAllCollectionVars = vm.newFunction('deleteAllCollectionVars', function () {
300
+ const deleteAllCollectionVars = vm.newFunction('deleteAllCollectionVars', function () {
301
301
  bru.deleteAllCollectionVars();
302
302
  });
303
303
  vm.setProp(bruObject, 'deleteAllCollectionVars', deleteAllCollectionVars);
304
304
  deleteAllCollectionVars.dispose();
305
305
 
306
- let getAllCollectionVars = vm.newFunction('getAllCollectionVars', function () {
306
+ const getAllCollectionVars = vm.newFunction('getAllCollectionVars', function () {
307
307
  return marshallToVm(bru.getAllCollectionVars(), vm);
308
308
  });
309
309
  vm.setProp(bruObject, 'getAllCollectionVars', getAllCollectionVars);
310
310
  getAllCollectionVars.dispose();
311
311
 
312
- let getTestResults = vm.newFunction('getTestResults', () => {
312
+ const getTestResults = vm.newFunction('getTestResults', () => {
313
313
  const promise = vm.newPromise();
314
314
  bru
315
315
  .getTestResults()
@@ -331,7 +331,7 @@ const addBruShimToContext = (vm, bru) => {
331
331
  });
332
332
  getTestResults.consume((handle) => vm.setProp(bruObject, 'getTestResults', handle));
333
333
 
334
- let getAssertionResults = vm.newFunction('getAssertionResults', () => {
334
+ const getAssertionResults = vm.newFunction('getAssertionResults', () => {
335
335
  const promise = vm.newPromise();
336
336
  bru
337
337
  .getAssertionResults()
@@ -353,7 +353,7 @@ const addBruShimToContext = (vm, bru) => {
353
353
  });
354
354
  getAssertionResults.consume((handle) => vm.setProp(bruObject, 'getAssertionResults', handle));
355
355
 
356
- let runRequestHandle = vm.newFunction('runRequest', (args) => {
356
+ const runRequestHandle = vm.newFunction('runRequest', (args) => {
357
357
  const promise = vm.newPromise();
358
358
  bru
359
359
  .runRequest(vm.dump(args))
@@ -375,7 +375,7 @@ const addBruShimToContext = (vm, bru) => {
375
375
  });
376
376
  runRequestHandle.consume((handle) => vm.setProp(bruObject, 'runRequest', handle));
377
377
 
378
- let sendRequestHandle = vm.newFunction('_sendRequest', (args) => {
378
+ const sendRequestHandle = vm.newFunction('_sendRequest', (args) => {
379
379
  const promise = vm.newPromise();
380
380
  bru
381
381
  .sendRequest(vm.dump(args))
@@ -396,7 +396,7 @@ const addBruShimToContext = (vm, bru) => {
396
396
  sendRequestHandle.consume((handle) => vm.setProp(bruObject, '_sendRequest', handle));
397
397
 
398
398
  // On vm.global, not bru, to stay off user-facing autocomplete.
399
- let setScopeHandle = vm.newFunction('__bruSetScope', (scopeArg) => {
399
+ const setScopeHandle = vm.newFunction('__bruSetScope', (scopeArg) => {
400
400
  bru._currentScope = vm.dump(scopeArg) || null;
401
401
  });
402
402
  setScopeHandle.consume((handle) => vm.setProp(vm.global, '__bruSetScope', handle));
@@ -416,7 +416,7 @@ const addBruShimToContext = (vm, bru) => {
416
416
  });
417
417
  sleep.consume((handle) => vm.setProp(bruObject, 'sleep', handle));
418
418
 
419
- let bruCookiesObject = vm.newObject();
419
+ const bruCookiesObject = vm.newObject();
420
420
  const { evalCode: cookiesEvalCode } = createPropertyListBridge(vm, bru.cookies, bruCookiesObject, {
421
421
  globalPath: 'globalThis.bru.cookies',
422
422
  syncReadMethods: ['get', 'has', 'count', 'indexOf', 'toObject', 'toString'],
@@ -0,0 +1,29 @@
1
+ const addBrunoGrpcRequestShimToContext = require('./grpc/bruno-grpc-request');
2
+ const addBrunoGrpcResponseShimToContext = require('./grpc/bruno-grpc-response');
3
+
4
+ /**
5
+ * Installs `bru.grpc` onto the `bru` object the bru shim has already put on the global, so it has
6
+ * to run after it.
7
+ */
8
+ const addBrunoGrpcShimToContext = (vm, grpc) => {
9
+ const bruObject = vm.getProp(vm.global, 'bru');
10
+ const grpcObject = vm.newObject();
11
+
12
+ const { evalCode: requestEvalCode } = addBrunoGrpcRequestShimToContext(vm, grpc.request, grpcObject);
13
+ // `response` is absent in `beforeCallStart`, which has no response yet.
14
+ const { evalCode: responseEvalCode } = grpc.response
15
+ ? addBrunoGrpcResponseShimToContext(vm, grpc.response, grpcObject)
16
+ : { evalCode: [] };
17
+
18
+ vm.setProp(bruObject, 'grpc', grpcObject);
19
+ grpcObject.dispose();
20
+ bruObject.dispose();
21
+
22
+ // The list code reaches its target through `globalThis.bru.grpc`, so it can only run now that
23
+ // `grpc` is on `bru`. Each block is braced on its own — every bridge declares the same consts.
24
+ for (const code of [...requestEvalCode, ...responseEvalCode].filter(Boolean)) {
25
+ vm.evalCode(`{ ${code} }`);
26
+ }
27
+ };
28
+
29
+ module.exports = addBrunoGrpcShimToContext;
@@ -0,0 +1,47 @@
1
+ const { marshallToVm } = require('../../utils');
2
+ const addGrpcMetadataListShimToContext = require('./grpc-metadata-list');
3
+ const addGrpcMessageListShimToContext = require('./grpc-message-list');
4
+
5
+ // Keep this in step with BrunoGrpcRequest.
6
+ const addBrunoGrpcRequestShimToContext = (vm, request, grpcObject) => {
7
+ const requestObject = vm.newObject();
8
+
9
+ const scalars = ['url', 'method', 'methodType', 'authMode', 'protoPath', 'name'];
10
+
11
+ for (const property of scalars) {
12
+ const value = marshallToVm(request[property], vm);
13
+ vm.setProp(requestObject, property, value);
14
+ value.dispose();
15
+ }
16
+
17
+ // request.metadata — writable in `beforeCallStart`, read-only in `afterCallEnd`
18
+ const metadataEvalCode = addGrpcMetadataListShimToContext(
19
+ vm,
20
+ request.metadata,
21
+ requestObject,
22
+ 'metadata',
23
+ 'globalThis.bru.grpc.request'
24
+ );
25
+
26
+ // request.messages — the messages the call sent, read-only, and empty until it has sent any
27
+ const messagesEvalCode = addGrpcMessageListShimToContext(
28
+ vm,
29
+ request.messages,
30
+ requestObject,
31
+ 'globalThis.bru.grpc.request'
32
+ );
33
+
34
+ // request.message — present only in `beforeMessageSend`.
35
+ if (request.message) {
36
+ const message = marshallToVm(request.message, vm);
37
+ vm.setProp(requestObject, 'message', message);
38
+ message.dispose();
39
+ }
40
+
41
+ vm.setProp(grpcObject, 'request', requestObject);
42
+ requestObject.dispose();
43
+
44
+ return { evalCode: [metadataEvalCode, messagesEvalCode] };
45
+ };
46
+
47
+ module.exports = addBrunoGrpcRequestShimToContext;