2
0

🔒 Use isolated-vm

This commit is contained in:
Baptiste Arnaud
2024-05-22 11:42:31 +02:00
parent 15b2901f8a
commit 3d496e1eec
13 changed files with 291 additions and 114 deletions

View File

@ -49,21 +49,14 @@ const nextConfig = {
},
experimental: {
outputFileTracingRoot: join(__dirname, '../../'),
serverComponentsExternalPackages: ['isolated-vm'],
},
webpack: (config, { nextRuntime }) => {
if (nextRuntime === 'nodejs') return config
webpack: (config, { isServer }) => {
if (isServer) return config
if (nextRuntime === 'edge') {
config.resolve.alias['minio'] = false
config.resolve.alias['got'] = false
config.resolve.alias['qrcode'] = false
return config
}
// These packages are imports from the integrations definition files that can be ignored for the client.
config.resolve.alias['minio'] = false
config.resolve.alias['got'] = false
config.resolve.alias['openai'] = false
config.resolve.alias['qrcode'] = false
config.resolve.alias['isolated-vm'] = false
return config
},
headers: async () => {

View File

@ -13,7 +13,6 @@
"format:check": "prettier --check ./src --ignore-path ../../.prettierignore"
},
"dependencies": {
"@typebot.io/theme": "workspace:*",
"@braintree/sanitize-url": "7.0.1",
"@chakra-ui/anatomy": "2.1.1",
"@chakra-ui/react": "2.7.1",
@ -45,6 +44,7 @@
"@typebot.io/env": "workspace:*",
"@typebot.io/js": "workspace:*",
"@typebot.io/nextjs": "workspace:*",
"@typebot.io/theme": "workspace:*",
"@udecode/cn": "29.0.1",
"@udecode/plate-basic-marks": "30.5.3",
"@udecode/plate-common": "30.4.5",
@ -68,9 +68,10 @@
"framer-motion": "10.3.0",
"google-auth-library": "8.9.0",
"google-spreadsheet": "4.1.1",
"ky": "1.2.3",
"immer": "10.0.2",
"isolated-vm": "4.7.2",
"jsonwebtoken": "9.0.1",
"ky": "1.2.3",
"libphonenumber-js": "1.10.37",
"micro": "10.0.1",
"micro-cors": "0.1.1",
@ -123,13 +124,13 @@
"@types/qs": "6.9.7",
"@types/react": "18.2.15",
"@types/tinycolor2": "1.4.3",
"dotenv": "16.4.5",
"dotenv-cli": "7.4.1",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
"next-runtime-env": "1.6.2",
"superjson": "1.12.4",
"typescript": "5.4.5",
"zod": "3.22.4",
"dotenv": "16.4.5"
"zod": "3.22.4"
}
}

View File

