@builder.io/sdk-react-native 5.0.1 → 5.1.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/lib/browser/commonjs/constants/sdk-version.js +1 -1
- package/lib/browser/commonjs/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/browser/commonjs/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/browser/module/constants/sdk-version.js +1 -1
- package/lib/browser/module/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/browser/module/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/browser/typescript/constants/sdk-version.d.ts +1 -1
- package/lib/edge/commonjs/constants/sdk-version.js +1 -1
- package/lib/edge/commonjs/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/edge/commonjs/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/edge/module/constants/sdk-version.js +1 -1
- package/lib/edge/module/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/edge/module/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/edge/typescript/constants/sdk-version.d.ts +1 -1
- package/lib/node/commonjs/constants/sdk-version.js +1 -1
- package/lib/node/commonjs/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/node/commonjs/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/node/module/constants/sdk-version.js +1 -1
- package/lib/node/module/functions/evaluate/node-runtime/node-runtime.js +72 -68
- package/lib/node/module/functions/evaluate/node-runtime/node-runtime.js.map +1 -1
- package/lib/node/typescript/constants/sdk-version.d.ts +1 -1
- package/package.json +1 -1
- package/src/constants/sdk-version.ts +1 -1
- package/src/functions/evaluate/node-runtime/node-runtime.ts +73 -69
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IsolateOptions } from 'isolated-vm';
|
|
2
2
|
import { SDK_NAME } from '../../../constants/sdk-name';
|
|
3
3
|
import { MSG_PREFIX, logger } from '../../../helpers/logger';
|
|
4
4
|
import { fastClone } from '../../fast-clone';
|
|
@@ -67,17 +67,23 @@ if (typeof output === 'object' && output !== null) {
|
|
|
67
67
|
};
|
|
68
68
|
type IsolatedVMImport = typeof import('isolated-vm');
|
|
69
69
|
let IVM_INSTANCE: IsolatedVMImport | null = null;
|
|
70
|
-
|
|
70
|
+
// Create fresh isolates per request to prevent memory leaks
|
|
71
|
+
let IVM_OPTIONS: IsolateOptions = {
|
|
72
|
+
memoryLimit: 128
|
|
73
|
+
};
|
|
71
74
|
|
|
72
75
|
/**
|
|
73
76
|
* Set the `isolated-vm` instance to be used by the node runtime.
|
|
74
77
|
* This is useful for environments that are not able to rely on our
|
|
75
78
|
* `safeDynamicRequire` trick to import the `isolated-vm` package.
|
|
76
79
|
*/
|
|
77
|
-
export const setIvm = (ivm: IsolatedVMImport, options
|
|
80
|
+
export const setIvm = (ivm: IsolatedVMImport, options?: IsolateOptions) => {
|
|
78
81
|
if (IVM_INSTANCE) return;
|
|
79
82
|
IVM_INSTANCE = ivm;
|
|
80
|
-
|
|
83
|
+
// Store options to be used per-request in runInNode
|
|
84
|
+
if (options) {
|
|
85
|
+
IVM_OPTIONS = options;
|
|
86
|
+
}
|
|
81
87
|
};
|
|
82
88
|
|
|
83
89
|
// only mention the script for SDKs that have it.
|
|
@@ -100,30 +106,6 @@ const getIvm = (): IsolatedVMImport => {
|
|
|
100
106
|
For more information, visit https://builder.io/c/docs/integration-tips#enabling-data-bindings-in-node-environments`;
|
|
101
107
|
throw new Error(ERROR_MESSAGE);
|
|
102
108
|
};
|
|
103
|
-
function setIsolateContext(options: IsolateOptions = {
|
|
104
|
-
memoryLimit: 128
|
|
105
|
-
}) {
|
|
106
|
-
if (IVM_CONTEXT) return IVM_CONTEXT;
|
|
107
|
-
const ivm = getIvm();
|
|
108
|
-
const isolate = new ivm.Isolate(options);
|
|
109
|
-
const context = isolate.createContextSync();
|
|
110
|
-
const jail = context.global;
|
|
111
|
-
|
|
112
|
-
// This makes the global object available in the context as `global`. We use `derefInto()` here
|
|
113
|
-
// because otherwise `global` would actually be a Reference{} object in the new isolate.
|
|
114
|
-
jail.setSync('global', jail.derefInto());
|
|
115
|
-
|
|
116
|
-
// We will create a basic `log` function for the new isolate to use.
|
|
117
|
-
jail.setSync('log', function (...logArgs: any[]) {
|
|
118
|
-
console.log(...logArgs);
|
|
119
|
-
});
|
|
120
|
-
jail.setSync(INJECTED_IVM_GLOBAL, ivm);
|
|
121
|
-
IVM_CONTEXT = context;
|
|
122
|
-
return context;
|
|
123
|
-
}
|
|
124
|
-
const getIsolateContext = () => {
|
|
125
|
-
return setIsolateContext();
|
|
126
|
-
};
|
|
127
109
|
export const runInNode = ({
|
|
128
110
|
code,
|
|
129
111
|
builder,
|
|
@@ -134,48 +116,70 @@ export const runInNode = ({
|
|
|
134
116
|
rootState
|
|
135
117
|
}: ExecutorArgs) => {
|
|
136
118
|
const ivm = getIvm();
|
|
137
|
-
const state = fastClone({
|
|
138
|
-
...rootState,
|
|
139
|
-
...localState
|
|
140
|
-
});
|
|
141
|
-
const args = getFunctionArguments({
|
|
142
|
-
builder,
|
|
143
|
-
context,
|
|
144
|
-
event,
|
|
145
|
-
state
|
|
146
|
-
});
|
|
147
|
-
const isolateContext = getIsolateContext();
|
|
148
|
-
const jail = isolateContext.global;
|
|
149
119
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*/
|
|
153
|
-
jail.setSync(BUILDER_SET_STATE_NAME, function (key: string, value: any) {
|
|
154
|
-
// mutate the `rootState` object itself. Important for cases where we do not have `rootSetState`
|
|
155
|
-
// like Qwik.
|
|
156
|
-
set(rootState, key, value);
|
|
157
|
-
// call the `rootSetState` function if it exists
|
|
158
|
-
rootSetState?.(rootState);
|
|
159
|
-
});
|
|
160
|
-
args.forEach(([key, arg]) => {
|
|
161
|
-
const val = typeof arg === 'object' ? new ivm.Reference(
|
|
162
|
-
// workaround: methods with default values for arguments is not being cloned over
|
|
163
|
-
key === 'builder' ? {
|
|
164
|
-
...arg,
|
|
165
|
-
getUserAttributes: () => (arg as BuilderGlobals).getUserAttributes()
|
|
166
|
-
} : arg) : null;
|
|
167
|
-
jail.setSync(getSyncValName(key), val);
|
|
168
|
-
});
|
|
169
|
-
const evalStr = processCode({
|
|
170
|
-
code,
|
|
171
|
-
args
|
|
172
|
-
});
|
|
173
|
-
const resultStr = isolateContext.evalClosureSync(evalStr);
|
|
120
|
+
// Use stored options from setIvm, or default to { memoryLimit: 128 }
|
|
121
|
+
let isolate;
|
|
174
122
|
try {
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
123
|
+
isolate = new ivm.Isolate(IVM_OPTIONS);
|
|
124
|
+
const isolateContext = isolate.createContextSync();
|
|
125
|
+
const jail = isolateContext.global;
|
|
126
|
+
|
|
127
|
+
// Setup the isolate
|
|
128
|
+
jail.setSync('global', jail.derefInto());
|
|
129
|
+
jail.setSync('log', function (...logArgs: any[]) {
|
|
130
|
+
console.log(...logArgs);
|
|
131
|
+
});
|
|
132
|
+
jail.setSync(INJECTED_IVM_GLOBAL, ivm);
|
|
133
|
+
const state = fastClone({
|
|
134
|
+
...rootState,
|
|
135
|
+
...localState
|
|
136
|
+
});
|
|
137
|
+
const args = getFunctionArguments({
|
|
138
|
+
builder,
|
|
139
|
+
context,
|
|
140
|
+
event,
|
|
141
|
+
state
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Propagate state changes back to the reactive root state.
|
|
146
|
+
*/
|
|
147
|
+
jail.setSync(BUILDER_SET_STATE_NAME, function (key: string, value: any) {
|
|
148
|
+
// mutate the `rootState` object itself. Important for cases where we do not have `rootSetState`
|
|
149
|
+
// like Qwik.
|
|
150
|
+
set(rootState, key, value);
|
|
151
|
+
// call the `rootSetState` function if it exists
|
|
152
|
+
rootSetState?.(rootState);
|
|
153
|
+
});
|
|
154
|
+
args.forEach(([key, arg]) => {
|
|
155
|
+
const val = typeof arg === 'object' ? new ivm.Reference(
|
|
156
|
+
// workaround: methods with default values for arguments is not being cloned over
|
|
157
|
+
key === 'builder' ? {
|
|
158
|
+
...arg,
|
|
159
|
+
getUserAttributes: () => (arg as BuilderGlobals).getUserAttributes()
|
|
160
|
+
} : arg) : null;
|
|
161
|
+
jail.setSync(getSyncValName(key), val);
|
|
162
|
+
});
|
|
163
|
+
const evalStr = processCode({
|
|
164
|
+
code,
|
|
165
|
+
args
|
|
166
|
+
});
|
|
167
|
+
const resultStr = isolateContext.evalClosureSync(evalStr);
|
|
168
|
+
try {
|
|
169
|
+
// returning objects throw errors in isolated vm, so we stringify it and parse it back
|
|
170
|
+
const res = JSON.parse(resultStr);
|
|
171
|
+
return res;
|
|
172
|
+
} catch (_error: any) {
|
|
173
|
+
return resultStr;
|
|
174
|
+
}
|
|
175
|
+
} finally {
|
|
176
|
+
// Destroy the entire VM, this frees ALL memory at the C++ level.
|
|
177
|
+
if (isolate) {
|
|
178
|
+
try {
|
|
179
|
+
isolate.dispose();
|
|
180
|
+
} catch (e) {
|
|
181
|
+
// Ignore disposal errors
|
|
182
|
+
}
|
|
183
|
+
}
|
|
180
184
|
}
|
|
181
185
|
}
|