@ -22,7 +22,7 @@ You need to write `console.log({{My variable}})` instead of `console.log("{{My v
If you want to set a variable value with Javascript, the [Set variable block](./set-variable) is more appropriate for most cases.
However, if you'd like to set variables with the script blocks, you can use the `setVariable` function in your script:
However, if you'd like to set variables in a Script block, you can use the `setVariable` function in your script:
```js
if({{My variable}} === 'foo') {
@ -34,6 +34,23 @@ if({{My variable}} === 'foo') {
The `setVariable` function is only available in script executed on the server, so it won't work if the `Execute on client?` is checked.
## Limitations on scripts executed on server
Because the script is executed on a isolated and secured environment, there are some limitations.
- Global functions like `console.log`, `setTimeout`, `setInterval`, etc. are not available
- The `fetch` function behavior is slightly different from the native `fetch` function. You just have to skip the `await response.text()` or `await response.json()` part.
```js
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
// const data = await response.text() 👈 You can remove this line, it is executed by default under the hood.
```
So `response` will always have the `string` type even if the the request returns a JSON object. If you know that the response is a JSON object, you can parse it using `JSON.parse(response)`.
- You can't use `import` or `require` to import external libraries
- You don't have access to browser APIs like `window`, `document`, `localStorage`, etc. If you need to use browser APIs, you should check the `Execute on client?` option so that the script is executed on the user's browser.
## Examples
### Reload page

View File

@ -50,21 +50,14 @@ const nextConfig = {
output: 'standalone',
experimental: {
outputFileTracingRoot: join(__dirname, '../../'),
serverComponentsExternalPackages: ['isolated-vm'],
},
webpack: (config, { nextRuntime }) => {
if (nextRuntime === 'nodejs') return config
webpack: (config, { isServer }) => {
if (isServer) return config
if (nextRuntime === 'edge') {
config.resolve.alias['minio'] = false
config.resolve.alias['got'] = false
config.resolve.alias['qrcode'] = false
return config
}
// These packages are imports from the integrations definition files that can be ignored for the client.
config.resolve.alias['minio'] = false
config.resolve.alias['got'] = false
config.resolve.alias['openai'] = false
config.resolve.alias['qrcode'] = false
config.resolve.alias['isolated-vm'] = false
return config
},
async redirects() {

View File

@ -26,6 +26,7 @@
"cors": "2.8.5",
"google-spreadsheet": "4.1.1",
"got": "12.6.0",
"isolated-vm": "4.7.2",
"ky": "1.2.3",
"next": "14.1.0",
"nextjs-cors": "2.1.2",
@ -37,7 +38,6 @@
"stripe": "12.13.0"
},
"devDependencies": {
"dotenv": "16.4.5",
"@faire/mjml-react": "3.3.0",
"@paralleldrive/cuid2": "2.2.1",
"@playwright/test": "1.43.1",
@ -46,6 +46,8 @@
"@typebot.io/forge": "workspace:*",
"@typebot.io/forge-repository": "workspace:*",
"@typebot.io/lib": "workspace:*",
"@typebot.io/playwright": "workspace:*",
"@typebot.io/results": "workspace:*",
"@typebot.io/schemas": "workspace:*",
"@typebot.io/tsconfig": "workspace:*",
"@typebot.io/variables": "workspace:*",
@ -55,8 +57,8 @@
"@types/papaparse": "5.3.7",
"@types/qs": "6.9.7",
"@types/react": "18.2.15",
"dotenv-cli": "7.4.1",
"dotenv": "16.4.5",
"dotenv-cli": "7.4.1",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
"google-auth-library": "8.9.0",
@ -64,8 +66,6 @@
"papaparse": "5.4.1",
"superjson": "1.12.4",
"typescript": "5.4.5",
"zod": "3.22.4",
"@typebot.io/playwright": "workspace:*",
"@typebot.io/results": "workspace:*"
"zod": "3.22.4"
}
}

View File

@ -11,7 +11,7 @@ import { SessionState } from '@typebot.io/schemas/features/chat/sessionState'
import { ExecuteIntegrationResponse } from '../../../types'
import { parseVariables } from '@typebot.io/variables/parseVariables'
import { updateVariablesInSession } from '@typebot.io/variables/updateVariablesInSession'
import vm from 'vm'
import { createHttpReqResponseMappingRunner } from '@typebot.io/variables/codeRunners'
type Props = {
state: SessionState
@ -50,19 +50,21 @@ export const resumeWebhookExecution = ({
}
)
let run: (varMapping: string) => unknown
if (block.options?.responseVariableMapping) {
run = createHttpReqResponseMappingRunner(response)
}
const newVariables = block.options?.responseVariableMapping?.reduce<
VariableWithUnknowValue[]
>((newVariables, varMapping) => {
if (!varMapping?.bodyPath || !varMapping.variableId) return newVariables
if (!varMapping?.bodyPath || !varMapping.variableId || !run)
return newVariables
const existingVariable = typebot.variables.find(byId(varMapping.variableId))
if (!existingVariable) return newVariables
const sandbox = vm.createContext({
data: response,
})
try {
const value: unknown = vm.runInContext(
`data.${parseVariables(typebot.variables)(varMapping?.bodyPath)}`,
sandbox
const value: unknown = run(
parseVariables(typebot.variables)(varMapping?.bodyPath)
)
return [...newVariables, { ...existingVariable, value }]
} catch (err) {

View File

@ -8,7 +8,6 @@ import {
import { byId, isEmpty } from '@typebot.io/lib'
import { ExecuteLogicResponse } from '../../../types'
import { parseScriptToExecuteClientSideAction } from '../script/executeScript'
import { parseGuessedValueType } from '@typebot.io/variables/parseGuessedValueType'
import { parseVariables } from '@typebot.io/variables/parseVariables'
import { updateVariablesInSession } from '@typebot.io/variables/updateVariablesInSession'
import { createId } from '@paralleldrive/cuid2'
@ -19,7 +18,7 @@ import {
} from '@typebot.io/logic/computeResultTranscript'
import prisma from '@typebot.io/lib/prisma'
import { sessionOnlySetVariableOptions } from '@typebot.io/schemas/features/blocks/logic/setVariable/constants'
import vm from 'vm'
import { createCodeRunner } from '@typebot.io/variables/codeRunners'
export const executeSetVariable = async (
state: SessionState,
@ -97,17 +96,11 @@ const evaluateSetVariableExpression =
if (isSingleVariable) return parseVariables(variables)(str)
// To avoid octal number evaluation
if (!isNaN(str as unknown as number) && /0[^.].+/.test(str)) return str
const evaluating = parseVariables(variables, { fieldToParse: 'id' })(
`(function() {${str.includes('return ') ? str : 'return ' + str}})()`
)
try {
const sandbox = vm.createContext({
...Object.fromEntries(
variables.map((v) => [v.id, parseGuessedValueType(v.value)])
),
fetch,
})
return vm.runInContext(evaluating, sandbox)
const body = parseVariables(variables, { fieldToParse: 'id' })(str)
return createCodeRunner({ variables })(
body.includes('return ') ? body : `return ${body}`
)
} catch (err) {
return parseVariables(variables)(str)
}

View File

@ -32,7 +32,8 @@
"nodemailer": "6.9.8",
"openai": "4.47.1",
"qs": "6.11.2",
"stripe": "12.13.0"
"stripe": "12.13.0",
"isolated-vm": "4.7.2"
},
"devDependencies": {
"@typebot.io/forge": "workspace:*",

View File

@ -0,0 +1,55 @@
import { Variable } from './types'
import ivm from 'isolated-vm'
import { parseGuessedValueType } from './parseGuessedValueType'
export const createCodeRunner = ({ variables }: { variables: Variable[] }) => {
const isolate = new ivm.Isolate()
const context = isolate.createContextSync()
const jail = context.global
jail.setSync('global', jail.derefInto())
variables.forEach((v) => {
jail.setSync(v.id, parseTransferrableValue(parseGuessedValueType(v.value)))
})
return (code: string) =>
context.evalClosureSync(
`return (function() {
return new Function($0)();
}())`,
[code],
{ result: { copy: true }, timeout: 10000 }
)
}
export const createHttpReqResponseMappingRunner = (response: any) => {
const isolate = new ivm.Isolate()
const context = isolate.createContextSync()
const jail = context.global
jail.setSync('global', jail.derefInto())
jail.setSync('response', new ivm.ExternalCopy(response).copyInto())
return (expression: string) => {
return context.evalClosureSync(
`globalThis.evaluateExpression = function(expression) {
try {
// Use Function to safely evaluate the expression
const func = new Function('statusCode', 'data', 'return (' + expression + ')');
return func(response.statusCode, response.data);
} catch (err) {
throw new Error('Invalid expression: ' + err.message);
}
};
return evaluateExpression.apply(null, arguments);`,
[expression],
{
result: { copy: true },
timeout: 10000,
}
)
}
}
const parseTransferrableValue = (value: unknown) => {
if (typeof value === 'object') {
return new ivm.ExternalCopy(value).copyInto()
}
return value
}

View File

@ -4,9 +4,9 @@ import { parseGuessedValueType } from './parseGuessedValueType'
import { isDefined } from '@typebot.io/lib'
import { safeStringify } from '@typebot.io/lib/safeStringify'
import { Variable } from './types'
import vm from 'vm'
import ivm from 'isolated-vm'
const defaultTimeout = 10
const defaultTimeout = 10 * 1000
type Props = {
variables: Variable[]
@ -19,9 +19,9 @@ export const executeFunction = async ({
body,
args: initialArgs,
}: Props) => {
const parsedBody = `(async function() {${parseVariables(variables, {
const parsedBody = parseVariables(variables, {
fieldToParse: 'id',
})(body)}})()`
})(body)
const args = (
extractVariablesFromText(variables)(body).map((variable) => ({
@ -40,21 +40,40 @@ export const executeFunction = async ({
updatedVariables[key] = value
}
const context = vm.createContext({
...Object.fromEntries(args.map(({ id, value }) => [id, value])),
setVariable,
fetch,
setTimeout,
const isolate = new ivm.Isolate()
const context = isolate.createContextSync()
const jail = context.global
jail.setSync('global', jail.derefInto())
context.evalClosure(
'globalThis.setVariable = (...args) => $0.apply(undefined, args, { arguments: { copy: true }, promise: true, result: { copy: true, promise: true } })',
[new ivm.Reference(setVariable)]
)
context.evalClosure(
'globalThis.fetch = (...args) => $0.apply(undefined, args, { arguments: { copy: true }, promise: true, result: { copy: true, promise: true } })',
[
new ivm.Reference(async (...args: any[]) => {
// @ts-ignore
const response = await fetch(...args)
return response.text()
}),
]
)
args.forEach(({ id, value }) => {
jail.setSync(id, value)
})
const timeout = new Timeout()
const run = (code: string) =>
context.evalClosure(
`return (async function() {
const AsyncFunction = async function () {}.constructor;
return new AsyncFunction($0)();
}())`,
[code],
{ result: { copy: true, promise: true }, timeout: defaultTimeout }
)
try {
const output: unknown = await timeout.wrap(
await vm.runInContext(parsedBody, context),
defaultTimeout * 1000
)
timeout.clear()
const output = await run(parsedBody)
console.log('Output', output)
return {
output: safeStringify(output) ?? '',
newVariables: Object.entries(updatedVariables)
@ -86,33 +105,3 @@ export const executeFunction = async ({
}
}
}
class Timeout {
private ids: NodeJS.Timeout[]
constructor() {
this.ids = []
}
private set = (delay: number) =>
new Promise((_, reject) => {
const id = setTimeout(() => {
reject(`Script ${defaultTimeout}s timeout reached`)
this.clear(id)
}, delay)
this.ids.push(id)
})
wrap = (promise: Promise<any>, delay: number) =>
Promise.race([promise, this.set(delay)])
clear = (...ids: NodeJS.Timeout[]) => {
this.ids = this.ids.filter((id) => {
if (ids.includes(id)) {
clearTimeout(id)
return false
}
return true
})
}
}

View File

@ -5,6 +5,7 @@
"private": true,
"dependencies": {
"@typebot.io/lib": "workspace:*",
"@typebot.io/tsconfig": "workspace:*"
"@typebot.io/tsconfig": "workspace:*",
"isolated-vm": "4.7.2"
}
}

View File

@ -1,8 +1,7 @@
import { safeStringify } from '@typebot.io/lib/safeStringify'
import { isDefined, isNotDefined } from '@typebot.io/lib/utils'
import { parseGuessedValueType } from './parseGuessedValueType'
import { Variable, VariableWithValue } from './types'
import vm from 'vm'
import { createCodeRunner } from './codeRunners'
export type ParseVariablesOptions = {
fieldToParse?: 'value' | 'id'
@ -73,18 +72,10 @@ const evaluateInlineCode = (
code: string,
{ variables }: { variables: Variable[] }
) => {
const evaluating = parseVariables(variables, { fieldToParse: 'id' })(
`(function() {
${code.includes('return ') ? code : 'return ' + code}
})()`
)
try {
const sandbox = vm.createContext({
...Object.fromEntries(
variables.map((v) => [v.id, parseGuessedValueType(v.value)])
),
})
return vm.runInContext(evaluating, sandbox)
return createCodeRunner({ variables })(
parseVariables(variables, { fieldToParse: 'id' })(code)
)
} catch (err) {
return parseVariables(variables)(code)
}

143
pnpm-lock.yaml generated
View File

@ -197,6 +197,9 @@ importers:
immer:
specifier: 10.0.2
version: 10.0.2
isolated-vm:
specifier: 4.7.2
version: 4.7.2
jsonwebtoken:
specifier: 9.0.1
version: 9.0.1
@ -550,6 +553,9 @@ importers:
got:
specifier: 12.6.0
version: 12.6.0
isolated-vm:
specifier: 4.7.2
version: 4.7.2
ky:
specifier: 1.2.3
version: 1.2.3
@ -744,6 +750,9 @@ importers:
google-spreadsheet:
specifier: 4.1.1
version: 4.1.1(google-auth-library@8.9.0)
isolated-vm:
specifier: 4.7.2
version: 4.7.2
ky:
specifier: 1.2.3
version: 1.2.3
@ -1948,6 +1957,9 @@ importers:
'@typebot.io/tsconfig':
specifier: workspace:*
version: link:../tsconfig
isolated-vm:
specifier: 4.7.2
version: 4.7.2
packages:
@ -11994,6 +12006,10 @@ packages:
optionalDependencies:
fsevents: 2.3.3
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
@ -12778,6 +12794,11 @@ packages:
optional: true
dev: true
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@ -12875,7 +12896,6 @@ packages:
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
dev: true
/detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
@ -13125,6 +13145,12 @@ packages:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
/end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
dev: false
/engine.io-client@6.5.3:
resolution: {integrity: sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==}
dependencies:
@ -14196,6 +14222,11 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
dev: false
/expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -14541,6 +14572,10 @@ packages:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: false
/fs-extra@11.2.0:
resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
engines: {node: '>=14.14'}
@ -14676,6 +14711,10 @@ packages:
dependencies:
resolve-pkg-maps: 1.0.0
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -15773,6 +15812,14 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isolated-vm@4.7.2:
resolution: {integrity: sha512-JVEs5gzWObzZK5+OlBplCdYSpokMcdhLSs/xWYYxmYWVfOOFF4oZJsYh7E/FmfX8e7gMioXMpMMeEyX1afuKrg==}
engines: {node: '>=16.0.0'}
requiresBuild: true
dependencies:
prebuild-install: 7.1.2
dev: false
/isomorphic-fetch@3.0.0:
resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==}
dependencies:
@ -18227,6 +18274,10 @@ packages:
transitivePeerDependencies:
- encoding
/mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: false
/mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
@ -18292,6 +18343,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
/natural-compare-lite@1.4.0:
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
dev: true
@ -18453,6 +18508,13 @@ packages:
dependencies:
lower-case: 1.1.4
/node-abi@3.62.0:
resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
engines: {node: '>=10'}
dependencies:
semver: 7.6.0
dev: false
/node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
@ -19587,6 +19649,25 @@ packages:
resolution: {integrity: sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==}
dev: false
/prebuild-install@7.1.2:
resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
engines: {node: '>=10'}
hasBin: true
dependencies:
detect-libc: 2.0.2
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 1.0.2
node-abi: 3.62.0
pump: 3.0.0
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -19721,6 +19802,13 @@ packages:
is-ip: 3.1.0
dev: true
/pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
dev: false
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@ -19819,6 +19907,16 @@ packages:
iconv-lite: 0.4.24
unpipe: 1.0.0
/rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: false
/react-clientside-effect@1.2.6(react@18.2.0):
resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==}
peerDependencies:
@ -20874,6 +20972,18 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
dev: false
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
dev: false
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies:
@ -21353,6 +21463,11 @@ packages:
min-indent: 1.0.1
dev: false
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@ -21684,6 +21799,26 @@ packages:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
/tar-fs@2.1.1:
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 2.2.0
dev: false
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
/tar@6.2.0:
resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
engines: {node: '>=10'}
@ -22065,6 +22200,12 @@ packages:
fsevents: 2.3.3
dev: true
/tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: false
/turbo-darwin-64@1.11.3:
resolution: {integrity: sha512-IsOOg2bVbIt3o/X8Ew9fbQp5t1hTHN3fGNQYrPQwMR2W1kIAC6RfbVD4A9OeibPGyEPUpwOH79hZ9ydFH5kifw==}
cpu: [x64]