From e302a5da02b1a795564d5b2d3cb0db8bc9e551da Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Wed, 23 Oct 2024 18:11:56 +0300 Subject: [PATCH 01/75] function crons local done --- package-lock.json | 1 - src/commands/local.ts | 65 +++++++++++++++++++++++------ src/projectConfiguration/yaml/v2.ts | 23 ++++++++++ 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index b69d6fc67..0f2b75a01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.5", diff --git a/src/commands/local.ts b/src/commands/local.ts index 157df2166..4c03b8f0d 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -83,6 +83,7 @@ import fsExtra from "fs-extra/esm"; import { DeployCodeFunctionResponse } from "../models/deployCodeResponse.js"; import { enableAuthentication, + evaluateResource, getOrCreateDatabase, getOrCreateEmptyProject, } from "./deploy/utils.js"; @@ -525,7 +526,12 @@ async function startBackendWatcher( ); // Start cron jobs - const crons = startCronJobs(projectConfiguration, processForUnits); + const crons = await startCronJobs( + projectConfiguration, + processForUnits, + yamlProjectConfiguration, + options.port, + ); log.info( "\x1b[36m%s\x1b[0m", "Your local server is running and the SDK was successfully generated!", @@ -998,40 +1004,38 @@ function getProjectFunctions( } export type LocalEnvCronHandler = { - className: string; - methodName: string; cronString: string; cronObject: cron.ScheduledTask | null; - process: UnitProcess; }; -function startCronJobs( +async function startCronJobs( projectConfiguration: ProjectConfiguration, processForUnits: Map, -): LocalEnvCronHandler[] { + yamlProjectConfiguration: YamlProjectConfiguration, + port?: number, +): Promise { const cronHandlers: LocalEnvCronHandler[] = []; for (const classElement of projectConfiguration.classes) { const methods = classElement.methods; for (const method of methods) { if (method.type === TriggerType.cron && method.cronString) { const cronHandler: LocalEnvCronHandler = { - className: classElement.name, - methodName: method.name, cronString: rectifyCronString(method.cronString), cronObject: null, - process: processForUnits.get(classElement.name)!, }; + const process = processForUnits.get(classElement.name)!; + cronHandler.cronObject = cron.schedule(cronHandler.cronString, () => { const reqToFunction = { genezioEventType: "cron", - methodName: cronHandler.methodName, + methodName: method.name, cronString: cronHandler.cronString, }; void communicateWithProcess( - cronHandler.process, - cronHandler.className, + process, + classElement.name, reqToFunction, processForUnits, ); @@ -1043,6 +1047,43 @@ function startCronJobs( } } + if (yamlProjectConfiguration.services && yamlProjectConfiguration.services.crons) { + for (const cronService of yamlProjectConfiguration.services.crons) { + const baseURL = await evaluateResource( + yamlProjectConfiguration, + cronService.url, + "local", + undefined, + { + isLocal: true, + port: port, + }, + ); + const endpoint = cronService.endpoint?.replace(/^\//, ""); + const cronString = cronService.cronString; + let url: string; + if (endpoint) { + url = `${baseURL}/${endpoint}`; + } else { + url = baseURL; + } + + const cronHandler: LocalEnvCronHandler = { + cronString: rectifyCronString(cronString), + cronObject: null, + }; + + cronHandler.cronObject = cron.schedule(cronHandler.cronString, async () => { + log.info("DEBUG: trigger cron: " + cronHandler.cronString + " on URL " + url); + return await axios.post(url); + }); + + cronHandler.cronObject.start(); + + cronHandlers.push(cronHandler); + } + } + return cronHandlers; } diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 8aebecaa7..727da2bb5 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -130,6 +130,28 @@ function parseGenezioConfig(config: unknown) { }), ); + const cronSchema = zod + .object({ + url: zod.string(), + cronString: zod.string(), + endpoint: zod.string().optional(), + }) + .refine(({ cronString }) => { + if (cronString && !isValidCron(cronString)) { + return false; + } + + return true; + }, "The cronString is not valid. Check https://crontab.guru/ for more information.") + .refine(({ cronString }) => { + const cronParts = cronString?.split(" "); + if (cronParts && cronParts[2] != "*" && cronParts[4] != "*") { + return false; + } + + return true; + }, "The day of the month and day of the week cannot be specified at the same time."); + const redirectUrlSchema = zod.string(); const authEmailSettings = zod.object({ @@ -171,6 +193,7 @@ function parseGenezioConfig(config: unknown) { databases: zod.array(databaseSchema).optional(), email: zod.boolean().optional(), authentication: authenticationSchema.optional(), + crons: zod.array(cronSchema).optional(), }); const backendSchema = zod.object({ From b5b822229f3396f93fa026dc4976a0e2c4730409 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 25 Oct 2024 16:03:15 +0300 Subject: [PATCH 02/75] add name to crons --- src/projectConfiguration/yaml/v2.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 727da2bb5..ede0d8852 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -132,6 +132,7 @@ function parseGenezioConfig(config: unknown) { const cronSchema = zod .object({ + name: zod.string(), url: zod.string(), cronString: zod.string(), endpoint: zod.string().optional(), From 68f7fc7229c5365b10b60bac16e875f7947dd716 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Thu, 7 Nov 2024 11:31:46 +0200 Subject: [PATCH 03/75] use name for functions in yaml --- src/commands/local.ts | 7 ++++--- src/projectConfiguration/yaml/v2.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 4c03b8f0d..8054c8bad 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1049,9 +1049,9 @@ async function startCronJobs( if (yamlProjectConfiguration.services && yamlProjectConfiguration.services.crons) { for (const cronService of yamlProjectConfiguration.services.crons) { - const baseURL = await evaluateResource( + const functionName = await evaluateResource( yamlProjectConfiguration, - cronService.url, + cronService.function, "local", undefined, { @@ -1060,7 +1060,8 @@ async function startCronJobs( }, ); const endpoint = cronService.endpoint?.replace(/^\//, ""); - const cronString = cronService.cronString; + const cronString = cronService.schedule; + const baseURL = `http://localhost:${port}/.functions/${functionName}`; let url: string; if (endpoint) { url = `${baseURL}/${endpoint}`; diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index ede0d8852..1742a75ef 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -133,19 +133,19 @@ function parseGenezioConfig(config: unknown) { const cronSchema = zod .object({ name: zod.string(), - url: zod.string(), - cronString: zod.string(), + function: zod.string(), + schedule: zod.string(), endpoint: zod.string().optional(), }) - .refine(({ cronString }) => { - if (cronString && !isValidCron(cronString)) { + .refine(({ schedule }) => { + if (schedule && !isValidCron(schedule)) { return false; } return true; }, "The cronString is not valid. Check https://crontab.guru/ for more information.") - .refine(({ cronString }) => { - const cronParts = cronString?.split(" "); + .refine(({ schedule }) => { + const cronParts = schedule?.split(" "); if (cronParts && cronParts[2] != "*" && cronParts[4] != "*") { return false; } From 7033a1c296b41be128c434b1939b28c035a7c5bc Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Thu, 7 Nov 2024 17:40:35 +0200 Subject: [PATCH 04/75] sync crons on deployment --- src/commands/deploy/genezio.ts | 45 +++++++++++++++++++++++++++++++ src/models/requests.ts | 48 ++++++++++++++++++++++++++++++++++ src/requests/crons.ts | 16 ++++++++++++ src/requests/function.ts | 30 ++++++++++----------- 4 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 src/requests/crons.ts diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index a6906eec0..eb5460058 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -74,6 +74,7 @@ import { enableAuthentication, uploadUserCode, setAuthenticationEmailTemplates, + evaluateResource, } from "./utils.js"; import { disableEmailIntegration, @@ -84,6 +85,9 @@ import { expandEnvironmentVariables, findAnEnvFile } from "../../utils/environme import { getProjectEnvFromProjectByName } from "../../requests/getProjectInfoByName.js"; import { getFunctionHandlerProvider } from "../../utils/getFunctionHandlerProvider.js"; import { getFunctionEntryFilename } from "../../utils/getFunctionEntryFilename.js"; +import { getFunctions } from "../../requests/function.js"; +import { CronDetails } from "../../models/requests.js"; +import { syncCrons } from "../../requests/crons.js"; export async function genezioDeploy(options: GenezioDeployOptions) { const configIOController = new YamlConfigurationIOController(options.config, { @@ -228,6 +232,47 @@ export async function genezioDeploy(options: GenezioDeployOptions) { }); } + if (configuration.services?.crons) { + const res = await getFunctions(deployClassesResult?.projectEnvId || "").catch(() => { + throw new UserError("Something went wrong while fetching the cron functions."); + }); + const crons: CronDetails[] = []; + for (const cron of configuration.services.crons) { + let cronFound = false; + const yamlFunctionName = await evaluateResource( + configuration, + cron.function, + options.stage || "prod", + undefined, + undefined, + ); + for (const deployedFunction of res.functions) { + if (deployedFunction.name === yamlFunctionName) { + crons.push({ + name: cron.name, + url: deployedFunction.cloudUrl, + endpoint: cron.endpoint || "", + cronString: cron.schedule, + }); + cronFound = true; + break; + } + } + if (!cronFound) { + throw new UserError( + `Function ${yamlFunctionName} not found in the deployed functions. Please make sure the function is deployed before adding it to the cron.`, + ); + } + } + await syncCrons({ + projectName: projectName, + stageName: options.stage || "prod", + crons: crons, + }).catch(() => { + throw new UserError("Something went wrong while syncing the cron jobs."); + }); + } + const frontendUrls = []; if (configuration.frontend && !options.backend) { const frontends = configuration.frontend; diff --git a/src/models/requests.ts b/src/models/requests.ts index b003307ce..a80a6b41f 100644 --- a/src/models/requests.ts +++ b/src/models/requests.ts @@ -184,3 +184,51 @@ export type SetEmailTemplatesResponse = { variables: string[]; }[]; }; + +export type FunctionDetails = { + id: string; + name: string; + projectName: string; + status: string; + cloudUrl: string; + cloudDeploymentId: string; + createdAt: number; + updatedAt: number; +}; + +export type GetFunctionsResponse = { + status: string; + functions: FunctionDetails[]; +}; + +export type CreateFunctionRequest = { + projectName: string; + stageName: string; + function: { + name: string; + language: string; + entryFile: string; + }; +}; + +export type CreateFunctionResponse = { + status: string; + functionId: string; +}; + +export type CronDetails = { + name: string; + url: string; + endpoint: string; + cronString: string; +}; + +export type SyncCronsRequest = { + projectName: string; + stageName: string; + crons: CronDetails[]; +}; + +export type SyncCronsResponse = { + status: string; +}; diff --git a/src/requests/crons.ts b/src/requests/crons.ts new file mode 100644 index 000000000..d6b5f079d --- /dev/null +++ b/src/requests/crons.ts @@ -0,0 +1,16 @@ +import { SyncCronsRequest, SyncCronsResponse } from "../models/requests.js"; +import sendRequest from "../utils/requests.js"; + +export async function syncCrons(request: SyncCronsRequest): Promise { + const { projectName, stageName, crons } = request; + + const data: string = JSON.stringify({ + projectName: projectName, + stageName: stageName, + crons: crons, + }); + + const syncCronsResponse = (await sendRequest("POST", `crons`, data)) as SyncCronsResponse; + + return syncCronsResponse; +} diff --git a/src/requests/function.ts b/src/requests/function.ts index d2e28f859..321afc61e 100644 --- a/src/requests/function.ts +++ b/src/requests/function.ts @@ -1,20 +1,10 @@ +import { + CreateFunctionRequest, + CreateFunctionResponse, + GetFunctionsResponse, +} from "../models/requests.js"; import sendRequest from "../utils/requests.js"; -export type CreateFunctionRequest = { - projectName: string; - stageName: string; - function: { - name: string; - language: string; - entryFile: string; - }; -}; - -export type CreateFunctionResponse = { - status: string; - functionId: string; -}; - export async function createFunction( request: CreateFunctionRequest, ): Promise { @@ -42,3 +32,13 @@ export async function createFunction( return createFunctionResponse; } + +export async function getFunctions(envId: string): Promise { + const getFunctionsResponse = (await sendRequest( + "GET", + `functions/all/${envId}`, + "", + )) as GetFunctionsResponse; + + return getFunctionsResponse; +} From 44bf97a0d0e8e33c132a75cc0002e3ed45f9a8a3 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 8 Nov 2024 14:08:27 +0200 Subject: [PATCH 05/75] handle crons/functions with same name in yaml --- src/commands/deploy/genezio.ts | 10 ++++- src/commands/local.ts | 7 +++- src/projectConfiguration/yaml/v2.ts | 60 ++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index eb5460058..254cfae75 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -247,7 +247,7 @@ export async function genezioDeploy(options: GenezioDeployOptions) { undefined, ); for (const deployedFunction of res.functions) { - if (deployedFunction.name === yamlFunctionName) { + if (deployedFunction.name === `function-${yamlFunctionName}`) { crons.push({ name: cron.name, url: deployedFunction.cloudUrl, @@ -271,6 +271,14 @@ export async function genezioDeploy(options: GenezioDeployOptions) { }).catch(() => { throw new UserError("Something went wrong while syncing the cron jobs."); }); + } else { + await syncCrons({ + projectName: projectName, + stageName: options.stage || "prod", + crons: [], + }).catch(() => { + throw new UserError("Something went wrong while syncing the cron jobs."); + }); } const frontendUrls = []; diff --git a/src/commands/local.ts b/src/commands/local.ts index 8054c8bad..0a4eb83af 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1075,7 +1075,12 @@ async function startCronJobs( }; cronHandler.cronObject = cron.schedule(cronHandler.cronString, async () => { - log.info("DEBUG: trigger cron: " + cronHandler.cronString + " on URL " + url); + log.info( + "DEBUG: trigger cron: " + + cronHandler.cronString + + " on function " + + functionName, + ); return await axios.post(url); }); diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 1742a75ef..b1e7bc1b9 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -190,26 +190,48 @@ function parseGenezioConfig(config: unknown) { settings: authEmailSettings.optional(), }); - const servicesSchema = zod.object({ - databases: zod.array(databaseSchema).optional(), - email: zod.boolean().optional(), - authentication: authenticationSchema.optional(), - crons: zod.array(cronSchema).optional(), - }); + const servicesSchema = zod + .object({ + databases: zod.array(databaseSchema).optional(), + email: zod.boolean().optional(), + authentication: authenticationSchema.optional(), + crons: zod.array(cronSchema).optional(), + }) + .refine(({ crons }) => { + const cronNamesMap = new Map(); + for (const cron of crons || []) { + if (cronNamesMap.has(cron.name)) { + return false; + } + cronNamesMap.set(cron.name, cron.name); + } + return true; + }, `You can't have two crons with the same name.`); - const backendSchema = zod.object({ - path: zod.string(), - language: languageSchema, - environment: environmentSchema.optional(), - scripts: zod - .object({ - deploy: scriptSchema, - local: scriptSchema, - }) - .optional(), - classes: zod.array(classSchema).optional(), - functions: zod.array(functionsSchema).optional(), - }); + const backendSchema = zod + .object({ + path: zod.string(), + language: languageSchema, + environment: environmentSchema.optional(), + scripts: zod + .object({ + deploy: scriptSchema, + local: scriptSchema, + }) + .optional(), + classes: zod.array(classSchema).optional(), + functions: zod.array(functionsSchema).optional(), + }) + .refine(({ functions }) => { + const functionNamesMap = new Map(); + for (const func of functions || []) { + if (functionNamesMap.has(func.name)) { + return false; + } + functionNamesMap.set(func.name, func.name); + } + return true; + }, `You can't have two functions with the same name.`); const frontendSchema = zod.object({ name: zod.string().optional(), From 579715a9507c8d6f1f09c7ba4321563712dce7fd Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 12 Nov 2024 15:12:55 +0200 Subject: [PATCH 06/75] Add python metadata --- src/cloudAdapter/cloudAdapter.ts | 15 ++++++++++++--- src/commands/deploy/docker/deploy.ts | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/cloudAdapter/cloudAdapter.ts b/src/cloudAdapter/cloudAdapter.ts index 86c202ea8..2489792b0 100644 --- a/src/cloudAdapter/cloudAdapter.ts +++ b/src/cloudAdapter/cloudAdapter.ts @@ -14,9 +14,18 @@ export enum GenezioCloudInputType { } export type GenezioFunctionMetadata = { - cwd: string; - cmd: string; - http_port: string; + container?: ContainerMetadata; + python?: PythonMetadata; +}; + +export type ContainerMetadata = { + cmd?: string; + cwd?: string; + http_port?: string; +}; + +export type PythonMetadata = { + app_name?: string; }; export type GenezioCloudInput = diff --git a/src/commands/deploy/docker/deploy.ts b/src/commands/deploy/docker/deploy.ts index 519161dcb..7f4d8df09 100644 --- a/src/commands/deploy/docker/deploy.ts +++ b/src/commands/deploy/docker/deploy.ts @@ -10,7 +10,10 @@ import { import { CloudProviderIdentifier } from "../../../models/cloudProviderIdentifier.js"; import { getCloudProvider } from "../../../requests/getCloudProvider.js"; import { getCloudAdapter } from "../genezio.js"; -import { GenezioCloudInputType } from "../../../cloudAdapter/cloudAdapter.js"; +import { + GenezioCloudInputType, + GenezioFunctionMetadata, +} from "../../../cloudAdapter/cloudAdapter.js"; import { setEnvironmentVariables } from "../../../requests/setEnvironmentVariables.js"; import { FunctionType } from "../../../projectConfiguration/yaml/models.js"; import { createTemporaryFolder } from "../../../utils/file.js"; @@ -131,6 +134,13 @@ export async function dockerDeploy(options: GenezioDeployOptions) { const cloudProvider = await getCloudProvider(projectConfiguration.name); const cloudAdapter = getCloudAdapter(cloudProvider); + const metadata: GenezioFunctionMetadata = { + container: { + cmd: cmdEntryFile, + cwd: dockerWorkingDir, + http_port: port, + }, + }; const result = await cloudAdapter.deploy( [ { @@ -140,11 +150,7 @@ export async function dockerDeploy(options: GenezioDeployOptions) { archiveName: `genezio-${config.name}.tar`, entryFile: cmdEntryFile, unzippedBundleSize: 100, - metadata: { - cmd: cmdEntryFile, - cwd: dockerWorkingDir, - http_port: port, - }, + metadata: metadata, timeout: config.container!.timeout, storageSize: config.container!.storageSize, instanceSize: config.container!.instanceSize, From 64233fe544047d3dec1e0900ca451822ffa33b57 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 12 Nov 2024 17:33:28 +0200 Subject: [PATCH 07/75] remove httpServer handlers --- src/cloudAdapter/cloudAdapter.ts | 17 +- src/commands/deploy/docker/deploy.ts | 10 +- src/commands/deploy/genezio.ts | 19 +- src/commands/local.ts | 13 +- .../providers/HttpServerHandlerProvider.ts | 368 ------------------ src/models/projectConfiguration.ts | 4 +- src/projectConfiguration/yaml/v2.ts | 1 + src/utils/getFunctionHandlerProvider.ts | 22 +- 8 files changed, 50 insertions(+), 404 deletions(-) delete mode 100644 src/functionHandlerProvider/providers/HttpServerHandlerProvider.ts diff --git a/src/cloudAdapter/cloudAdapter.ts b/src/cloudAdapter/cloudAdapter.ts index 2489792b0..79c3d6049 100644 --- a/src/cloudAdapter/cloudAdapter.ts +++ b/src/cloudAdapter/cloudAdapter.ts @@ -13,21 +13,30 @@ export enum GenezioCloudInputType { FUNCTION = "function", } -export type GenezioFunctionMetadata = { - container?: ContainerMetadata; - python?: PythonMetadata; -}; +export type GenezioFunctionMetadata = ContainerMetadata | PythonMetadata | HttpServerMetadata; +export enum GenezioFunctionMetadataType { + Container = "container", + Python = "python", + HttpServer = "httpServer", +} export type ContainerMetadata = { + type: GenezioFunctionMetadataType.Container; cmd?: string; cwd?: string; http_port?: string; }; export type PythonMetadata = { + type: GenezioFunctionMetadataType.Python; app_name?: string; }; +export type HttpServerMetadata = { + type: GenezioFunctionMetadataType.HttpServer; + http_port?: string; +}; + export type GenezioCloudInput = | { type: GenezioCloudInputType.CLASS; diff --git a/src/commands/deploy/docker/deploy.ts b/src/commands/deploy/docker/deploy.ts index 7f4d8df09..7f5e09077 100644 --- a/src/commands/deploy/docker/deploy.ts +++ b/src/commands/deploy/docker/deploy.ts @@ -13,6 +13,7 @@ import { getCloudAdapter } from "../genezio.js"; import { GenezioCloudInputType, GenezioFunctionMetadata, + GenezioFunctionMetadataType, } from "../../../cloudAdapter/cloudAdapter.js"; import { setEnvironmentVariables } from "../../../requests/setEnvironmentVariables.js"; import { FunctionType } from "../../../projectConfiguration/yaml/models.js"; @@ -135,11 +136,10 @@ export async function dockerDeploy(options: GenezioDeployOptions) { const cloudProvider = await getCloudProvider(projectConfiguration.name); const cloudAdapter = getCloudAdapter(cloudProvider); const metadata: GenezioFunctionMetadata = { - container: { - cmd: cmdEntryFile, - cwd: dockerWorkingDir, - http_port: port, - }, + type: GenezioFunctionMetadataType.Container, + cmd: cmdEntryFile, + cwd: dockerWorkingDir, + http_port: port, }; const result = await cloudAdapter.deploy( [ diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index 839009918..2aa3996d2 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -38,6 +38,8 @@ import { GenezioCloudInput, GenezioCloudInputType, GenezioCloudOutput, + GenezioFunctionMetadata, + GenezioFunctionMetadataType, } from "../../cloudAdapter/cloudAdapter.js"; import { CloudProviderIdentifier } from "../../models/cloudProviderIdentifier.js"; import { GenezioDeployOptions } from "../../models/commandOptions.js"; @@ -627,8 +629,20 @@ export async function functionToCloudInput( } } + let metadata: GenezioFunctionMetadata | undefined; + if (functionElement.type === "httpServer") { + metadata = { + type: GenezioFunctionMetadataType.HttpServer, + http_port: functionElement.port, + }; + } + // Handle Python projects dependencies if (functionElement.language === "python") { + metadata = { + type: GenezioFunctionMetadataType.Python, + app_name: functionElement.handler, + }; // Requirements file must be in the root of the backend folder const requirementsPath = path.join(backendPath, "requirements.txt"); if (fs.existsSync(requirementsPath)) { @@ -670,7 +684,9 @@ export async function functionToCloudInput( ); } - await handlerProvider.write(tmpFolderPath, entryFileName, functionElement); + if (handlerProvider) { + await handlerProvider.write(tmpFolderPath, entryFileName, functionElement); + } debugLogger.debug(`Zip the directory ${tmpFolderPath}.`); @@ -691,6 +707,7 @@ export async function functionToCloudInput( instanceSize: functionElement.instanceSize, storageSize: functionElement.storageSize, maxConcurrentRequestsPerInstance: functionElement.maxConcurrentRequestsPerInstance, + metadata: metadata, }; } diff --git a/src/commands/local.ts b/src/commands/local.ts index 7f52cba30..941704af7 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -90,10 +90,6 @@ import { displayHint } from "../utils/strings.js"; import { enableEmailIntegration, getProjectIntegrations } from "../requests/integration.js"; import { expandEnvironmentVariables, findAnEnvFile } from "../utils/environmentVariables.js"; import { getFunctionHandlerProvider } from "../utils/getFunctionHandlerProvider.js"; -import { - HttpServerHandlerProvider, - HttpServerPythonHandlerProvider, -} from "../functionHandlerProvider/providers/HttpServerHandlerProvider.js"; import { getFunctionEntryFilename } from "../utils/getFunctionEntryFilename.js"; type UnitProcess = { @@ -641,12 +637,15 @@ async function startProcesses( ); // if handlerProvider is Http - if (handlerProvider instanceof HttpServerHandlerProvider) { + if ( + functionInfo.type === "httpServer" && + (functionInfo.language === "js" || functionInfo.language === "ts") + ) { log.error("We recommend to run the HTTP server with `node` or `npm start`."); process.exit(1); } - if (handlerProvider instanceof HttpServerPythonHandlerProvider) { + if (functionInfo.type === "httpServer" && functionInfo.language === "python") { log.error("We recommend to run the HTTP server with `python` or `python3`."); process.exit(1); } @@ -657,7 +656,7 @@ async function startProcesses( functionInfo.language as Language, "local_function_wrapper", ), - await handlerProvider.getLocalFunctionWrapperCode( + await handlerProvider!.getLocalFunctionWrapperCode( functionInfo.handler, functionInfo.entry, ), diff --git a/src/functionHandlerProvider/providers/HttpServerHandlerProvider.ts b/src/functionHandlerProvider/providers/HttpServerHandlerProvider.ts deleted file mode 100644 index 019b1b928..000000000 --- a/src/functionHandlerProvider/providers/HttpServerHandlerProvider.ts +++ /dev/null @@ -1,368 +0,0 @@ -import { writeToFile } from "../../utils/file.js"; -import { FunctionConfiguration } from "../../models/projectConfiguration.js"; -import { FunctionHandlerProvider } from "../functionHandlerProvider.js"; -import path from "path"; - -export class HttpServerHandlerProvider implements FunctionHandlerProvider { - async write( - outputPath: string, - handlerFileName: string, - functionConfiguration: FunctionConfiguration, - ): Promise { - const handlerContent = ` -import * as domain from "domain"; -import { createRequire } from "module"; -const require = createRequire(import.meta.url); -const http = require('http') - -const originalCreateServer = http.createServer; -let server; - -http.createServer = function(...args) { - server = originalCreateServer(...args); - return server -}; - -// Import the original app.js, but it will automatically start the server -const app = await import("./${functionConfiguration.entry}"); - - -async function sendRequest(event) { - return new Promise(async (resolve) => { - const req = new http.IncomingMessage(); - req.method = event.http.method; - req.url = \`\${event.http.path}\${event.url.search}\`; - - const http2CompliantHeaders = {}; - for (const header in event.headers) { - http2CompliantHeaders[header.toLowerCase()] = event.headers[header]; - } - - req.headers = http2CompliantHeaders; - - req.body = event.body; - req.connection = { - remoteAddress: event.http.sourceIp - } - - const res = new http.ServerResponse(req); - - res.writeHead = (status, headersLocal) => { - event.responseStream.statusCode = res.statusCode; - event.responseStream.writeHead(status, headersLocal); - } - - res.write = data => { - event.responseStream.statusCode = res.statusCode; - event.responseStream.write(data); - } - - res.end = data => { - event.responseStream.statusCode = res.statusCode; - event.responseStream.end(data); - resolve(); - } - - res.setHeader = (name, value) => { - event.responseStream.setHeader(name, value); - } - - res.getHeader = name => { - return event.responseStream.getHeader(name); - } - - res.getHeaderNames = () => { - return event.responseStream.getHeaderNames(); - } - - res.removeHeader = name => { - event.responseStream.removeHeader(name); - } - - const operationId = process.domain ? process.domain.operationId : "unknown"; - const reqDomain = domain.create(); - - reqDomain.operationId = operationId; - reqDomain.on("error", err => { - console.error(err); - try { - res.statusCode = 500; - if (process.env.GENEZIO_DEBUG_MODE === "true") { - res.end(err.toString()); - } else { - res.end("Internal Server Error"); - } - } catch (err) { - console.error("Error:", err); - } - }); - - reqDomain.run(() => { - server.emit("request", req, res); - req.emit("data", req.body); - req.emit("end"); - }); - }).catch((error) => { - console.error(error); - throw error; - }); -} - -const handler = async function(event) { - await sendRequest(event); -}; - -export { handler };`; - - await writeToFile(outputPath, handlerFileName, handlerContent); - } - - // NOT USED - async getLocalFunctionWrapperCode(handler: string, entry: string): Promise { - return `${handler} ${entry}`; - } -} - -export class HttpServerPythonHandlerProvider implements FunctionHandlerProvider { - async write( - outputPath: string, - handlerFileName: string, - functionConfiguration: FunctionConfiguration, - ): Promise { - const nameModule = path - .join(functionConfiguration.path || "", functionConfiguration.entry || "") - .replace(/\\/g, ".") // Convert backslashes to dots (Windows) - .replace(/\//g, ".") // Convert slashes to dots (Unix) - .replace(/^\.+/, "") // Remove leading dots - .replace(/\.+/g, ".") // Remove duplicate dots - .replace(/\.py$/, ""); // Remove extension - - const handlerContent = ` -import asyncio -import traceback -from io import BytesIO -import base64 -from ${nameModule} import ${functionConfiguration.handler} as application - -async def handler(event): - """Main handler to route requests to the appropriate application type. - - Args: - event (dict): Incoming event data containing request information. - - Returns: - dict: HTTP response as a dictionary. - """ - try: - # Determine if the application is ASGI or WSGI - if callable(application) and asyncio.iscoroutinefunction(application.__call__): - return await asgi_handler(event) - else: - return wsgi_handler(event) - except Exception as e: - return handle_exception(e) - -def handle_exception(e): - """Handle exceptions and format them into an HTTP response. - - Args: - e (Exception): The exception to handle. - - Returns: - dict: A formatted HTTP error response. - """ - print("Error processing request:", traceback.format_exc()) - return { - "statusCode": 500, - "headers": {"Content-Type": "text/plain"}, - "body": "Internal Server Error", - } - -def wsgi_handler(event): - """Handler for WSGI applications. - - Args: - event (dict): Incoming event data containing request information. - - Returns: - dict: HTTP response as a dictionary. - """ - http_info = event.get('http', {}) - path = event.get('path', http_info.get('path', '/')) - environ = create_wsgi_environ(event, http_info, path) - - status_code = 500 - headers_dict = {} - response_stream = event.get("responseStream") - - def start_response(status, headers, exc_info=None): - """WSGI start response callable.""" - nonlocal status_code, headers_dict - status_code = int(status.split()[0]) - headers_dict = {key: value for key, value in headers} - - # Generate the response from the WSGI application - app_response = application(environ, start_response) - return stream_response(app_response, response_stream, status_code, headers_dict) - -def stream_response(app_response, response_stream, status_code, headers_dict): - """Stream the response from the WSGI application. - - Args: - app_response: WSGI application response. - response_stream: The response stream to write to. - status_code (int): The HTTP status code. - headers_dict (dict): The response headers. - - Returns: - dict: Formatted HTTP response. - """ - for chunk in app_response: - if isinstance(chunk, bytes): - response_stream.write(chunk) - else: - response_stream.write(chunk.encode()) - - return { - "statusCode": status_code, - "headers": headers_dict, - "body": None, - } - -async def asgi_handler(event): - """Handler for ASGI applications. - - Args: - event (dict): Incoming event data containing request information. - - Returns: - dict: HTTP response as a dictionary. - """ - http_info = event.get('http', {}) - path = event.get('path', http_info.get('path', '/')) - scope = create_asgi_scope(event, http_info, path) - - status_code = 500 - headers_dict = {} - response_body = b"" - - async def send(message): - """Send ASGI messages to construct the response.""" - nonlocal status_code, headers_dict, response_body - if message["type"] == "http.response.start": - status_code = message["status"] - headers_dict = {key.decode(): value.decode() for key, value in message["headers"]} - elif message["type"] == "http.response.body": - response_body += message.get("body", b"") - - async def receive(): - """Receive ASGI messages.""" - return { - "type": "http.request", - "body": event.get('body', b""), - "more_body": False - } - - # Call the ASGI application - await application(scope, receive, send) - - return format_response(response_body, headers_dict, status_code) - -def create_wsgi_environ(event, http_info, path): - """Create the WSGI environment from the event data. - - Args: - event (dict): Incoming event data. - http_info (dict): HTTP request information. - path (str): Request path. - - Returns: - dict: WSGI environment. - """ - return { - 'REQUEST_METHOD': http_info.get('method', 'GET'), - 'PATH_INFO': path, - 'QUERY_STRING': event.get('query', ''), - 'REMOTE_ADDR': http_info.get('sourceIp', ''), - 'CONTENT_TYPE': event.get('headers', {}).get('CONTENT-TYPE', ''), - 'CONTENT_LENGTH': str(len(event.get('body', ''))), - 'wsgi.input': BytesIO( - event.get('body', '').encode() if isinstance(event.get('body', ''), str) else event['body']), - 'wsgi.errors': BytesIO(), - 'wsgi.url_scheme': 'http', - **create_wsgi_headers(event.get('headers', {})) - } - -def create_asgi_scope(event, http_info, path): - """Create the ASGI scope from the event data. - - Args: - event (dict): Incoming event data. - http_info (dict): HTTP request information. - path (str): Request path. - - Returns: - dict: ASGI scope. - """ - return { - "type": "http", - "http_version": "1.1", - "method": http_info.get('method', 'GET'), - "path": path, - "query_string": event.get("query", "").encode(), - "headers": [ - (key.lower().encode(), value.encode()) - for key, value in event.get("headers", {}).items() - ], - "client": (http_info.get("sourceIp", ""), 0), - "server": ("server", 80), - } - -def create_wsgi_headers(headers): - """Create WSGI headers from the incoming headers. - - Args: - headers (dict): Incoming headers. - - Returns: - dict: Formatted WSGI headers. - """ - return {f"HTTP_{header.upper().replace('-', '_')}": value for header, value in headers.items()} - -def format_response(response_body, headers, status_code): - """Format the response for HTTP output. - - Args: - response_body (bytes): The body of the response. - headers (dict): Response headers. - status_code (int): HTTP status code. - - Returns: - dict: Formatted HTTP response. - """ - content_type = headers.get("Content-Type", "text/html") - - # Decode response body if it's bytes and intended as text - if isinstance(response_body, bytes): - try: - body = response_body.decode("utf-8", errors='replace') - except UnicodeDecodeError: - body = base64.b64encode(response_body).decode("utf-8") - else: - body = response_body - - return { - "statusCode": status_code, - "body": body, - "headers": headers - } -`; - - await writeToFile(outputPath, handlerFileName, handlerContent); - } - - // NOT USED - async getLocalFunctionWrapperCode(handler: string, entry: string): Promise { - return `${handler} ${entry}`; - } -} diff --git a/src/models/projectConfiguration.ts b/src/models/projectConfiguration.ts index a5ababd7e..13071c172 100644 --- a/src/models/projectConfiguration.ts +++ b/src/models/projectConfiguration.ts @@ -113,7 +113,7 @@ export class FunctionConfiguration { storageSize?: number; instanceSize?: InstanceSize; maxConcurrentRequestsPerInstance?: number; - + port?: string; constructor( name: string, path: string, @@ -125,6 +125,7 @@ export class FunctionConfiguration { storageSize?: number, instanceSize?: InstanceSize, maxConcurrentRequestsPerInstance?: number, + port?: string, ) { this.name = name; this.path = path; @@ -136,6 +137,7 @@ export class FunctionConfiguration { this.storageSize = storageSize; this.instanceSize = instanceSize; this.maxConcurrentRequestsPerInstance = maxConcurrentRequestsPerInstance; + this.port = port; } } diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index a52522783..dfbefeecf 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -122,6 +122,7 @@ function parseGenezioConfig(config: unknown) { storageSize: zod.number().optional(), instanceSize: zod.nativeEnum(InstanceSize).optional(), maxConcurrentRequestsPerInstance: zod.number().optional(), + port: zod.string().optional(), }) .refine( ({ type, handler }) => !(type === FunctionType.aws && !handler), diff --git a/src/utils/getFunctionHandlerProvider.ts b/src/utils/getFunctionHandlerProvider.ts index 0869e283d..77b87d65d 100644 --- a/src/utils/getFunctionHandlerProvider.ts +++ b/src/utils/getFunctionHandlerProvider.ts @@ -3,16 +3,12 @@ import { AwsFunctionHandlerProvider, AwsPythonFunctionHandlerProvider, } from "../functionHandlerProvider/providers/AwsFunctionHandlerProvider.js"; -import { - HttpServerHandlerProvider, - HttpServerPythonHandlerProvider, -} from "../functionHandlerProvider/providers/HttpServerHandlerProvider.js"; import { FunctionType, Language } from "../projectConfiguration/yaml/models.js"; export function getFunctionHandlerProvider( functionType: FunctionType, language: Language, -): AwsFunctionHandlerProvider | HttpServerHandlerProvider { +): AwsFunctionHandlerProvider | null { switch (functionType) { case FunctionType.aws: { const providerMap: { [key: string]: AwsFunctionHandlerProvider } = { @@ -33,23 +29,13 @@ export function getFunctionHandlerProvider( } } case FunctionType.httpServer: { - const providerMap: { [key: string]: HttpServerHandlerProvider } = { - [`${FunctionType.httpServer}-${Language.python}`]: - new HttpServerPythonHandlerProvider(), - [`${FunctionType.httpServer}-${Language.js}`]: new HttpServerHandlerProvider(), - [`${FunctionType.httpServer}-${Language.ts}`]: new HttpServerHandlerProvider(), - }; - - const key = `${functionType}-${language}`; - const provider = providerMap[key]; - - if (provider) { - return provider; - } else { + const supportedLanguages = [Language.python, Language.js, Language.ts]; + if (!supportedLanguages.includes(language)) { throw new UserError( `Unsupported language: ${language} for HTTP Server function. Supported languages are: python, js, ts.`, ); } + return null; } default: throw new UserError( From 89054f7d552d242e9023abb502125bca610bca48 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 12 Nov 2024 17:55:40 +0200 Subject: [PATCH 08/75] remove httpServer handler --- src/commands/deploy/genezio.ts | 36 +++++++++++++++++------------ src/models/projectConfiguration.ts | 5 ++-- src/projectConfiguration/yaml/v2.ts | 2 +- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index 2aa3996d2..e02cc47f5 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -631,9 +631,10 @@ export async function functionToCloudInput( let metadata: GenezioFunctionMetadata | undefined; if (functionElement.type === "httpServer") { + debugLogger.debug(`Http server port: ${functionElement.port}`); metadata = { type: GenezioFunctionMetadataType.HttpServer, - http_port: functionElement.port, + http_port: functionElement.port?.toString(), }; } @@ -671,21 +672,26 @@ export async function functionToCloudInput( const unzippedBundleSize = await getBundleFolderSizeLimit(tmpFolderPath); - // add the handler to the temporary folder - let entryFileName = - entryFileFunctionMap[functionElement.language as keyof typeof entryFileFunctionMap]; - while (fs.existsSync(path.join(tmpFolderPath, entryFileName))) { - debugLogger.debug( - `[FUNCTION ${functionElement.name}] File ${entryFileName} already exists in the temporary folder.`, - ); - entryFileName = getFunctionEntryFilename( - functionElement.language as Language, - `index-${Math.random().toString(36).substring(7)}`, - ); - } + // Determine entry file name + let entryFileName; + if (functionElement.type === "httpServer") { + entryFileName = functionElement.entry; // Use the entry file for httpServer + } else { + entryFileName = + entryFileFunctionMap[functionElement.language as keyof typeof entryFileFunctionMap]; + while (fs.existsSync(path.join(tmpFolderPath, entryFileName))) { + debugLogger.debug( + `[FUNCTION ${functionElement.name}] File ${entryFileName} already exists in the temporary folder.`, + ); + entryFileName = getFunctionEntryFilename( + functionElement.language as Language, + `index-${Math.random().toString(36).substring(7)}`, + ); + } - if (handlerProvider) { - await handlerProvider.write(tmpFolderPath, entryFileName, functionElement); + if (handlerProvider) { + await handlerProvider.write(tmpFolderPath, entryFileName, functionElement); + } } debugLogger.debug(`Zip the directory ${tmpFolderPath}.`); diff --git a/src/models/projectConfiguration.ts b/src/models/projectConfiguration.ts index 13071c172..ed38a7aac 100644 --- a/src/models/projectConfiguration.ts +++ b/src/models/projectConfiguration.ts @@ -113,7 +113,7 @@ export class FunctionConfiguration { storageSize?: number; instanceSize?: InstanceSize; maxConcurrentRequestsPerInstance?: number; - port?: string; + port?: number; constructor( name: string, path: string, @@ -125,7 +125,7 @@ export class FunctionConfiguration { storageSize?: number, instanceSize?: InstanceSize, maxConcurrentRequestsPerInstance?: number, - port?: string, + port?: number, ) { this.name = name; this.path = path; @@ -303,6 +303,7 @@ export class ProjectConfiguration { storageSize: f.storageSize, instanceSize: f.instanceSize, maxConcurrentRequestsPerInstance: f.maxConcurrentRequestsPerInstance, + port: f.port, }; }) || []; } diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index dfbefeecf..48e801874 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -122,7 +122,7 @@ function parseGenezioConfig(config: unknown) { storageSize: zod.number().optional(), instanceSize: zod.nativeEnum(InstanceSize).optional(), maxConcurrentRequestsPerInstance: zod.number().optional(), - port: zod.string().optional(), + port: zod.number().optional(), }) .refine( ({ type, handler }) => !(type === FunctionType.aws && !handler), From 203ee24c34b33516f8f5f246bfc256d0ac1c6677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Thu, 14 Nov 2024 14:14:01 +0200 Subject: [PATCH 09/75] Automatically detect databases and add them in the configuration file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 42 +++++++++++++++- src/commands/analyze/frameworks.ts | 75 ++++++++++++++++++++++++++++- src/commands/analyze/utils.ts | 21 +++++++- src/projectConfiguration/yaml/v2.ts | 1 + 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index d1813376f..9c62b347e 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -21,6 +21,8 @@ import { isPythonLambdaFunction, findEntryFile, isGenezioTypesafe, + hasPostgresDependency, + hasMongoDependency, } from "./frameworks.js"; import { readOrAskConfig } from "../deploy/utils.js"; import { getPackageManager, PackageManagerType } from "../../packageManagers/packageManager.js"; @@ -30,13 +32,14 @@ import { addBackendComponentToConfig, addContainerComponentToConfig, addFrontendComponentToConfig, + addServicesToConfig, addSSRComponentToConfig, getFrontendPrefix, getPythonHandler, injectBackendApiUrlsInConfig, injectSDKInConfig, } from "./utils.js"; -import { FunctionType, Language } from "../../projectConfiguration/yaml/models.js"; +import { DatabaseType, FunctionType, Language } from "../../projectConfiguration/yaml/models.js"; import { report } from "./outputUtils.js"; import { isCI } from "../../utils/process.js"; import { @@ -60,6 +63,11 @@ export type FrameworkReport = { backend?: string[]; frontend?: string[]; ssr?: string[]; + services?: FrameworkReportService[]; +}; + +export type FrameworkReportService = { + databases?: string[]; }; export enum FRONTEND_ENV_PREFIX { @@ -79,6 +87,7 @@ export const DEFAULT_FORMAT = SUPPORTED_FORMATS.TEXT; export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; export const KEY_FILES = ["package.json", "Dockerfile", "requirements.txt"]; +export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build"]; export const NODE_DEFAULT_ENTRY_FILE = "index.mjs"; export const PYTHON_DEFAULT_ENTRY_FILE = "app.py"; @@ -121,6 +130,37 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { [filename]: fileContent, }; + // Check for services (postgres, mongo) + if (await hasPostgresDependency(contents, filename)) { + await addServicesToConfig(configPath, { + databases: [ + { + name: "postgres-db", + region: genezioConfig.region, + type: DatabaseType.neon, + }, + ], + }); + + frameworksDetected.services = frameworksDetected.services || []; + frameworksDetected.services.push({ databases: ["postgres"] }); + } + if (await hasMongoDependency(contents, filename)) { + await addServicesToConfig(configPath, { + databases: [ + { + name: "mongo-db", + region: genezioConfig.region, + type: DatabaseType.mongo, + }, + ], + }); + + frameworksDetected.services = frameworksDetected.services || []; + frameworksDetected.services.push({ databases: ["mongo"] }); + } + + // Check for frameworks (backend, frontend, ssr, container) if (await isServerlessHttpBackend(contents)) { const entryFile = await findEntryFile( componentPath, diff --git a/src/commands/analyze/frameworks.ts b/src/commands/analyze/frameworks.ts index 90289cebb..425d87d80 100644 --- a/src/commands/analyze/frameworks.ts +++ b/src/commands/analyze/frameworks.ts @@ -1,6 +1,6 @@ import { promises as fs } from "fs"; import path from "path"; -import { EXCLUDED_DIRECTORIES } from "./command.js"; +import { EXCLUDED_DIRECTORIES, KEY_DEPENDENCY_FILES } from "./command.js"; import { FUNCTION_EXTENSIONS } from "../../models/projectOptions.js"; export interface PackageJSON { @@ -133,6 +133,79 @@ async function getEntryFileFromPackageJson( return { candidateFile: mainPath, fallback: false }; } +export async function hasPostgresDependency( + contents: Record, + dependencyFile: string, +): Promise { + if (!KEY_DEPENDENCY_FILES.includes(dependencyFile)) { + return false; + } + + if (!contents[dependencyFile]) { + return false; + } + + const jsPostgresIndicators = ["pg", "pg-promise"]; + const pythonPostgresIndicators = ["psycopg2", "asyncpg", "py-postgresql"]; + const dependencyList = jsPostgresIndicators.concat(pythonPostgresIndicators); + + return await searchDependency(contents, dependencyFile, dependencyList); +} + +export async function hasMongoDependency( + contents: Record, + dependencyFile: string, +): Promise { + if (!KEY_DEPENDENCY_FILES.includes(dependencyFile)) { + return false; + } + + if (!contents[dependencyFile]) { + return false; + } + + const jsMongoIndicators = ["mongodb", "mongoose", "connect-mongo"]; + const pythonMongoIndicators = ["pymongo"]; + const dependencyList = jsMongoIndicators.concat(pythonMongoIndicators); + + return await searchDependency(contents, dependencyFile, dependencyList); +} + +/** + * This function receives a dependency file such as package.json or requirements.txt + * and a list of dependency such as ["mongodb", "mongoose", "connect-mongo"]. + * + * It returns true if any of the dependencies are found in the file. + * + * This is used to determine if a project is using certain services such as Postgres or MongoDB + * Can be used for other services too - redis, mysql, kafka etc. + */ +export async function searchDependency( + contents: Record, + dependencyFile: string, + dependencyList: string[], +): Promise { + if (!contents[dependencyFile]) { + return false; + } + + if (dependencyFile === "package.json") { + const packageJsonContent = JSON.parse(contents["package.json"]) as PackageJSON; + return dependencyList.some( + (indicator) => + indicator in (packageJsonContent.dependencies || {}) || + indicator in (packageJsonContent.devDependencies || {}), + ); + } else if (dependencyFile === "requirements.txt") { + const requirementsContent = contents["requirements.txt"]; + return requirementsContent + .split("\n") + .some((line) => dependencyList.some((indicator) => line.trim().startsWith(indicator))); + } + + return false; +} + // Checks if the project is a Express component // `contents` is a map of important file paths and their contents export async function isExpressBackend(contents: Record): Promise { diff --git a/src/commands/analyze/utils.ts b/src/commands/analyze/utils.ts index d4e6d00d0..ea0954090 100644 --- a/src/commands/analyze/utils.ts +++ b/src/commands/analyze/utils.ts @@ -1,6 +1,11 @@ import path from "path"; import { SSRFrameworkComponentType } from "../../models/projectOptions.js"; -import { YamlFrontend, YAMLBackend, YamlContainer } from "../../projectConfiguration/yaml/v2.js"; +import { + YamlFrontend, + YAMLBackend, + YamlContainer, + YAMLService, +} from "../../projectConfiguration/yaml/v2.js"; import { YamlConfigurationIOController } from "../../projectConfiguration/yaml/v2.js"; import { SSRFrameworkComponent } from "../deploy/command.js"; import { FRONTEND_ENV_PREFIX } from "./command.js"; @@ -120,6 +125,20 @@ export async function addContainerComponentToConfig(configPath: string, componen await configIOController.write(config); } +export async function addServicesToConfig(configPath: string, services: YAMLService) { + const configIOController = new YamlConfigurationIOController(configPath); + // We have to read the config here with fillDefaults=false + // to be able to edit it in the least intrusive way + const config = await configIOController.read(/* fillDefaults= */ false); + + config.services = { + ...config.services, + ...services, + }; + + await configIOController.write(config); +} + /** * Injects the backend function URLs into the frontend environment variables. * @param frontendPrefix The prefix to use for the frontend environment variables. diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index a52522783..7a7a9d6b1 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -29,6 +29,7 @@ import { DeepRequired } from "../../utils/types.js"; export type RawYamlProjectConfiguration = ReturnType; export type YAMLBackend = NonNullable; +export type YAMLService = NonNullable; export type YAMLLanguage = NonNullable; export type YamlClass = NonNullable[number]; export type YamlFunction = NonNullable[number]; From 805cdc4d3fac5808a8440be1295a98e3eef8c6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Thu, 14 Nov 2024 15:11:53 +0200 Subject: [PATCH 10/75] Generate a unique database name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 6 +++--- src/commands/deploy/utils.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 9c62b347e..824fa256c 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -24,7 +24,7 @@ import { hasPostgresDependency, hasMongoDependency, } from "./frameworks.js"; -import { readOrAskConfig } from "../deploy/utils.js"; +import { generateDatabaseName, readOrAskConfig } from "../deploy/utils.js"; import { getPackageManager, PackageManagerType } from "../../packageManagers/packageManager.js"; import { SSRFrameworkComponentType } from "../../models/projectOptions.js"; import { RawYamlProjectConfiguration, YAMLLanguage } from "../../projectConfiguration/yaml/v2.js"; @@ -135,7 +135,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { await addServicesToConfig(configPath, { databases: [ { - name: "postgres-db", + name: await generateDatabaseName("postgres"), region: genezioConfig.region, type: DatabaseType.neon, }, @@ -149,7 +149,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { await addServicesToConfig(configPath, { databases: [ { - name: "mongo-db", + name: await generateDatabaseName("mongo"), region: genezioConfig.region, type: DatabaseType.mongo, }, diff --git a/src/commands/deploy/utils.ts b/src/commands/deploy/utils.ts index dd2a54cfd..0b16e509e 100644 --- a/src/commands/deploy/utils.ts +++ b/src/commands/deploy/utils.ts @@ -273,6 +273,35 @@ export async function readOrAskProjectName(): Promise { return name; } +/** + * To prevent reusing an already deployed database, we will check if the database exists remotely. + * @param prefix Prefix for the database name, usually the engine used - e.g. "postgres", "mongo" + * @returns A unique database name + */ +export async function generateDatabaseName(prefix: string): Promise { + const defaultDatabaseName = prefix + "-" + "db"; + + const databaseExists = await getDatabaseByName(defaultDatabaseName) + .then(() => true) + .catch(() => false); + + if (!databaseExists) { + return defaultDatabaseName; + } + + const generatedDatabaseName = + prefix + + "-" + + uniqueNamesGenerator({ + dictionaries: [adjectives, animals], + separator: "-", + style: "lowerCase", + length: 2, + }); + + return generatedDatabaseName; +} + export async function getOrCreateDatabase( createDatabaseReq: CreateDatabaseRequest, stage: string, From 0c5fc3be4f55c2a642cdf93033fb52fcbd7f5df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Thu, 14 Nov 2024 11:09:42 +0200 Subject: [PATCH 11/75] Add agent that analyzes env files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- package-lock.json | 151 +++++++++++++++++++++++++++++- package.json | 1 + src/commands/analyze/agent.ts | 79 ++++++++++++++++ src/commands/analyze/command.ts | 42 ++++++++- src/commands/analyze/constants.ts | 29 ++++++ 5 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 src/commands/analyze/agent.ts diff --git a/package-lock.json b/package-lock.json index 8e50087ce..ada2ee0dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "node-abort-controller": "^3.1.1", "node-cron": "^3.0.3", "open": "^10.1.0", + "openai": "^4.72.0", "ora": "^8.1.1", "parse-gitignore": "^2.0.0", "semver": "^7.6.3", @@ -5358,6 +5359,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/parse-gitignore": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/parse-gitignore/-/parse-gitignore-1.0.2.tgz", @@ -5948,6 +5958,17 @@ "node": ">=12.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -8310,6 +8331,23 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/forwarded": { "version": "0.2.0", "license": "MIT", @@ -8558,6 +8596,14 @@ "node": ">=18.18.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/husky": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", @@ -9766,6 +9812,43 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -9858,6 +9941,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "4.72.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.72.0.tgz", + "integrity": "sha512-hFqG9BWCs7L7ifrhJXw7mJXmUBr7d9N6If3J9563o0jfwVA4wFANFDDaOIWFdgDdwgCXg5emf0Q+LoLCGszQYA==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -11547,6 +11668,11 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tree-dump": { "version": "1.0.1", "engines": { @@ -11969,6 +12095,19 @@ } } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "node_modules/whatwg-mimetype": { "version": "3.0.0", "license": "MIT", @@ -11976,6 +12115,15 @@ "node": ">=12" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", @@ -12232,7 +12380,8 @@ }, "node_modules/zod": { "version": "3.23.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 089a90dbf..1a2129505 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "node-abort-controller": "^3.1.1", "node-cron": "^3.0.3", "open": "^10.1.0", + "openai": "^4.72.0", "ora": "^8.1.1", "parse-gitignore": "^2.0.0", "semver": "^7.6.3", diff --git a/src/commands/analyze/agent.ts b/src/commands/analyze/agent.ts new file mode 100644 index 000000000..1d464d880 --- /dev/null +++ b/src/commands/analyze/agent.ts @@ -0,0 +1,79 @@ +import { OpenAI } from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; +import { z } from "zod"; +import { + ENVIRONMENT_ANALYZE_PROMPT, + INJECT_SERVICES, + SYSTEM_ENVIRONMENT_ANALYZE_PROMPT, +} from "./constants.js"; +import { debugLogger } from "../../utils/logging.js"; +import { YAMLService } from "../../projectConfiguration/yaml/v2.js"; + +export interface ProjectEnvironment { + key: string; + defaultValue: string; + aboveComment?: string; + link?: string; +} + +export const ProjectEnvironmentSchema = z.object({ + environment: z.array( + z.object({ + key: z.string(), + defaultValue: z.string(), + aboveComment: z.string().optional(), + link: z.string().optional(), + }), + ), +}); + +export async function analyzeBackendEnvExampleFile( + contents: string, + services?: YAMLService, +): Promise { + if (!process.env["OPENAI_API_KEY"]) { + debugLogger.debug("No OpenAI API key found. Set OPENAI_API_KEY to enable analyze agent."); + return []; + } + + try { + const openai = new OpenAI({ + apiKey: process.env["OPENAI_API_KEY"], + }); + + // Services might not be provided, so we need to check if it's available + const injectedServices = services + ? INJECT_SERVICES.replace("{{services}}", JSON.stringify(services)) + : undefined; + const prompt = ENVIRONMENT_ANALYZE_PROMPT.replace( + "{{injectedServices}}", + injectedServices || "", + ).replace("{{contents}}", contents); + + const completion = await openai.beta.chat.completions.parse({ + model: "gpt-4o", + messages: [ + { role: "system", content: SYSTEM_ENVIRONMENT_ANALYZE_PROMPT }, + { role: "user", content: prompt }, + ], + response_format: zodResponseFormat(ProjectEnvironmentSchema, "json_schema"), + }); + + if (completion.choices[0]?.message?.refusal) { + debugLogger.debug("OpenAI refused to provide a response"); + return []; + } + + // Parse and return the response + const answer = completion?.choices?.[0]?.message; + if (answer?.parsed) { + return answer.parsed.environment; + } else { + debugLogger.debug("No parsed response from OpenAI"); + return []; + } + } catch (error) { + debugLogger.error("Error analyzing backend env example file", error); + return []; + } +} diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 824fa256c..298f7b258 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -27,7 +27,11 @@ import { import { generateDatabaseName, readOrAskConfig } from "../deploy/utils.js"; import { getPackageManager, PackageManagerType } from "../../packageManagers/packageManager.js"; import { SSRFrameworkComponentType } from "../../models/projectOptions.js"; -import { RawYamlProjectConfiguration, YAMLLanguage } from "../../projectConfiguration/yaml/v2.js"; +import { + RawYamlProjectConfiguration, + YamlConfigurationIOController, + YAMLLanguage, +} from "../../projectConfiguration/yaml/v2.js"; import { addBackendComponentToConfig, addContainerComponentToConfig, @@ -51,6 +55,7 @@ import { PYTHON_LAMBDA_PATTERN, SERVERLESS_HTTP_PATTERN, } from "./constants.js"; +import { analyzeBackendEnvExampleFile, ProjectEnvironment } from "./agent.js"; // backend javascript: aws-compatible functions, serverless-http functions, express, fastify // backend typescript: aws-compatible functions, serverless-http functions, express, fastify @@ -61,6 +66,7 @@ import { // services: databases, authentication, crons, cache/redis, queues export type FrameworkReport = { backend?: string[]; + backendEnvironment?: ProjectEnvironment[]; frontend?: string[]; ssr?: string[]; services?: FrameworkReportService[]; @@ -88,6 +94,7 @@ export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; export const KEY_FILES = ["package.json", "Dockerfile", "requirements.txt"]; export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; +export const ENVIRONMENT_EXAMPLE_FILES = [".env.template", ".env.example", ".env.local.example"]; export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build"]; export const NODE_DEFAULT_ENTRY_FILE = "index.mjs"; export const PYTHON_DEFAULT_ENTRY_FILE = "app.py"; @@ -542,6 +549,32 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { } } + // Analyze the environment example file if we have a backend component + if (frameworksDetected.backend && frameworksDetected.backend.length > 0) { + const envExampleFiles = await findKeyFiles(rootDirectory, ENVIRONMENT_EXAMPLE_FILES); + // Read the file contents + const envExampleContents = new Map(); + for (const [relativeFilePath, filename] of envExampleFiles.entries()) { + const fileContent = await retrieveFileContent(relativeFilePath); + envExampleContents.set(filename, fileContent); + } + + // envExampleContents to string + const envExampleContentsString = Array.from(envExampleContents.values()).join("\n"); + + const configIOController = new YamlConfigurationIOController(configPath); + // We have to read the config here with fillDefaults=false + // to be able to edit it in the least intrusive way + const config = await configIOController.read(/* fillDefaults= */ false); + + // Analyze the environment example file + const envExampleAnalysis = await analyzeBackendEnvExampleFile( + envExampleContentsString, + config.services, + ); + frameworksDetected.backendEnvironment = envExampleAnalysis; + } + // Inject Backend API URLs into the frontend component // This is done after all the components have been detected if ( @@ -570,7 +603,10 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { log.info(result); } -export const findKeyFiles = async (dir: string): Promise> => { +export const findKeyFiles = async ( + dir: string, + keyFiles: string[] = KEY_FILES, +): Promise> => { const result = new Map(); const searchDir = async (currentDir: string) => { @@ -586,7 +622,7 @@ export const findKeyFiles = async (dir: string): Promise> => // Recursively search subdirectory await searchDir(fullPath); - } else if (KEY_FILES.includes(entry.name)) { + } else if (keyFiles.includes(entry.name)) { // If the file is one of the key files, add it to the map const relativePath = path.relative(dir, fullPath); result.set(relativePath, entry.name); diff --git a/src/commands/analyze/constants.ts b/src/commands/analyze/constants.ts index fd8a0e27a..3dfb2ebc7 100644 --- a/src/commands/analyze/constants.ts +++ b/src/commands/analyze/constants.ts @@ -36,3 +36,32 @@ export const FASTAPI_PATTERN = [ /\w+\s*=\s*FastAPI\(\)/, /from\s+fastapi\s+import\s+FastAPI|import\s+fastapi/, ]; + +// Agent Prompts +export const ENVIRONMENT_ANALYZE_PROMPT = `Your task is to analyze the following .env.example file and provide values as best as you can. + +{{injectedServices}} + +This is the .env.example: + +{{contents}} + +Analyze the file and provide the following information for each environment variable: +- key: The name of the environment variable +- defaultValue: The default value of the environment variable - try and provide a value that is most likely to be used +- aboveComment(optional): A helpful description of what this environment variable does +- link(optional): A link to the documentation on how to retrieve this environment variable if it's not possible to provide a default value. This is an optional value. If you already have a default value, provide "" for link. + +There are a few tips to keep in mind: +1. If the environment variable is a postgres database - you can provide the following \`\${{services.databases..uri}}\` +2. If the environment variable is a mongo database - you can provide the following \`\${{services.databases..uri}}\` +3. If the environment variable has to be random secret string, generate a random string with the proper length + +`; +export const INJECT_SERVICES = `You are also given a list of services that are provisioned by Genezio. +You can use the following services to provide values for the environment variables. + +The services are: +{{services}} +`; +export const SYSTEM_ENVIRONMENT_ANALYZE_PROMPT = `Your task is to analyze the following system environment variables and provide values as best as you can.`; From 556f2ac0d97d5673281116cfcd8ff494fc31389d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Thu, 14 Nov 2024 15:02:23 +0200 Subject: [PATCH 12/75] Save Genezio provisioned environment variables in the genezio.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/agent.ts | 2 ++ src/commands/analyze/command.ts | 20 ++++++++++++++++++++ src/commands/analyze/constants.ts | 5 +++-- src/commands/analyze/utils.ts | 4 ++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/commands/analyze/agent.ts b/src/commands/analyze/agent.ts index 1d464d880..d9df39d24 100644 --- a/src/commands/analyze/agent.ts +++ b/src/commands/analyze/agent.ts @@ -12,6 +12,7 @@ import { YAMLService } from "../../projectConfiguration/yaml/v2.js"; export interface ProjectEnvironment { key: string; defaultValue: string; + genezioProvisioned: boolean; aboveComment?: string; link?: string; } @@ -21,6 +22,7 @@ export const ProjectEnvironmentSchema = z.object({ z.object({ key: z.string(), defaultValue: z.string(), + genezioProvisioned: z.boolean(), aboveComment: z.string().optional(), link: z.string().optional(), }), diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 298f7b258..4578e08c7 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -29,6 +29,7 @@ import { getPackageManager, PackageManagerType } from "../../packageManagers/pac import { SSRFrameworkComponentType } from "../../models/projectOptions.js"; import { RawYamlProjectConfiguration, + YAMLBackend, YamlConfigurationIOController, YAMLLanguage, } from "../../projectConfiguration/yaml/v2.js"; @@ -572,6 +573,25 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { envExampleContentsString, config.services, ); + + const filteredEnvExampleAnalysis = envExampleAnalysis.filter((env: ProjectEnvironment) => + /\$\{\{.*\}\}/.test(env.defaultValue), + ); + + const environment: Record = filteredEnvExampleAnalysis.reduce( + (acc: Record, env: ProjectEnvironment) => { + acc[env.key] = env.defaultValue; + return acc; + }, + {}, + ); + + // Add backend environment to the config + await addBackendComponentToConfig(configPath, { + ...(config.backend as YAMLBackend), + environment: environment, + }); + frameworksDetected.backendEnvironment = envExampleAnalysis; } diff --git a/src/commands/analyze/constants.ts b/src/commands/analyze/constants.ts index 3dfb2ebc7..58047eab5 100644 --- a/src/commands/analyze/constants.ts +++ b/src/commands/analyze/constants.ts @@ -51,10 +51,11 @@ Analyze the file and provide the following information for each environment vari - defaultValue: The default value of the environment variable - try and provide a value that is most likely to be used - aboveComment(optional): A helpful description of what this environment variable does - link(optional): A link to the documentation on how to retrieve this environment variable if it's not possible to provide a default value. This is an optional value. If you already have a default value, provide "" for link. +- genezioProvisioned: If the environment variable is for a service that is provisioned by Genezio, set this to true. If not, set this to false. There are a few tips to keep in mind: -1. If the environment variable is a postgres database - you can provide the following \`\${{services.databases..uri}}\` -2. If the environment variable is a mongo database - you can provide the following \`\${{services.databases..uri}}\` +1. If the environment variable is a postgres database - you can provide the following \`\${{services.databases..uri}}\` because it's provisioned by Genezio +2. If the environment variable is a mongo database - you can provide the following \`\${{services.databases..uri}}\` because it's provisioned by Genezio 3. If the environment variable has to be random secret string, generate a random string with the proper length `; diff --git a/src/commands/analyze/utils.ts b/src/commands/analyze/utils.ts index ea0954090..d5c40d1d6 100644 --- a/src/commands/analyze/utils.ts +++ b/src/commands/analyze/utils.ts @@ -68,6 +68,10 @@ export async function addBackendComponentToConfig(configPath: string, component: path: backend?.path || component.path, language: backend?.language || component.language, functions: backend?.functions || component.functions, + environment: { + ...component.environment, + ...backend?.environment, + }, scripts: { deploy: backend?.scripts?.deploy || scripts?.deploy, local: backend?.scripts?.local || scripts?.local, From 9edbeb38f87b10776547ce071cc5371d8af76fa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:36:51 +0000 Subject: [PATCH 13/75] Bump @types/adm-zip from 0.5.5 to 0.5.6 Bumps [@types/adm-zip](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/adm-zip) from 0.5.5 to 0.5.6. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/adm-zip) --- updated-dependencies: - dependency-name: "@types/adm-zip" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e50087ce..b072766bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@genezio/test-interface-component": "^1.2.3", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", - "@types/adm-zip": "^0.5.5", + "@types/adm-zip": "^0.5.6", "@webcontainer/env": "^1.1.1", "adm-zip": "^0.5.16", "archiver": "^7.0.1", @@ -5128,8 +5128,9 @@ } }, "node_modules/@types/adm-zip": { - "version": "0.5.5", - "license": "MIT", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.6.tgz", + "integrity": "sha512-lRlcSLg5Yoo7C2H2AUiAoYlvifWoCx/se7iUNiCBTfEVVYFVn+Tr9ZGed4K73tYgLe9O4PjdJvbxlkdAOx/qiw==", "dependencies": { "@types/node": "*" } diff --git a/package.json b/package.json index 089a90dbf..6d800c5f6 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@genezio/test-interface-component": "^1.2.3", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", - "@types/adm-zip": "^0.5.5", + "@types/adm-zip": "^0.5.6", "@webcontainer/env": "^1.1.1", "adm-zip": "^0.5.16", "archiver": "^7.0.1", From 38fd3aeb6d7716798bf150c4ad2876f069f5d0f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:36:59 +0000 Subject: [PATCH 14/75] Bump memfs from 4.11.1 to 4.14.0 Bumps [memfs](https://github.com/streamich/memfs) from 4.11.1 to 4.14.0. - [Release notes](https://github.com/streamich/memfs/releases) - [Changelog](https://github.com/streamich/memfs/blob/master/CHANGELOG.md) - [Commits](https://github.com/streamich/memfs/compare/v4.11.1...v4.14.0) --- updated-dependencies: - dependency-name: memfs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e50087ce..6c45dfa98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "lodash": "^4.17.21", "log-update": "^6.1.0", "loglevel-plugin-prefix": "^0.8.4", - "memfs": "^4.11.1", + "memfs": "^4.14.0", "mime-types": "^2.1.35", "mustache": "^4.2.0", "node-abort-controller": "^3.1.1", @@ -9544,9 +9544,9 @@ } }, "node_modules/memfs": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", - "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", diff --git a/package.json b/package.json index 089a90dbf..e9e18a228 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "lodash": "^4.17.21", "log-update": "^6.1.0", "loglevel-plugin-prefix": "^0.8.4", - "memfs": "^4.11.1", + "memfs": "^4.14.0", "mime-types": "^2.1.35", "mustache": "^4.2.0", "node-abort-controller": "^3.1.1", From 8601b2f7d24f8795408936066a0e0bc75472072e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:37:08 +0000 Subject: [PATCH 15/75] Bump uuid from 10.0.0 to 11.0.3 Bumps [uuid](https://github.com/uuidjs/uuid) from 10.0.0 to 11.0.3. - [Release notes](https://github.com/uuidjs/uuid/releases) - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v10.0.0...v11.0.3) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e50087ce..5fd4d1202 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "tslog": "^4.9.2", "typescript": "^5.6.3", "unique-names-generator": "^4.7.1", - "uuid": "^10.0.0", + "uuid": "^11.0.3", "whatwg-mimetype": "~3.0.0", "which": "^5.0.0", "yaml": "^2.5.0", @@ -11753,14 +11753,15 @@ } }, "node_modules/uuid": { - "version": "10.0.0", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz", + "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/vary": { diff --git a/package.json b/package.json index 089a90dbf..329edfb9c 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "tslog": "^4.9.2", "typescript": "^5.6.3", "unique-names-generator": "^4.7.1", - "uuid": "^10.0.0", + "uuid": "^11.0.3", "whatwg-mimetype": "~3.0.0", "which": "^5.0.0", "yaml": "^2.5.0", From d9e3e8d1111eae69d2dee925cc3ee3d3b8a44fd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:37:16 +0000 Subject: [PATCH 16/75] Bump @rollup/rollup-win32-arm64-msvc from 4.24.0 to 4.27.2 Bumps [@rollup/rollup-win32-arm64-msvc](https://github.com/rollup/rollup) from 4.24.0 to 4.27.2. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.24.0...v4.27.2) --- updated-dependencies: - dependency-name: "@rollup/rollup-win32-arm64-msvc" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e50087ce..fd41f386b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", + "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.5", @@ -131,7 +132,7 @@ "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.22.5", "@rollup/rollup-linux-x64-musl": "4.24.3", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" } @@ -4354,9 +4355,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "version": "4.27.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.2.tgz", + "integrity": "sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==", "cpu": [ "arm64" ], diff --git a/package.json b/package.json index 089a90dbf..61c8cc391 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.22.5", "@rollup/rollup-linux-x64-musl": "4.24.3", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" }, From 5ebb9004253585569cd06a3752dfb0698053fdbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:37:23 +0000 Subject: [PATCH 17/75] Bump @types/archiver from 6.0.2 to 6.0.3 Bumps [@types/archiver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/archiver) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/archiver) --- updated-dependencies: - dependency-name: "@types/archiver" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e50087ce..684df5bf7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,7 +81,7 @@ }, "devDependencies": { "@babel/types": "^7.25.2", - "@types/archiver": "^6.0.2", + "@types/archiver": "^6.0.3", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.4", "@types/body": "^5.1.4", @@ -5135,9 +5135,10 @@ } }, "node_modules/@types/archiver": { - "version": "6.0.2", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.3.tgz", + "integrity": "sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/readdir-glob": "*" } diff --git a/package.json b/package.json index 089a90dbf..360964704 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ }, "devDependencies": { "@babel/types": "^7.25.2", - "@types/archiver": "^6.0.2", + "@types/archiver": "^6.0.3", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.4", "@types/body": "^5.1.4", From bfcea13f28e0977706ee80a17a2e934896c0c26b Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 10:41:56 +0200 Subject: [PATCH 18/75] Run with node/python3 entryfile --- src/commands/local.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 7f52cba30..e70fba945 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -95,6 +95,7 @@ import { HttpServerPythonHandlerProvider, } from "../functionHandlerProvider/providers/HttpServerHandlerProvider.js"; import { getFunctionEntryFilename } from "../utils/getFunctionEntryFilename.js"; +import { detectPythonCommand } from "../utils/detectPythonCommand.js"; type UnitProcess = { process: ChildProcess; @@ -640,15 +641,28 @@ async function startProcesses( functionInfo.language as Language, ); - // if handlerProvider is Http + // if handlerProvider is Http, run it with node if (handlerProvider instanceof HttpServerHandlerProvider) { - log.error("We recommend to run the HTTP server with `node` or `npm start`."); - process.exit(1); + return { + configuration: functionInfo, + extra: { + type: "function" as const, + startingCommand: "node", + commandParameters: [functionInfo.entry], + }, + }; } + // if handlerProvider is Http and language is python if (handlerProvider instanceof HttpServerPythonHandlerProvider) { - log.error("We recommend to run the HTTP server with `python` or `python3`."); - process.exit(1); + return { + configuration: functionInfo, + extra: { + type: "function" as const, + startingCommand: (await detectPythonCommand()) || "python", + commandParameters: [functionInfo.entry], + }, + }; } await writeToFile( From df5ba871ce168ee966dce6978bf8d098ef888560 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 15:21:38 +0200 Subject: [PATCH 19/75] Fix genezio local httpServer --- src/commands/local.ts | 30 ++++++++++++++++++++++++++---- src/models/projectConfiguration.ts | 3 +++ src/utils/scripts.ts | 8 +++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index e70fba945..253091f5d 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -8,7 +8,11 @@ import url from "url"; import * as http from "http"; import colors from "colors"; import { createRequire } from "module"; -import { ProjectConfiguration, ClassConfiguration } from "../models/projectConfiguration.js"; +import { + ProjectConfiguration, + ClassConfiguration, + FunctionConfiguration, +} from "../models/projectConfiguration.js"; import { RECOMMENTDED_GENEZIO_TYPES_VERSION_RANGE, REQUIRED_GENEZIO_TYPES_VERSION_RANGE, @@ -39,6 +43,7 @@ import axios, { AxiosError, AxiosResponse } from "axios"; import { findAvailablePort } from "../utils/findAvailablePort.js"; import { entryFileFunctionMap, + FunctionType, Language, startingCommandMap, TriggerType, @@ -104,6 +109,7 @@ type UnitProcess = { listeningPort: number; envVars: dotenv.DotenvPopulateInput; type: "class" | "function"; + handlerType?: FunctionType; }; type LocalUnitProcessSpawnResponse = { @@ -627,7 +633,7 @@ async function startProcesses( }); const bundlersOutputPromiseFunctions = projectConfiguration.functions?.map( - async (functionInfo) => { + async (functionInfo: FunctionConfiguration) => { const tmpFolder = await createTemporaryFolder( `${functionInfo.name}-${hash(functionInfo.path)}`, ); @@ -643,24 +649,34 @@ async function startProcesses( // if handlerProvider is Http, run it with node if (handlerProvider instanceof HttpServerHandlerProvider) { + process.env[`${functionInfo.name.replace(/-/g, "_").toUpperCase()}_PORT`] = ( + functionInfo.port || 8080 + ).toString(); + return { configuration: functionInfo, extra: { type: "function" as const, startingCommand: "node", commandParameters: [functionInfo.entry], + handlerType: FunctionType.httpServer, }, }; } // if handlerProvider is Http and language is python if (handlerProvider instanceof HttpServerPythonHandlerProvider) { + process.env[`${functionInfo.name.replace(/-/g, "_").toUpperCase()}_PORT`] = ( + functionInfo.port || 8080 + ).toString(); + return { configuration: functionInfo, extra: { type: "function" as const, startingCommand: (await detectPythonCommand()) || "python", commandParameters: [functionInfo.entry], + handlerType: FunctionType.httpServer, }, }; } @@ -1013,7 +1029,10 @@ function getProjectFunctions( projectConfiguration: ProjectConfiguration, ): DeployCodeFunctionResponse[] { return projectConfiguration.functions.map((f) => ({ - cloudUrl: `http://localhost:${port}/.functions/${f.name}`, + cloudUrl: + f.type === FunctionType.httpServer + ? `http://localhost:${process.env[`${f.name.replace(/-/g, "_").toUpperCase()}_PORT`]}` + : `http://localhost:${port}/.functions/${f.name}`, id: f.name, name: f.name, })); @@ -1333,7 +1352,10 @@ function reportSuccess(projectConfiguration: ProjectConfiguration, port: number) projectConfiguration.functions.map((f) => ({ name: f.name, id: f.name, - cloudUrl: `http://localhost:${port}/.functions/${f.name}`, + cloudUrl: + f.type === FunctionType.httpServer + ? `http://localhost:${process.env[`${f.name.replace(/-/g, "_").toUpperCase()}_PORT`]}` + : `http://localhost:${port}/.functions/${f.name}`, })), ); } diff --git a/src/models/projectConfiguration.ts b/src/models/projectConfiguration.ts index a5ababd7e..c0a1b8818 100644 --- a/src/models/projectConfiguration.ts +++ b/src/models/projectConfiguration.ts @@ -113,6 +113,7 @@ export class FunctionConfiguration { storageSize?: number; instanceSize?: InstanceSize; maxConcurrentRequestsPerInstance?: number; + port?: number; constructor( name: string, @@ -125,6 +126,7 @@ export class FunctionConfiguration { storageSize?: number, instanceSize?: InstanceSize, maxConcurrentRequestsPerInstance?: number, + port?: number, ) { this.name = name; this.path = path; @@ -136,6 +138,7 @@ export class FunctionConfiguration { this.storageSize = storageSize; this.instanceSize = instanceSize; this.maxConcurrentRequestsPerInstance = maxConcurrentRequestsPerInstance; + this.port = port; } } diff --git a/src/utils/scripts.ts b/src/utils/scripts.ts index 5f80ab5ab..58fdfabea 100644 --- a/src/utils/scripts.ts +++ b/src/utils/scripts.ts @@ -106,7 +106,7 @@ export async function resolveConfigurationVariable( isLocal?: boolean; port?: number; }, -): Promise { +): Promise { if (options?.isLocal && !options?.port) { options.port = PORT_LOCAL_ENVIRONMENT; } @@ -141,6 +141,12 @@ export async function resolveConfigurationVariable( // Retrieve custom output fields for a function object such as `url` if (field === "url") { if (options?.isLocal) { + if (functionObj.type === FunctionType.httpServer) { + const port = + process.env[`${functionObj.name.replace(/-/g, "_").toUpperCase()}_PORT`] || + "8080"; + return `http://localhost:${port}`; + } return `http://localhost:${options.port}/.functions/function-${functionObj.name}`; } From f1c2043c6220113621716c953b2ae99e0b48dc8c Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 15:41:24 +0200 Subject: [PATCH 20/75] Add port --- src/models/projectConfiguration.ts | 1 + src/projectConfiguration/yaml/v2.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/models/projectConfiguration.ts b/src/models/projectConfiguration.ts index c0a1b8818..53ef10cef 100644 --- a/src/models/projectConfiguration.ts +++ b/src/models/projectConfiguration.ts @@ -304,6 +304,7 @@ export class ProjectConfiguration { storageSize: f.storageSize, instanceSize: f.instanceSize, maxConcurrentRequestsPerInstance: f.maxConcurrentRequestsPerInstance, + port: f.port, }; }) || []; } diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 7a7a9d6b1..dfa25f23b 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -123,6 +123,7 @@ function parseGenezioConfig(config: unknown) { storageSize: zod.number().optional(), instanceSize: zod.nativeEnum(InstanceSize).optional(), maxConcurrentRequestsPerInstance: zod.number().optional(), + port: zod.number().optional(), }) .refine( ({ type, handler }) => !(type === FunctionType.aws && !handler), From 7d1abcb0ef30820133dfdfffe71c05071653ff52 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 15:55:47 +0200 Subject: [PATCH 21/75] small fix --- src/utils/scripts.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/scripts.ts b/src/utils/scripts.ts index 58fdfabea..bdc0ec5bb 100644 --- a/src/utils/scripts.ts +++ b/src/utils/scripts.ts @@ -142,9 +142,7 @@ export async function resolveConfigurationVariable( if (field === "url") { if (options?.isLocal) { if (functionObj.type === FunctionType.httpServer) { - const port = - process.env[`${functionObj.name.replace(/-/g, "_").toUpperCase()}_PORT`] || - "8080"; + const port = functionObj.port || 8080; return `http://localhost:${port}`; } return `http://localhost:${options.port}/.functions/function-${functionObj.name}`; From 64d4028a3294fb91a87ee6e75cb1bff55b8f8ae7 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 16:52:37 +0200 Subject: [PATCH 22/75] improv --- src/commands/local.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 941704af7..9906b621c 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -42,6 +42,7 @@ import { Language, startingCommandMap, TriggerType, + FunctionType, } from "../projectConfiguration/yaml/models.js"; import { YAMLBackend, @@ -638,8 +639,8 @@ async function startProcesses( // if handlerProvider is Http if ( - functionInfo.type === "httpServer" && - (functionInfo.language === "js" || functionInfo.language === "ts") + functionInfo.type === FunctionType.httpServer && + (functionInfo.language === Language.js || functionInfo.language === Language.ts) ) { log.error("We recommend to run the HTTP server with `node` or `npm start`."); process.exit(1); From d62bf06bd448ef6296d2fef9f76fdb0e070ba78c Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 16:53:25 +0200 Subject: [PATCH 23/75] improv --- src/commands/local.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 9906b621c..87a8a3ee4 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -646,7 +646,10 @@ async function startProcesses( process.exit(1); } - if (functionInfo.type === "httpServer" && functionInfo.language === "python") { + if ( + functionInfo.type === FunctionType.httpServer && + functionInfo.language === Language.python + ) { log.error("We recommend to run the HTTP server with `python` or `python3`."); process.exit(1); } From fc0e31cf91cfa8d0e45f11b3dc107a480790a149 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 19 Nov 2024 17:03:29 +0200 Subject: [PATCH 24/75] fix --- src/commands/local.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 89cfcf5c9..43064b030 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -47,7 +47,6 @@ import { Language, startingCommandMap, TriggerType, - FunctionType, } from "../projectConfiguration/yaml/models.js"; import { YAMLBackend, From 5121c5bd48ee7d459980f56268975d41f9d7407f Mon Sep 17 00:00:00 2001 From: Stefan Iordache Date: Tue, 19 Nov 2024 16:37:33 +0200 Subject: [PATCH 25/75] ignore reinclusion rules in .gitignore --- src/commands/deploy/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/deploy/utils.ts b/src/commands/deploy/utils.ts index 4f6078e67..0e541dc3a 100644 --- a/src/commands/deploy/utils.ts +++ b/src/commands/deploy/utils.ts @@ -976,7 +976,9 @@ const excludedFiles = [ function getGitIgnorePatterns(cwd: string): string[] { const gitIgnorePath = path.join(cwd, ".gitignore"); if (existsSync(gitIgnorePath)) { - return gitignore.parse(readFileSync(gitIgnorePath)).patterns; + return gitignore + .parse(readFileSync(gitIgnorePath)) + .patterns.filter((pattern) => !pattern.startsWith("!")); } return []; From 3515eb9840ca0f693552411b4805d20db203ecc2 Mon Sep 17 00:00:00 2001 From: Stefan Iordache Date: Tue, 19 Nov 2024 18:48:41 +0200 Subject: [PATCH 26/75] implement logic for reincluding files --- src/commands/deploy/utils.ts | 42 ++++++++++++++++++++++++++---------- src/utils/file.ts | 29 ++++++++++++++++--------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/commands/deploy/utils.ts b/src/commands/deploy/utils.ts index 0e541dc3a..ac7236918 100644 --- a/src/commands/deploy/utils.ts +++ b/src/commands/deploy/utils.ts @@ -973,28 +973,46 @@ const excludedFiles = [ ".env.local", ]; -function getGitIgnorePatterns(cwd: string): string[] { +type Patterns = { + exclude: string[]; + reinclude: string[]; +}; + +function getGitIgnorePatterns(cwd: string): Patterns { const gitIgnorePath = path.join(cwd, ".gitignore"); if (existsSync(gitIgnorePath)) { - return gitignore - .parse(readFileSync(gitIgnorePath)) - .patterns.filter((pattern) => !pattern.startsWith("!")); + return { + exclude: gitignore + .parse(readFileSync(gitIgnorePath)) + .patterns.filter((pattern) => !pattern.startsWith("!")), + reinclude: gitignore + .parse(readFileSync(gitIgnorePath)) + .patterns.filter((pattern) => pattern.startsWith("!")) + .map((pattern) => pattern.slice(1)), + }; } - return []; + return { exclude: [], reinclude: [] }; } -function getAllGitIgnorePatterns(cwd: string): string[] { - let patterns: string[] = getGitIgnorePatterns(cwd); +function getAllGitIgnorePatterns(cwd: string): Patterns { + const patterns: Patterns = getGitIgnorePatterns(cwd); readdirSync(cwd, { withFileTypes: true }).forEach((file) => { if ( file.isDirectory() && !file.name.startsWith(".") && !file.name.startsWith("node_modules") ) { - patterns = [ - ...patterns, - ...getAllGitIgnorePatterns(path.join(cwd, file.name)).map((pattern) => + const newPatterns = getAllGitIgnorePatterns(path.join(cwd, file.name)); + patterns.exclude = [ + ...patterns.exclude, + ...newPatterns.exclude.map((pattern) => + path.join(path.relative(cwd, path.join(cwd, file.name)), pattern), + ), + ]; + patterns.reinclude = [ + ...patterns.reinclude, + ...newPatterns.reinclude.map((pattern) => path.join(path.relative(cwd, path.join(cwd, file.name)), pattern), ), ]; @@ -1012,11 +1030,13 @@ export async function uploadUserCode( ): Promise { const tmpFolderProject = await createTemporaryFolder(); debugLogger.debug(`Creating archive of the project in ${tmpFolderProject}`); + const { exclude, reinclude } = getAllGitIgnorePatterns(cwd); const promiseZip = zipDirectory( cwd, path.join(tmpFolderProject, "projectCode.zip"), true, - excludedFiles.concat(getAllGitIgnorePatterns(cwd)), + excludedFiles.concat(exclude), + reinclude, ); await promiseZip; diff --git a/src/utils/file.ts b/src/utils/file.ts index 775a4bd55..244ab7583 100644 --- a/src/utils/file.ts +++ b/src/utils/file.ts @@ -106,7 +106,8 @@ export async function zipDirectory( sourceDir: string, outPath: string, includeHiddenFiles: boolean = false, - exclusion?: string[], + exclusion: string[] = [], + reinclusion: string[] = [], ): Promise { const archive = archiver("zip", { zlib: { level: 9 } }); const stream = fs.createWriteStream(outPath); @@ -116,17 +117,25 @@ export async function zipDirectory( } return new Promise((resolve, reject) => { - archive - .glob("**/*", { + archive.on("error", (err) => reject(err)); + archive.pipe(stream); + + archive.glob("**/*", { + cwd: sourceDir, + dot: includeHiddenFiles, + // skip deals with directories, it doesn't allow any children to be returned + skip: exclusion, + // ignore deals with files, it doesn't prevent files from folder content to be returned + ignore: exclusion, + }); + + if (reinclusion.length > 0) { + archive.glob("**/*", { cwd: sourceDir, dot: includeHiddenFiles, - // skip deals with directories, it doesn't allow any children to be returned - skip: exclusion, - // ignore deals with files, it doesn't prevent files from folder content to be returned - ignore: exclusion, - }) - .on("error", (err) => reject(err)) - .pipe(stream); + pattern: reinclusion, + }); + } stream.on("close", () => resolve()); archive.finalize(); From ea0377150d1e7bdeb83b690348a2586fbbe22dd1 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Wed, 20 Nov 2024 09:30:19 +0200 Subject: [PATCH 27/75] Fix path entryfile for httpServer --- package-lock.json | 1 - src/commands/deploy/genezio.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f56375ff..bebe0ecbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index e02cc47f5..c7782a448 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -675,7 +675,7 @@ export async function functionToCloudInput( // Determine entry file name let entryFileName; if (functionElement.type === "httpServer") { - entryFileName = functionElement.entry; // Use the entry file for httpServer + entryFileName = path.join(functionElement.path, functionElement.entry); } else { entryFileName = entryFileFunctionMap[functionElement.language as keyof typeof entryFileFunctionMap]; From b07ab8a5bd69dd0dce55c784609657ed96468087 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Wed, 20 Nov 2024 09:59:40 +0200 Subject: [PATCH 28/75] fix windows path --- src/commands/deploy/genezio.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index c7782a448..87be91fe3 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -675,7 +675,7 @@ export async function functionToCloudInput( // Determine entry file name let entryFileName; if (functionElement.type === "httpServer") { - entryFileName = path.join(functionElement.path, functionElement.entry); + entryFileName = path.join(functionElement.path, functionElement.entry).replace(/\\/g, "/"); } else { entryFileName = entryFileFunctionMap[functionElement.language as keyof typeof entryFileFunctionMap]; From e72dd8e528bb321bf48d40d219141ad1f64250a3 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Wed, 20 Nov 2024 11:56:15 +0200 Subject: [PATCH 29/75] use deployClasses result for func URL instead of separate endpoint --- src/commands/deploy/genezio.ts | 44 +++++++++++++++-------------- src/commands/local.ts | 4 +-- src/models/requests.ts | 5 ---- src/projectConfiguration/yaml/v2.ts | 33 ++++++---------------- src/requests/function.ts | 16 +---------- src/utils/yaml.ts | 14 +++++++++ 6 files changed, 48 insertions(+), 68 deletions(-) diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index 6bdc42a11..1a63e03c8 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -85,7 +85,6 @@ import { expandEnvironmentVariables, findAnEnvFile } from "../../utils/environme import { getProjectEnvFromProjectByName } from "../../requests/getProjectInfoByName.js"; import { getFunctionHandlerProvider } from "../../utils/getFunctionHandlerProvider.js"; import { getFunctionEntryFilename } from "../../utils/getFunctionEntryFilename.js"; -import { getFunctions } from "../../requests/function.js"; import { CronDetails } from "../../models/requests.js"; import { syncCrons } from "../../requests/crons.js"; import { getPackageManager } from "../../packageManagers/packageManager.js"; @@ -235,12 +234,8 @@ export async function genezioDeploy(options: GenezioDeployOptions) { } if (configuration.services?.crons) { - const res = await getFunctions(deployClassesResult?.projectEnvId || "").catch(() => { - throw new UserError("Something went wrong while fetching the cron functions."); - }); const crons: CronDetails[] = []; for (const cron of configuration.services.crons) { - let cronFound = false; const yamlFunctionName = await evaluateResource( configuration, cron.function, @@ -248,30 +243,33 @@ export async function genezioDeploy(options: GenezioDeployOptions) { undefined, undefined, ); - for (const deployedFunction of res.functions) { - if (deployedFunction.name === `function-${yamlFunctionName}`) { - crons.push({ - name: cron.name, - url: deployedFunction.cloudUrl, - endpoint: cron.endpoint || "", - cronString: cron.schedule, - }); - cronFound = true; - break; - } + if (!deployClassesResult) { + throw new UserError( + "Could not deploy cron jobs. Please make sure your backend is deployed before adding cron jobs.", + ); } - if (!cronFound) { + const functions = deployClassesResult.functions ?? []; + const cronFunction = functions.find((f) => f.name === `function-${yamlFunctionName}`); + if (!cronFunction) { throw new UserError( - `Function ${yamlFunctionName} not found in the deployed functions. Please make sure the function is deployed before adding it to the cron.`, + `Function ${yamlFunctionName} not found. Please make sure the function is deployed before adding cron jobs.`, ); } + crons.push({ + name: cron.name, + url: cronFunction.cloudUrl, + endpoint: cron.endpoint || "", + cronString: cron.schedule, + }); } await syncCrons({ projectName: projectName, stageName: options.stage || "prod", crons: crons, - }).catch(() => { - throw new UserError("Something went wrong while syncing the cron jobs."); + }).catch((error) => { + throw new UserError( + `Something went wrong while syncing the cron jobs.\n${error}\nPlease try to redeploy your project. If the problem persists, please contact support at contact@genez.io.`, + ); }); } else { await syncCrons({ @@ -279,7 +277,9 @@ export async function genezioDeploy(options: GenezioDeployOptions) { stageName: options.stage || "prod", crons: [], }).catch(() => { - throw new UserError("Something went wrong while syncing the cron jobs."); + throw new UserError( + "Something went wrong while syncing the cron jobs. Please try to redeploy your project. If the problem persists, please contact support at contact@genez.io.", + ); }); } @@ -629,6 +629,8 @@ export async function deployClasses( return { projectId: projectId, projectEnvId: projectEnvId, + functions: result.functions, + classes: result.classes, }; } } diff --git a/src/commands/local.ts b/src/commands/local.ts index 17ad8d03d..a36878087 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1069,7 +1069,7 @@ async function startCronJobs( ); const endpoint = cronService.endpoint?.replace(/^\//, ""); const cronString = cronService.schedule; - const baseURL = `http://localhost:${port}/.functions/${functionName}`; + const baseURL = `http://localhost:${port}/.functions/function-${functionName}`; let url: string; if (endpoint) { url = `${baseURL}/${endpoint}`; @@ -1089,7 +1089,7 @@ async function startCronJobs( " on function " + functionName, ); - return await axios.post(url); + await axios.post(url); }); cronHandler.cronObject.start(); diff --git a/src/models/requests.ts b/src/models/requests.ts index a80a6b41f..970af755e 100644 --- a/src/models/requests.ts +++ b/src/models/requests.ts @@ -196,11 +196,6 @@ export type FunctionDetails = { updatedAt: number; }; -export type GetFunctionsResponse = { - status: string; - functions: FunctionDetails[]; -}; - export type CreateFunctionRequest = { projectName: string; stageName: string; diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 9b02d4988..1bb5393c9 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -25,12 +25,15 @@ import { isValidCron } from "cron-validator"; import { tryV2Migration } from "./migration.js"; import yaml, { YAMLParseError } from "yaml"; import { DeepRequired } from "../../utils/types.js"; +import { isUnique } from "../../utils/yaml.js"; export type RawYamlProjectConfiguration = ReturnType; export type YAMLBackend = NonNullable; export type YAMLLanguage = NonNullable; export type YamlClass = NonNullable[number]; export type YamlFunction = NonNullable[number]; +export type YamlServices = NonNullable; +export type YamlCron = NonNullable[number]; export type YamlMethod = NonNullable[number]; export type YamlFrontend = NonNullable[number]; export type YamlContainer = NonNullable; @@ -158,15 +161,7 @@ function parseGenezioConfig(config: unknown) { } return true; - }, "The cronString is not valid. Check https://crontab.guru/ for more information.") - .refine(({ schedule }) => { - const cronParts = schedule?.split(" "); - if (cronParts && cronParts[2] != "*" && cronParts[4] != "*") { - return false; - } - - return true; - }, "The day of the month and day of the week cannot be specified at the same time."); + }, "The cronString is not valid. Check https://crontab.guru/ for more information."); const redirectUrlSchema = zod.string(); @@ -213,14 +208,8 @@ function parseGenezioConfig(config: unknown) { crons: zod.array(cronSchema).optional(), }) .refine(({ crons }) => { - const cronNamesMap = new Map(); - for (const cron of crons || []) { - if (cronNamesMap.has(cron.name)) { - return false; - } - cronNamesMap.set(cron.name, cron.name); - } - return true; + const isUniqueCron = isUnique(crons ?? [], "name"); + return isUniqueCron; }, `You can't have two crons with the same name.`); const backendSchema = zod @@ -238,14 +227,8 @@ function parseGenezioConfig(config: unknown) { functions: zod.array(functionsSchema).optional(), }) .refine(({ functions }) => { - const functionNamesMap = new Map(); - for (const func of functions || []) { - if (functionNamesMap.has(func.name)) { - return false; - } - functionNamesMap.set(func.name, func.name); - } - return true; + const isUniqueFunction = isUnique(functions ?? [], "name"); + return isUniqueFunction; }, `You can't have two functions with the same name.`); const frontendSchema = zod.object({ diff --git a/src/requests/function.ts b/src/requests/function.ts index 321afc61e..2bdefad0b 100644 --- a/src/requests/function.ts +++ b/src/requests/function.ts @@ -1,8 +1,4 @@ -import { - CreateFunctionRequest, - CreateFunctionResponse, - GetFunctionsResponse, -} from "../models/requests.js"; +import { CreateFunctionRequest, CreateFunctionResponse } from "../models/requests.js"; import sendRequest from "../utils/requests.js"; export async function createFunction( @@ -32,13 +28,3 @@ export async function createFunction( return createFunctionResponse; } - -export async function getFunctions(envId: string): Promise { - const getFunctionsResponse = (await sendRequest( - "GET", - `functions/all/${envId}`, - "", - )) as GetFunctionsResponse; - - return getFunctionsResponse; -} diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index 5c0f4cccc..779d2e66d 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -1,4 +1,5 @@ import { uniqueNamesGenerator, adjectives, colors, animals } from "unique-names-generator"; +import { YamlCron, YamlFunction } from "../projectConfiguration/yaml/v2.js"; export function generateRandomSubdomain(): string { const name: string = uniqueNamesGenerator({ @@ -10,3 +11,16 @@ export function generateRandomSubdomain(): string { return name; } + +type FieldName = "name"; + +export function isUnique(units: YamlCron[] | YamlFunction[], fieldName: FieldName): boolean { + const unitMap = new Map(); + for (const unit of units || []) { + if (unitMap.has(unit[fieldName])) { + return false; + } + unitMap.set(unit[fieldName], unit[fieldName]); + } + return true; +} From ad0980f3a164ae2deef64f3146c9c8942a98cf60 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Thu, 21 Nov 2024 17:02:42 +0200 Subject: [PATCH 30/75] small fixes --- src/commands/deploy/utils.ts | 4 ++-- src/commands/local.ts | 15 +++++++++++---- src/models/requests.ts | 26 ------------------------- src/projectConfiguration/yaml/v2.ts | 2 +- src/requests/function.ts | 30 ----------------------------- src/utils/scripts.ts | 5 +++-- src/utils/yaml.ts | 11 ++++------- 7 files changed, 21 insertions(+), 72 deletions(-) delete mode 100644 src/requests/function.ts diff --git a/src/commands/deploy/utils.ts b/src/commands/deploy/utils.ts index df25563af..704c51093 100644 --- a/src/commands/deploy/utils.ts +++ b/src/commands/deploy/utils.ts @@ -660,7 +660,7 @@ export async function setAuthenticationEmailTemplates( export async function evaluateResource( configuration: YamlProjectConfiguration, resource: string | undefined, - stage: string, + stage: string | undefined, envFile: string | undefined, options?: { isLocal?: boolean; @@ -676,7 +676,7 @@ export async function evaluateResource( if ("path" in resourceRaw && "field" in resourceRaw) { const resourceValue = await resolveConfigurationVariable( configuration, - stage, + stage ?? "prod", resourceRaw.path, resourceRaw.field, options, diff --git a/src/commands/local.ts b/src/commands/local.ts index a36878087..56866aacc 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1005,7 +1005,7 @@ function getProjectFunctions( projectConfiguration: ProjectConfiguration, ): DeployCodeFunctionResponse[] { return projectConfiguration.functions.map((f) => ({ - cloudUrl: `http://localhost:${port}/.functions/${f.name}`, + cloudUrl: retrieveLocalFunctionUrl(port, f.name), id: f.name, name: f.name, })); @@ -1060,7 +1060,7 @@ async function startCronJobs( const functionName = await evaluateResource( yamlProjectConfiguration, cronService.function, - "local", + undefined, undefined, { isLocal: true, @@ -1069,7 +1069,7 @@ async function startCronJobs( ); const endpoint = cronService.endpoint?.replace(/^\//, ""); const cronString = cronService.schedule; - const baseURL = `http://localhost:${port}/.functions/function-${functionName}`; + const baseURL = retrieveLocalFunctionUrl(port, `function-${functionName}`); let url: string; if (endpoint) { url = `${baseURL}/${endpoint}`; @@ -1366,7 +1366,7 @@ function reportSuccess(projectConfiguration: ProjectConfiguration, port: number) projectConfiguration.functions.map((f) => ({ name: f.name, id: f.name, - cloudUrl: `http://localhost:${port}/.functions/${f.name}`, + cloudUrl: retrieveLocalFunctionUrl(port, f.name), })), ); } @@ -1537,3 +1537,10 @@ function formatTimestamp(date: Date) { const formattedDate = `${day}/${month}/${year}:${hours}:${minutes}:${seconds} +0000`; return formattedDate; } + +export function retrieveLocalFunctionUrl(port?: number, functionName?: string): string { + if (!port) { + port = 8080; + } + return `http://localhost:${port}/.functions/${functionName}`; +} diff --git a/src/models/requests.ts b/src/models/requests.ts index 970af755e..7e9c062c9 100644 --- a/src/models/requests.ts +++ b/src/models/requests.ts @@ -185,32 +185,6 @@ export type SetEmailTemplatesResponse = { }[]; }; -export type FunctionDetails = { - id: string; - name: string; - projectName: string; - status: string; - cloudUrl: string; - cloudDeploymentId: string; - createdAt: number; - updatedAt: number; -}; - -export type CreateFunctionRequest = { - projectName: string; - stageName: string; - function: { - name: string; - language: string; - entryFile: string; - }; -}; - -export type CreateFunctionResponse = { - status: string; - functionId: string; -}; - export type CronDetails = { name: string; url: string; diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index 1bb5393c9..3b0fdfdb5 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -161,7 +161,7 @@ function parseGenezioConfig(config: unknown) { } return true; - }, "The cronString is not valid. Check https://crontab.guru/ for more information."); + }, "The schedule expression is not valid. Please visit https://crontab.guru/ to validate it."); const redirectUrlSchema = zod.string(); diff --git a/src/requests/function.ts b/src/requests/function.ts deleted file mode 100644 index 2bdefad0b..000000000 --- a/src/requests/function.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { CreateFunctionRequest, CreateFunctionResponse } from "../models/requests.js"; -import sendRequest from "../utils/requests.js"; - -export async function createFunction( - request: CreateFunctionRequest, -): Promise { - const { - projectName, - stageName, - function: { name, language, entryFile }, - } = request; - - const data: string = JSON.stringify({ - projectName: projectName, - stageName: stageName, - function: { - name: name, - language: language, - entryFile: entryFile, - }, - }); - - const createFunctionResponse = (await sendRequest( - "POST", - "functions", - data, - )) as CreateFunctionResponse; - - return createFunctionResponse; -} diff --git a/src/utils/scripts.ts b/src/utils/scripts.ts index 5f80ab5ab..33e707b12 100644 --- a/src/utils/scripts.ts +++ b/src/utils/scripts.ts @@ -15,6 +15,7 @@ import { execaCommand } from "execa"; import { ENVIRONMENT, PORT_LOCAL_ENVIRONMENT } from "../constants.js"; import { getDatabaseByName } from "../requests/database.js"; import { getAuthentication } from "../requests/authentication.js"; +import { retrieveLocalFunctionUrl } from "../commands/local.js"; /** * Determines whether a given value is a valid `FunctionConfiguration` object. @@ -106,7 +107,7 @@ export async function resolveConfigurationVariable( isLocal?: boolean; port?: number; }, -): Promise { +): Promise { if (options?.isLocal && !options?.port) { options.port = PORT_LOCAL_ENVIRONMENT; } @@ -141,7 +142,7 @@ export async function resolveConfigurationVariable( // Retrieve custom output fields for a function object such as `url` if (field === "url") { if (options?.isLocal) { - return `http://localhost:${options.port}/.functions/function-${functionObj.name}`; + return retrieveLocalFunctionUrl(options.port, `function-${functionObj.name}`); } const response = await getProjectInfoByName(configuration.name).catch((error) => { diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index 779d2e66d..59444f1e3 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -1,5 +1,4 @@ import { uniqueNamesGenerator, adjectives, colors, animals } from "unique-names-generator"; -import { YamlCron, YamlFunction } from "../projectConfiguration/yaml/v2.js"; export function generateRandomSubdomain(): string { const name: string = uniqueNamesGenerator({ @@ -12,15 +11,13 @@ export function generateRandomSubdomain(): string { return name; } -type FieldName = "name"; - -export function isUnique(units: YamlCron[] | YamlFunction[], fieldName: FieldName): boolean { - const unitMap = new Map(); +export function isUnique(units: T[] | undefined, fieldName: keyof T): boolean { + const unitSet = new Set(); for (const unit of units || []) { - if (unitMap.has(unit[fieldName])) { + if (unitSet.has(unit[fieldName])) { return false; } - unitMap.set(unit[fieldName], unit[fieldName]); + unitSet.add(unit[fieldName]); } return true; } From 7e288ecdf615770ac32e0ad4f3213cef9aefa095 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 22 Nov 2024 10:45:42 +0200 Subject: [PATCH 31/75] handle http server function type local url retrieval --- src/commands/local.ts | 33 ++++++++++++++++++++------------- src/utils/scripts.ts | 6 +----- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 4ee8b4522..d5d23d1e3 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1037,10 +1037,7 @@ function getProjectFunctions( projectConfiguration: ProjectConfiguration, ): DeployCodeFunctionResponse[] { return projectConfiguration.functions.map((f) => ({ - cloudUrl: - f.type === FunctionType.httpServer - ? `http://localhost:${process.env[`${f.name.replace(/-/g, "_").toUpperCase()}_PORT`]}` - : retrieveLocalFunctionUrl(port, f.name), + cloudUrl: retrieveLocalFunctionUrl(f), id: f.name, name: f.name, })); @@ -1104,7 +1101,15 @@ async function startCronJobs( ); const endpoint = cronService.endpoint?.replace(/^\//, ""); const cronString = cronService.schedule; - const baseURL = retrieveLocalFunctionUrl(port, `function-${functionName}`); + const functionConfiguration = projectConfiguration.functions.find( + (f) => f.name === `function-${functionName}`, + ); + if (!functionConfiguration) { + throw new UserError( + `Function ${functionName} not found in deployed functions. Check if your function is deployed. If the problem persists, please contact support at contact@genez.io.`, + ); + } + const baseURL = retrieveLocalFunctionUrl(functionConfiguration); let url: string; if (endpoint) { url = `${baseURL}/${endpoint}`; @@ -1401,10 +1406,7 @@ function reportSuccess(projectConfiguration: ProjectConfiguration, port: number) projectConfiguration.functions.map((f) => ({ name: f.name, id: f.name, - cloudUrl: - f.type === FunctionType.httpServer - ? `http://localhost:${process.env[`${f.name.replace(/-/g, "_").toUpperCase()}_PORT`]}` - : retrieveLocalFunctionUrl(port, f.name), + cloudUrl: retrieveLocalFunctionUrl(f), })), ); } @@ -1576,9 +1578,14 @@ function formatTimestamp(date: Date) { return formattedDate; } -export function retrieveLocalFunctionUrl(port?: number, functionName?: string): string { - if (!port) { - port = 8080; +export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { + if (functionObj.type === FunctionType.httpServer) { + const envPort = process.env[`${functionObj.name.replace(/-/g, "_").toUpperCase()}_PORT`]; + if (envPort) { + return `http://localhost:${envPort}`; + } + return `http://localhost:${functionObj.port ?? 8080}`; } - return `http://localhost:${port}/.functions/${functionName}`; + + return `http://localhost:${functionObj.port ?? 8080}/.functions/${functionObj.name}`; } diff --git a/src/utils/scripts.ts b/src/utils/scripts.ts index 5c2f4cd91..8500559d7 100644 --- a/src/utils/scripts.ts +++ b/src/utils/scripts.ts @@ -142,11 +142,7 @@ export async function resolveConfigurationVariable( // Retrieve custom output fields for a function object such as `url` if (field === "url") { if (options?.isLocal) { - if (functionObj.type === FunctionType.httpServer) { - const port = functionObj.port || 8080; - return `http://localhost:${port}`; - } - return retrieveLocalFunctionUrl(options.port, `function-${functionObj.name}`); + return retrieveLocalFunctionUrl(functionObj); } const response = await getProjectInfoByName(configuration.name).catch((error) => { From e0a16a8c2116635ce7119f82e63cbaf409998478 Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 22 Nov 2024 11:03:54 +0200 Subject: [PATCH 32/75] remove http server function ports from env --- src/commands/local.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index d5d23d1e3..54a124b9e 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -654,10 +654,6 @@ async function startProcesses( functionInfo.type === FunctionType.httpServer && (functionInfo.language === Language.js || functionInfo.language === Language.ts) ) { - process.env[`${functionInfo.name.replace(/-/g, "_").toUpperCase()}_PORT`] = ( - functionInfo.port || 8080 - ).toString(); - return { configuration: functionInfo, extra: { @@ -674,10 +670,6 @@ async function startProcesses( functionInfo.type === FunctionType.httpServer && functionInfo.language === Language.python ) { - process.env[`${functionInfo.name.replace(/-/g, "_").toUpperCase()}_PORT`] = ( - functionInfo.port || 8080 - ).toString(); - return { configuration: functionInfo, extra: { @@ -1580,10 +1572,6 @@ function formatTimestamp(date: Date) { export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { if (functionObj.type === FunctionType.httpServer) { - const envPort = process.env[`${functionObj.name.replace(/-/g, "_").toUpperCase()}_PORT`]; - if (envPort) { - return `http://localhost:${envPort}`; - } return `http://localhost:${functionObj.port ?? 8080}`; } From d59e7528f76d3c6f759f1549de966589f36ffcfe Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 22 Nov 2024 11:15:08 +0200 Subject: [PATCH 33/75] fix port issues --- src/commands/local.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 54a124b9e..251ad7910 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1572,8 +1572,8 @@ function formatTimestamp(date: Date) { export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { if (functionObj.type === FunctionType.httpServer) { - return `http://localhost:${functionObj.port ?? 8080}`; + return `http://localhost:${functionObj.port ?? 8083}`; } - return `http://localhost:${functionObj.port ?? 8080}/.functions/${functionObj.name}`; + return `http://localhost:${functionObj.port ?? 8083}/.functions/${functionObj.name}`; } From 489f60d5ca89352181e007c7501703fbcc80058a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 11:52:44 +0200 Subject: [PATCH 34/75] Check if file exists and log an error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The analyze command should throw or forcefully exist when we cannot salvage it. Here we can log the error and let the process continue with defaults. Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 4578e08c7..c952a6faf 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -657,13 +657,19 @@ export const findKeyFiles = async ( // Method to read the contents of a file async function retrieveFileContent(filePath: string): Promise { - // check if file exists + try { + await fs.access(filePath); + } catch (error) { + log.error(`Cannot access ${filePath}: ${error}`); + return ""; + } try { + // Read and return the file content const fileContent = await fs.readFile(filePath, "utf-8"); return fileContent; } catch (error) { - log.error("Error reading package.json:", error); + log.error(`Error reading file at ${filePath}: ${error}`); return ""; } } From fbb7193c76b00780d8074475161d1f372965ae96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 11:55:00 +0200 Subject: [PATCH 35/75] Fix Flask pattern to allow multiple arguments at Flask object init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/analyze/constants.ts b/src/commands/analyze/constants.ts index 58047eab5..1133febc9 100644 --- a/src/commands/analyze/constants.ts +++ b/src/commands/analyze/constants.ts @@ -22,7 +22,7 @@ export const SERVERLESS_HTTP_PATTERN = [ export const FLASK_PATTERN = [ /from\s+flask\s+import\s+Flask|import\s+flask/, - /\w+\s*=\s*[Ff]lask\(__name__\)/, + /\w+\s*=\s*[Ff]lask\(\s*__name__[^)]*\)/, ]; export const DJANGO_PATTERN = [ From 386c40c2e2d05f448fc15e39d2c0bb468294ba86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 11:55:57 +0200 Subject: [PATCH 36/75] Add more directories to the excludede list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index c952a6faf..4a045afd0 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -96,7 +96,7 @@ export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; export const KEY_FILES = ["package.json", "Dockerfile", "requirements.txt"]; export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; export const ENVIRONMENT_EXAMPLE_FILES = [".env.template", ".env.example", ".env.local.example"]; -export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build"]; +export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build", "static", "tests"]; export const NODE_DEFAULT_ENTRY_FILE = "index.mjs"; export const PYTHON_DEFAULT_ENTRY_FILE = "app.py"; From 0aa90dd754ce11097c1efc3a9b4c2dc13c320b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 12:03:16 +0200 Subject: [PATCH 37/75] Fix Django and FastAPI pattern to allow arguments in the constructor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/analyze/constants.ts b/src/commands/analyze/constants.ts index 1133febc9..6a997b27e 100644 --- a/src/commands/analyze/constants.ts +++ b/src/commands/analyze/constants.ts @@ -27,13 +27,13 @@ export const FLASK_PATTERN = [ export const DJANGO_PATTERN = [ /from\s+django\.core\.wsgi\s+import\s+get_wsgi_application|from\s+django\.core\.asgi\s+import\s+get_asgi_application/, - /application\s*=\s*get_wsgi_application\(\)|application\s*=\s*get_asgi_application\(\)/, + /application\s*=\s*get_wsgi_application\([^)]*\)|application\s*=\s*get_asgi_application\([^)]*\)/, ]; export const PYTHON_LAMBDA_PATTERN = [/def\s+handler\s*\(\s*event\s*\):/]; export const FASTAPI_PATTERN = [ - /\w+\s*=\s*FastAPI\(\)/, + /\w+\s*=\s*FastAPI\([^)]*\)/, /from\s+fastapi\s+import\s+FastAPI|import\s+fastapi/, ]; From 4d4d2a0204653a90f85a178c7edcbec690249991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 12:33:55 +0200 Subject: [PATCH 38/75] Fix relative path for reading entry files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 4a045afd0..1b714cc70 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -434,7 +434,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { FLASK_PATTERN, PYTHON_DEFAULT_ENTRY_FILE, ); - const entryFileContent = await retrieveFileContent(path.join(componentPath, entryFile)); + const entryFileContent = await retrieveFileContent(entryFile); const pythonHandler = getPythonHandler(entryFileContent); await addBackendComponentToConfig(configPath, { @@ -460,7 +460,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { } if (await isDjangoComponent(contents)) { - const entryfile = await findEntryFile( + const entryFile = await findEntryFile( componentPath, contents, DJANGO_PATTERN, @@ -477,7 +477,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { name: "django", path: ".", handler: "application", - entry: entryfile, + entry: entryFile, type: FunctionType.httpServer, }, ], @@ -489,14 +489,14 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { } if (await isFastAPIComponent(contents)) { - const entryfile = await findEntryFile( + const entryFile = await findEntryFile( componentPath, contents, FASTAPI_PATTERN, PYTHON_DEFAULT_ENTRY_FILE, ); - const entryFileContent = await retrieveFileContent(path.join(componentPath, entryfile)); + const entryFileContent = await retrieveFileContent(entryFile); const pythonHandler = getPythonHandler(entryFileContent); await addBackendComponentToConfig(configPath, { @@ -510,7 +510,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { name: "fastapi", path: ".", handler: pythonHandler, - entry: entryfile, + entry: entryFile, type: FunctionType.httpServer, }, ], @@ -522,7 +522,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { } if (await isPythonLambdaFunction(contents)) { - const entryfile = await findEntryFile( + const entryFile = await findEntryFile( componentPath, contents, PYTHON_LAMBDA_PATTERN, @@ -539,7 +539,7 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { name: "serverless", path: ".", handler: "handler", - entry: entryfile, + entry: entryFile, type: FunctionType.aws, }, ], From e3365e0e0094189901a10415e1a2a6fa7867f9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 12:36:14 +0200 Subject: [PATCH 39/75] Temporarily revert detecting containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 4578e08c7..7c82e8fa1 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -14,7 +14,6 @@ import { isVueComponent, isAngularComponent, isSvelteComponent, - isContainerComponent, isFlaskComponent, isDjangoComponent, isFastAPIComponent, @@ -35,7 +34,6 @@ import { } from "../../projectConfiguration/yaml/v2.js"; import { addBackendComponentToConfig, - addContainerComponentToConfig, addFrontendComponentToConfig, addServicesToConfig, addSSRComponentToConfig, @@ -93,7 +91,7 @@ export enum SUPPORTED_FORMATS { export const DEFAULT_FORMAT = SUPPORTED_FORMATS.TEXT; export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; -export const KEY_FILES = ["package.json", "Dockerfile", "requirements.txt"]; +export const KEY_FILES = ["package.json", "requirements.txt"]; export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; export const ENVIRONMENT_EXAMPLE_FILES = [".env.template", ".env.example", ".env.local.example"]; export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build"]; @@ -400,16 +398,6 @@ export async function analyzeCommand(options: GenezioAnalyzeOptions) { continue; } - if (await isContainerComponent(contents)) { - addContainerComponentToConfig(configPath, { - path: componentPath, - }); - - frameworksDetected.backend = frameworksDetected.backend || []; - frameworksDetected.backend.push("container"); - continue; - } - if (await isGenezioTypesafe(contents)) { await addBackendComponentToConfig(configPath, { path: componentPath, From a1ec223463d83a79d42f6a0c613ef60f8745534f Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Fri, 22 Nov 2024 12:43:20 +0200 Subject: [PATCH 40/75] small comment --- src/requests/crons.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/requests/crons.ts b/src/requests/crons.ts index d6b5f079d..d96b50086 100644 --- a/src/requests/crons.ts +++ b/src/requests/crons.ts @@ -1,6 +1,9 @@ import { SyncCronsRequest, SyncCronsResponse } from "../models/requests.js"; import sendRequest from "../utils/requests.js"; +// This request will start all the crons jobs sent in the request body +// and will stop/delete all the crons that are not in the request body +// If the request body is empty, it will stop/delete all the crons export async function syncCrons(request: SyncCronsRequest): Promise { const { projectName, stageName, crons } = request; From c5502a341ace2dc146ac99858a6df88db8fdfa69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Fri, 22 Nov 2024 12:55:53 +0200 Subject: [PATCH 41/75] Update excluded directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 7c1785453..b737ae52f 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -94,7 +94,7 @@ export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; export const KEY_FILES = ["package.json", "requirements.txt"]; export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; export const ENVIRONMENT_EXAMPLE_FILES = [".env.template", ".env.example", ".env.local.example"]; -export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build", "static", "tests"]; +export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build", "tests"]; export const NODE_DEFAULT_ENTRY_FILE = "index.mjs"; export const PYTHON_DEFAULT_ENTRY_FILE = "app.py"; From ae7633d9f41dc1068013b31ce7890972a1fe5d91 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Fri, 22 Nov 2024 13:08:02 +0200 Subject: [PATCH 42/75] Fix path http --- src/commands/local.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 43064b030..fb5ec89d4 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -657,7 +657,7 @@ async function startProcesses( extra: { type: "function" as const, startingCommand: "node", - commandParameters: [functionInfo.entry], + commandParameters: [path.resolve(functionInfo.path, functionInfo.entry)], handlerType: FunctionType.httpServer, }, }; @@ -677,7 +677,7 @@ async function startProcesses( extra: { type: "function" as const, startingCommand: (await detectPythonCommand()) || "python", - commandParameters: [functionInfo.entry], + commandParameters: [path.resolve(functionInfo.path, functionInfo.entry)], handlerType: FunctionType.httpServer, }, }; From 28c0110d3af414a9446a35ab3baf4e4460c01aa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:28:56 +0000 Subject: [PATCH 43/75] Bump @rollup/rollup-linux-x64-musl from 4.24.3 to 4.27.4 Bumps [@rollup/rollup-linux-x64-musl](https://github.com/rollup/rollup) from 4.24.3 to 4.27.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.24.3...v4.27.4) --- updated-dependencies: - dependency-name: "@rollup/rollup-linux-x64-musl" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 22 ++++++++++++++++++---- package.json | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index bebe0ecbf..d7e4fab34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", + "@rollup/rollup-linux-x64-musl": "4.27.4", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", @@ -131,7 +132,7 @@ "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.22.5", - "@rollup/rollup-linux-x64-musl": "4.24.3", + "@rollup/rollup-linux-x64-musl": "4.27.4", "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" @@ -4343,9 +4344,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.3.tgz", - "integrity": "sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", "cpu": [ "x64" ], @@ -10959,6 +10960,19 @@ "linux" ] }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.3.tgz", + "integrity": "sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/rollup/node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.24.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.3.tgz", diff --git a/package.json b/package.json index 2089b6d80..58be1a596 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.22.5", - "@rollup/rollup-linux-x64-musl": "4.24.3", + "@rollup/rollup-linux-x64-musl": "4.27.4", "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" From ebfa0c2bd3d7b955fb70a4b14bc9b8111221c0ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:29:11 +0000 Subject: [PATCH 44/75] Bump yaml from 2.5.0 to 2.6.1 Bumps [yaml](https://github.com/eemeli/yaml) from 2.5.0 to 2.6.1. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.5.0...v2.6.1) --- updated-dependencies: - dependency-name: yaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 19 ++++++++++++++++--- package.json | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index bebe0ecbf..594e4ae73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,7 @@ "uuid": "^11.0.3", "whatwg-mimetype": "~3.0.0", "which": "^5.0.0", - "yaml": "^2.5.0", + "yaml": "^2.6.1", "yaml-transmute": "^0.0.7", "zod": "^3.23.8" }, @@ -9251,6 +9251,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/listr2": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", @@ -12321,8 +12333,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.5.0", - "license": "ISC", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 2089b6d80..050eecff0 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "uuid": "^11.0.3", "whatwg-mimetype": "~3.0.0", "which": "^5.0.0", - "yaml": "^2.5.0", + "yaml": "^2.6.1", "yaml-transmute": "^0.0.7", "zod": "^3.23.8" }, From 6e78112077d091f20105d44c1a033feadc8bd4f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:32:03 +0000 Subject: [PATCH 45/75] Bump @rollup/rollup-linux-x64-gnu from 4.22.5 to 4.27.4 Bumps [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) from 4.22.5 to 4.27.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.22.5...v4.27.4) --- updated-dependencies: - dependency-name: "@rollup/rollup-linux-x64-gnu" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c9aa056a..ed74bdc29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", @@ -131,7 +131,7 @@ "@rollup/rollup-linux-arm64-gnu": "4.24.3", "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.22.5", + "@rollup/rollup-linux-x64-gnu": "4.27.4", "@rollup/rollup-linux-x64-musl": "4.27.4", "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", @@ -4332,9 +4332,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz", - "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", "cpu": [ "x64" ], diff --git a/package.json b/package.json index 1ba933d67..bca69fe60 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "@rollup/rollup-linux-arm64-gnu": "4.24.3", "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.22.5", + "@rollup/rollup-linux-x64-gnu": "4.27.4", "@rollup/rollup-linux-x64-musl": "4.27.4", "@rollup/rollup-win32-arm64-msvc": "4.27.2", "@rollup/rollup-win32-ia32-msvc": "4.22.4", From 2bb64024026ed1a77836ead33c7bd0a2d0a4ae78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:34:59 +0000 Subject: [PATCH 46/75] Bump @rollup/rollup-linux-arm64-gnu from 4.24.3 to 4.27.4 Bumps [@rollup/rollup-linux-arm64-gnu](https://github.com/rollup/rollup) from 4.24.3 to 4.27.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.24.3...v4.27.4) --- updated-dependencies: - dependency-name: "@rollup/rollup-linux-arm64-gnu" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 23 ++++++++++++++++++----- package.json | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed74bdc29..885aa3662 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", @@ -128,7 +128,7 @@ "@rollup/rollup-darwin-arm64": "4.24.0", "@rollup/rollup-darwin-x64": "4.18.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.27.4", @@ -4270,9 +4270,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.3.tgz", - "integrity": "sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", "cpu": [ "arm64" ], @@ -10933,6 +10933,19 @@ "linux" ] }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.3.tgz", + "integrity": "sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.24.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.3.tgz", diff --git a/package.json b/package.json index bca69fe60..2907f9ed7 100644 --- a/package.json +++ b/package.json @@ -160,7 +160,7 @@ "@rollup/rollup-darwin-arm64": "4.24.0", "@rollup/rollup-darwin-x64": "4.18.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", "@rollup/rollup-linux-arm64-musl": "4.25.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.27.4", From 34daa0b885195af4021f3c71de91d91ac65de744 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:37:44 +0000 Subject: [PATCH 47/75] Bump @rollup/rollup-win32-arm64-msvc from 4.27.2 to 4.27.4 Bumps [@rollup/rollup-win32-arm64-msvc](https://github.com/rollup/rollup) from 4.27.2 to 4.27.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.27.2...v4.27.4) --- updated-dependencies: - dependency-name: "@rollup/rollup-win32-arm64-msvc" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 885aa3662..3ca6e4cc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", @@ -133,7 +133,7 @@ "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.27.4", "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.2", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" } @@ -4356,9 +4356,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.2.tgz", - "integrity": "sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", "cpu": [ "arm64" ], diff --git a/package.json b/package.json index 2907f9ed7..641127db4 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.27.4", "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.2", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", "@rollup/rollup-win32-ia32-msvc": "4.22.4", "@rollup/rollup-win32-x64-msvc": "4.24.2" }, From a756cfe61bd055f912e29babbb4a9ba93e79c0dd Mon Sep 17 00:00:00 2001 From: Virgil993 Date: Mon, 25 Nov 2024 15:35:40 +0200 Subject: [PATCH 48/75] improve cron terminal output --- src/commands/deploy/genezio.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index 0007070f1..01ec5904e 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -236,6 +236,7 @@ export async function genezioDeploy(options: GenezioDeployOptions) { } if (configuration.services?.crons) { + printAdaptiveLog("Deploying cron jobs\n", "start"); const crons: CronDetails[] = []; for (const cron of configuration.services.crons) { const yamlFunctionName = await evaluateResource( @@ -269,10 +270,12 @@ export async function genezioDeploy(options: GenezioDeployOptions) { stageName: options.stage || "prod", crons: crons, }).catch((error) => { + printAdaptiveLog("Deploying cron jobs\n", "error"); throw new UserError( `Something went wrong while syncing the cron jobs.\n${error}\nPlease try to redeploy your project. If the problem persists, please contact support at contact@genez.io.`, ); }); + printAdaptiveLog("Cron Jobs deployed successfully\n", "end"); } else { await syncCrons({ projectName: projectName, From 5724978123ad0904e82254c61eb61bace182b056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 25 Nov 2024 16:07:19 +0200 Subject: [PATCH 49/75] Remove addHelpCommand because it's deprecated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/genezio.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/genezio.ts b/src/genezio.ts index f3b03f592..0dc88bed1 100644 --- a/src/genezio.ts +++ b/src/genezio.ts @@ -86,7 +86,6 @@ try { // make genezio --version program.version(currentGenezioVersion, "-v, --version", "Print the installed genezio version."); program.helpOption("-h, --help", "Print this help message."); -program.addHelpCommand("help", "Print this help message."); program.configureHelp({ subcommandTerm: (cmd) => cmd.name(), }); From 5666306f681520c5d8c2e02ff0e3534af6a89615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 25 Nov 2024 16:07:50 +0200 Subject: [PATCH 50/75] Log the installed CLI version for more debugging context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/genezio.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/genezio.ts b/src/genezio.ts index 0dc88bed1..809063689 100644 --- a/src/genezio.ts +++ b/src/genezio.ts @@ -103,6 +103,11 @@ program .hook("preAction", (thisCommand: Command) => { setDebuggingLoggerLogLevel(thisCommand.opts()["logLevel"]); }); + +program.hook("preAction", async () => { + log.info("Version: " + currentGenezioVersion); +}); + program.hook("postAction", async () => { if (!isCI()) { await logOutdatedVersion().catch((error) => { From 2f602df719f0e153d5f8fc3d5ae8078d723f73e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 18 Nov 2024 13:02:15 +0200 Subject: [PATCH 51/75] Sync cli releases and build machine redeployments and notify the team MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- .github/workflows/ping-build-machine.yaml | 32 +++++++++++++++++++++++ .github/workflows/release.yaml | 24 +++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/.github/workflows/ping-build-machine.yaml b/.github/workflows/ping-build-machine.yaml index e058c1d01..b4c8e0fcd 100644 --- a/.github/workflows/ping-build-machine.yaml +++ b/.github/workflows/ping-build-machine.yaml @@ -4,6 +4,7 @@ on: push: branches: - dev + - main paths-ignore: - "**/*.md" @@ -11,6 +12,7 @@ jobs: ping: runs-on: ubuntu-latest steps: + # Dispatch for 'dev' branch - name: Send Repository Dispatch if: github.ref == 'refs/heads/dev' uses: peter-evans/repository-dispatch@v3 @@ -25,3 +27,33 @@ jobs: token: ${{ secrets.ORG_ACCESS_TOKEN }} repository: genez-io/genezio-build-machine event-type: redeploy-build-machine-workflows-runtime-dev + + # Dispatch for 'main' branch + - name: Send Repository Dispatch - Prod Docker Build + if: github.ref == 'refs/heads/main' + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.ORG_ACCESS_TOKEN }} + repository: genez-io/genezio-build-machine + event-type: redeploy-build-machine-docker-images-prod + + - name: Send Repository Dispatch - Prod Runtime Workflows + if: github.ref == 'refs/heads/main' + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.ORG_ACCESS_TOKEN }} + repository: genez-io/genezio-build-machine + event-type: redeploy-build-machine-workflows-runtime-prod + notify: + if: always() + runs-on: ubuntu-latest + needs: ping + steps: + - name: Notify slack + uses: slackapi/slack-github-action@v2.0.0 + with: + method: chat.postMessage + token: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }} + payload: | + channel: ${{ secrets.SLACK_CHANNEL_ID }} + text: "A redeployment for the build machine has been triggered from the ${{github.ref}} branch." diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 54ce22145..4b85852d7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -39,3 +39,27 @@ jobs: name: Release ${{ github.ref_name }} tag_name: ${{ github.ref_name }} generate_release_notes: true + + notify: + if: always() + runs-on: ubuntu-latest + needs: publish-cli + steps: + - name: Notify slack + uses: slackapi/slack-github-action@v2.0.0 + with: + method: chat.postMessage + token: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }} + payload: | + channel: ${{ secrets.SLACK_CHANNEL_ID }} + text: "GitHub Action build result: ${{ needs.publish-cli.result }}\n + blocks: + - type: "section" + text: + type: "mrkdwn" + text: | + *Github Action Build Result:* ${{ needs.publish-cli.result }}\n + *Repository:* ${{ github.repository }}\n + *Branch:* ${{ github.ref }}\n + *Workflow:* ${{ github.workflow }}\n + *Note: * This will trigger a new build on the build machine From fee016b12f2e0ec84db32cde791c1ee63fb02d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 25 Nov 2024 17:30:37 +0200 Subject: [PATCH 52/75] Ignore dependabot for build machine rebuilds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- .github/workflows/ping-build-machine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ping-build-machine.yaml b/.github/workflows/ping-build-machine.yaml index b4c8e0fcd..97d32f1fa 100644 --- a/.github/workflows/ping-build-machine.yaml +++ b/.github/workflows/ping-build-machine.yaml @@ -10,6 +10,7 @@ on: jobs: ping: + if: github.actor != 'dependabot[bot]' && github.actor != 'github-actions[bot]' runs-on: ubuntu-latest steps: # Dispatch for 'dev' branch From 75e2af26cae2ce4f1da863e216bb5ce26d6d9b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Tue, 26 Nov 2024 15:06:36 +0200 Subject: [PATCH 53/75] Remove version log for analyze because it's breaking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/genezio.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/genezio.ts b/src/genezio.ts index 809063689..eaa24f260 100644 --- a/src/genezio.ts +++ b/src/genezio.ts @@ -104,7 +104,10 @@ program setDebuggingLoggerLogLevel(thisCommand.opts()["logLevel"]); }); -program.hook("preAction", async () => { +program.hook("preAction", async (thisCommand) => { + if (thisCommand.args[0] === "analyze") { + return; + } log.info("Version: " + currentGenezioVersion); }); From b2e55ff7aaf69b0b6aca4107d7e29b90460f5fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Tue, 26 Nov 2024 15:06:48 +0200 Subject: [PATCH 54/75] Update comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/agent.ts | 2 ++ src/commands/analyze/command.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/commands/analyze/agent.ts b/src/commands/analyze/agent.ts index d9df39d24..d4870fa87 100644 --- a/src/commands/analyze/agent.ts +++ b/src/commands/analyze/agent.ts @@ -9,6 +9,8 @@ import { import { debugLogger } from "../../utils/logging.js"; import { YAMLService } from "../../projectConfiguration/yaml/v2.js"; +// Warning: Changing this type will break compatibility across the codebase +// Specifically, it is used in the dashboard to display the detected components export interface ProjectEnvironment { key: string; defaultValue: string; diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index b737ae52f..63c314a85 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -63,6 +63,9 @@ import { analyzeBackendEnvExampleFile, ProjectEnvironment } from "./agent.js"; // ssr: next, nuxt, nitro // containers // services: databases, authentication, crons, cache/redis, queues + +// Warning: Changing this type will break compatibility across the codebase +// Specifically, it is used in the dashboard to display the detected components export type FrameworkReport = { backend?: string[]; backendEnvironment?: ProjectEnvironment[]; @@ -71,6 +74,8 @@ export type FrameworkReport = { services?: FrameworkReportService[]; }; +// Warning: Changing this type will break compatibility across the codebase +// Specifically, it is used in the dashboard to display the detected components export type FrameworkReportService = { databases?: string[]; }; From 3d43652d07714fb18c0692a13e4b4d1c8c32f78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Wed, 27 Nov 2024 16:09:48 +0200 Subject: [PATCH 55/75] Update Readme.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 3cd32efd1..7317ee416 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ For more details on how to use `genezio`, you can check out the official [docume - [Features](#features) - [Getting Started](#getting-started) +- [Installation](#installation) +- [Create a new project](#create-a-new-project) - [Test your project using the Test Interface](#test-your-project-using-the-test-interface) - [Commands Summary](#commands-summary) - [Examples deployed with genezio](#examples-deployed-with-`genezio`) @@ -95,6 +97,24 @@ Check out our [Getting started](https://genezio.com/docs/getting-started) docume For more details about the `genezio` CLI commands, run `genezio help` or `genezio [command] help`. +# Installation + +To install the `genezio` CLI tool, run the following command: + +```bash +npm install -g genezio +``` + +# Create a new project + +Visit the [Genezio template page](https://app.genez.io/new-project) and create a new project. You can choose from a variety of templates or start from scratch. + +If you already have a project you can either [import it from you GitHub repository](https://app.genez.io/import) or deploy it from your local machine using the following command: + +```bash +genezio deploy +``` + # Test your project using the Test Interface You can also test your code locally by running the following command in the `server` directory. From 2f963f6b1dc1499728e49a2a8bcdd7048b094a76 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu <65810476+cristim67@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:17:12 +0200 Subject: [PATCH 56/75] Next http server (#1514) * Add python metadata * remove httpServer handlers * remove httpServer handler * Move nextjs to httpServer type * Move nextjs deploy logic to httpServer * add cache nextjs * add cache handler * Add cache handler * fix * add cacheMaxMemorySize param * fix * move route _next/image to serverOrigin * fix --- src/commands/deploy/nextjs/deploy.ts | 319 ++++++++++++++------------- src/commands/deploy/nextjs/edge.ts | 168 -------------- 2 files changed, 170 insertions(+), 317 deletions(-) delete mode 100644 src/commands/deploy/nextjs/edge.ts diff --git a/src/commands/deploy/nextjs/deploy.ts b/src/commands/deploy/nextjs/deploy.ts index adf46971b..9fabc7f4e 100644 --- a/src/commands/deploy/nextjs/deploy.ts +++ b/src/commands/deploy/nextjs/deploy.ts @@ -16,11 +16,7 @@ import { getFrontendPresignedURL, } from "../../../requests/getFrontendPresignedURL.js"; import { uploadContentToS3 } from "../../../requests/uploadContentToS3.js"; -import { - createTemporaryFolder, - getAllFilesFromPath, - zipDirectoryToDestinationPath, -} from "../../../utils/file.js"; +import { createTemporaryFolder, zipDirectoryToDestinationPath } from "../../../utils/file.js"; import { DeployCodeFunctionResponse } from "../../../models/deployCodeResponse.js"; import { createFrontendProjectV2, @@ -29,7 +25,6 @@ import { import { setEnvironmentVariables } from "../../../requests/setEnvironmentVariables.js"; import { GenezioCloudOutput } from "../../../cloudAdapter/cloudAdapter.js"; import { - ENVIRONMENT, GENEZIO_FRONTEND_DEPLOYMENT_BUCKET, NEXT_JS_GET_ACCESS_KEY, NEXT_JS_GET_SECRET_ACCESS_KEY, @@ -38,7 +33,6 @@ import colors from "colors"; import { computeAssetsPaths } from "./assets.js"; import * as Sentry from "@sentry/node"; import { randomUUID } from "crypto"; -import { EdgeFunction, getEdgeFunctions } from "./edge.js"; import { attemptToInstallDependencies, uploadEnvVarsFromFile, uploadUserCode } from "../utils.js"; import { readOrAskConfig } from "../utils.js"; import { SSRFrameworkComponentType } from "../../../models/projectOptions.js"; @@ -55,6 +49,12 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { // Install dependencies const installDependenciesCommand = await attemptToInstallDependencies([], componentPath); + // Install dependencies including the ISR package + await attemptToInstallDependencies( + [`@genezio/nextjs-isr-${genezioConfig.region}`], + componentPath, + ); + // Add nextjs component await addSSRComponentToConfig( options.config, @@ -68,19 +68,15 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { SSRFrameworkComponentType.next, ); - const edgeFunctions = await getEdgeFunctions(componentPath); - writeNextConfig(componentPath); - await writeOpenNextConfig( - genezioConfig.region, - edgeFunctions, - installDependenciesCommand.args, - componentPath, - ); - // Build the Next.js project + writeNextConfig(componentPath, genezioConfig.region); await $({ stdio: "inherit", cwd: componentPath, - })`npx --yes @genezio/open-next@latest build`.catch(() => { + env: { + ...process.env, + NEXT_PRIVATE_STANDALONE: "true", + }, + })`npx next build --no-lint`.catch(() => { throw new UserError("Failed to build the Next.js project. Check the logs above."); }); @@ -90,7 +86,7 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { const [deploymentResult, domainName] = await Promise.all([ // Deploy NextJs serverless functions - deployFunctions(genezioConfig, componentPath, options.stage), + deployFunction(genezioConfig, componentPath, options.stage), // Deploy NextJs static assets to S3 deployStaticAssets(genezioConfig, options.stage, cacheToken, componentPath), ]); @@ -102,11 +98,10 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { setupEnvironmentVariables(deploymentResult, domainName, genezioConfig.region, cacheToken), // Deploy CDN that serves the Next.js app deployCDN( - deploymentResult.functions, + deploymentResult.functions[0], domainName, genezioConfig, options.stage, - edgeFunctions, componentPath, ), uploadEnvVarsFromFile( @@ -126,7 +121,7 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { } async function checkProjectLimitations(cwd: string) { - const assetsPath = path.join(cwd, ".open-next", "assets"); + const assetsPath = path.join(cwd, ".next", "static"); const paths = await computeAssetsPaths(assetsPath, {} as CreateFrontendV2Origin); if (paths.length > 195) { @@ -146,7 +141,7 @@ async function setupEnvironmentVariables( await setEnvironmentVariables(deploymentResult.projectId, deploymentResult.projectEnvId, [ { name: "BUCKET_KEY_PREFIX", - value: `${domainName}/_assets`, + value: `${domainName}/_assets/`, }, { name: "BUCKET_NAME", @@ -176,48 +171,17 @@ async function setupEnvironmentVariables( } async function deployCDN( - deployedFunctions: DeployCodeFunctionResponse[], + deployedFunction: DeployCodeFunctionResponse, domainName: string, config: YamlProjectConfiguration, stage: string, - edgeFunctions: EdgeFunction[] = [], cwd: string, ) { const PATH_NUMBER_LIMIT = 200; - const externalPaths: { - origin: CreateFrontendV2Origin; - pattern: string; - }[] = deployedFunctions - .filter((f) => f.name !== "function-image-optimization" && f.name !== "function-default") - .map((f) => { - return { - origin: { - domain: { - id: f.id, - type: "function", - }, - path: undefined, - methods: ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], - cachePolicy: "custom-function-cache", - }, - pattern: edgeFunctions.find((ef) => ef.name === f.name)!.pattern, - }; - }); - const serverOrigin: CreateFrontendV2Origin = { domain: { - id: deployedFunctions.find((f) => f.name === "function-default")?.id ?? "", - type: "function", - }, - path: undefined, - methods: ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], - cachePolicy: "custom-function-cache", - }; - - const imageOptimizationOrigin: CreateFrontendV2Origin = { - domain: { - id: deployedFunctions.find((f) => f.name === "function-image-optimization")?.id ?? "", + id: deployedFunction.id, type: "function", }, path: undefined, @@ -236,13 +200,14 @@ async function deployCDN( }; const paths = [ - ...externalPaths, { origin: serverOrigin, pattern: "api/*" }, { origin: serverOrigin, pattern: "_next/data/*" }, - { origin: imageOptimizationOrigin, pattern: "_next/image*" }, + { origin: serverOrigin, pattern: "_next/image*" }, + { origin: s3Origin, pattern: "_next/static*" }, + { origin: s3Origin, pattern: "*.*" }, ]; - const assetsFolder = path.join(cwd, ".open-next", "assets"); + const assetsFolder = path.join(cwd, ".next", "static"); paths.push(...(await computeAssetsPaths(assetsFolder, s3Origin))); if (paths.length >= PATH_NUMBER_LIMIT) { @@ -283,19 +248,24 @@ async function deployStaticAssets( const temporaryFolder = await createTemporaryFolder(); const archivePath = path.join(temporaryFolder, "next-static.zip"); + const staticAssetsPath = path.join(temporaryFolder, "next-static", "_assets"); - await fs.promises.mkdir(path.join(temporaryFolder, "next-static")); + // Create base directory structure first + await fs.promises.mkdir(staticAssetsPath, { recursive: true }); + await fs.promises.mkdir(path.join(staticAssetsPath, "_next"), { recursive: true }); + + // Copy files after directories are created await Promise.all([ fs.promises.cp( - path.join(cwd, ".open-next", "assets"), - path.join(temporaryFolder, "next-static", "_assets"), + path.join(cwd, ".next", "static"), + path.join(staticAssetsPath, "_next", "static"), { recursive: true }, ), fs.promises.cp( - path.join(cwd, ".open-next", "cache"), - path.join(temporaryFolder, "next-static", cacheToken, "_cache"), - { recursive: true }, + path.join(cwd, ".next", "BUILD_ID"), + path.join(staticAssetsPath, "BUILD_ID"), ), + fs.promises.cp(path.join(cwd, "public"), staticAssetsPath, { recursive: true }), ]); const { presignedURL, userId, domain } = await getFrontendPresignedURLPromise; @@ -313,31 +283,20 @@ async function deployStaticAssets( return domain; } -async function deployFunctions(config: YamlProjectConfiguration, cwd: string, stage?: string) { +async function deployFunction(config: YamlProjectConfiguration, cwd: string, stage?: string) { const cloudProvider = await getCloudProvider(config.name); const cloudAdapter = getCloudAdapter(cloudProvider); const cwdRelative = path.relative(process.cwd(), cwd) || "."; - const basePath = path.join(cwdRelative, ".open-next", "server-functions"); - const serverSubfolders = await getAllFilesFromPath(basePath, false); - - const functions = serverSubfolders.map((folder) => { - return { - path: path.join(cwdRelative, ".open-next", "server-functions", folder.name), - name: folder.name, - entry: "index.mjs", - handler: "handler", - type: FunctionType.aws, - }; - }); - functions.push({ - path: path.join(cwdRelative, ".open-next", "image-optimization-function"), - name: "image-optimization", - entry: "index.mjs", + const serverFunction = { + path: path.join(cwdRelative, ".next", "standalone"), + name: "nextjs", + entry: "server.js", handler: "handler", - type: FunctionType.aws, - }); + type: FunctionType.httpServer, + port: 3000, + }; const deployConfig: YamlProjectConfiguration = { ...config, @@ -349,7 +308,7 @@ async function deployFunctions(config: YamlProjectConfiguration, cwd: string, st architecture: "x86_64", packageManager: PackageManagerType.npm, }, - functions, + functions: [serverFunction], }, }; @@ -381,83 +340,145 @@ async function deployFunctions(config: YamlProjectConfiguration, cwd: string, st return result; } -function writeNextConfig(cwd: string) { - const configExists = ["js", "cjs", "mjs", "ts"].find((ext) => +function writeNextConfig(cwd: string, region: string) { + const configExtensions = ["js", "cjs", "mjs", "ts"]; + const existingConfig = configExtensions.find((ext) => fs.existsSync(path.join(cwd, `next.config.${ext}`)), ); - if (!configExists) { - fs.writeFileSync("next.config.js", ``); - } -} -async function writeOpenNextConfig( - region: string, - edgeFunctionPaths: EdgeFunction[], - installArgs: string[] = [], - cwd: string, -) { - let functions = ""; - - if (edgeFunctionPaths.length > 0) { - functions += "functions: {\n"; - for (const index in edgeFunctionPaths) { - const f = edgeFunctionPaths[index]; - functions += ` edge${index}: { - runtime: 'edge', - routes: ['${f.path}'], - patterns: ['${f.pattern}'], - }, -`; - } - functions += "},"; + if (!existingConfig) { + const extension = determineFileExtension(cwd); + writeConfigFiles(cwd, extension, region); + return; } - const OPEN_NEXT_CONFIG = ` - import { IncrementalCache, Queue, TagCache } from "@genezio/nextjs-isr-${region}"; - const deployment = process.env["GENEZIO_DOMAIN_NAME"] || ""; - const token = (process.env["GENEZIO_CACHE_TOKEN"] || "") + "/_cache/" + (process.env["NEXT_BUILD_ID"] || ""); + const configPath = path.join(cwd, `next.config.${existingConfig}`); + const handlerPath = `./cache-handler.${existingConfig}`; - const queue = () => ({ - name: "genezio-queue", - send: Queue.send.bind(null, deployment, token), - }); + fs.writeFileSync( + path.join(cwd, `cache-handler.${existingConfig}`), + getCacheHandlerContent(existingConfig as "js" | "ts" | "mjs", region), + ); - const incrementalCache = () => ({ - name: "genezio-incremental-cache", - get: IncrementalCache.get.bind(null, deployment, token), - set: IncrementalCache.set.bind(null, deployment, token), - delete: IncrementalCache.delete.bind(null, deployment, token), - }); + const content = fs.readFileSync(configPath, "utf8"); - const tagCache = () => ({ - name: "genzio-tag-cache", - getByTag: TagCache.getByTag.bind(null, deployment, token), - getByPath: TagCache.getByPath.bind(null, deployment, token), - getLastModified: TagCache.getLastModified.bind(null, deployment, token), - writeTags: TagCache.writeTags.bind(null, deployment, token), - }); + const updatedContent = content.replace( + /const\s+nextConfig\s*=\s*(\{[^]*?\n\})/m, + (match, configObject) => { + const hasCache = configObject.includes("cacheHandler"); + const hasMemSize = configObject.includes("cacheMaxMemorySize"); - const config = { - default: { - override: { - queue, - incrementalCache, - tagCache, - }, - }, - ${functions} - imageOptimization: { - arch: "x64", + const newConfig = configObject.trim(); + const insertPoint = newConfig.lastIndexOf("}"); + + const cacheConfig = `${!hasCache ? `cacheHandler: process.env.NODE_ENV === "production" ? "${handlerPath}" : undefined,` : ""} + ${!hasMemSize ? "cacheMaxMemorySize: 0," : ""}`; + + return `const nextConfig = ${ + newConfig.slice(0, insertPoint) + + (insertPoint > 0 ? cacheConfig : "") + + newConfig.slice(insertPoint) + }`; }, + ); + + fs.writeFileSync(configPath, updatedContent); +} + +function determineFileExtension(cwd: string): "js" | "mjs" | "ts" { + try { + // Always prefer .mjs for Next.js config files + const packageJson = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8")); + return packageJson.type === "module" ? "mjs" : "js"; + } catch { + return "js"; // Fallback to CommonJS + } +} + +function getConfigContent(extension: string): string { + const isESM = extension === "mjs"; + const handlerPath = `./cache-handler.${extension}`; + + return `/** @type {import('next').NextConfig} */ +const nextConfig = { + cacheHandler: process.env.NODE_ENV === "production" + ? ${isESM ? handlerPath : `require.resolve("${handlerPath}")`} + : undefined, + output: 'standalone', + cacheMaxMemorySize: 0 +} + +${isESM ? "export default nextConfig;" : "module.exports = nextConfig;"}`; +} + +function getCacheHandlerContent(extension: "ts" | "mjs" | "js", region: string): string { + const imports = { + ts: `import { IncrementalCache, Queue, TagCache } from "@genezio/nextjs-isr-${region}"; + +interface CacheOptions { + tags?: string[]; + revalidate?: number; +}`, + mjs: `import { IncrementalCache, Queue, TagCache } from "@genezio/nextjs-isr-${region}"`, + js: `const { IncrementalCache, Queue, TagCache } = require("@genezio/nextjs-isr-${region}");`, }; - export default config;`; + const exportStatement = extension === "js" ? "module.exports = " : "export default "; + + return `${imports[extension]} + +const deployment = process.env["GENEZIO_DOMAIN_NAME"] || ""; +const token = (process.env["GENEZIO_CACHE_TOKEN"] || "") + "/_cache/" + (process.env["NEXT_BUILD_ID"] || ""); + +${exportStatement}class CacheHandler { + constructor(options) { + this.queue = Queue; + this.incrementalCache = IncrementalCache; + this.tagCache = TagCache; + } - // Write the open-next configuration - // TODO: Check if the file already exists and merge the configurations, instead of overwriting it. - const openNextConfigPath = path.join(cwd, "open-next.config.ts"); - await fs.promises.writeFile(openNextConfigPath, OPEN_NEXT_CONFIG); + async get(key) { + try { + return await this.incrementalCache.get(deployment, token, key); + } catch (error) { + return null; + } + } - const tag = ENVIRONMENT === "prod" ? "latest" : "dev"; - await getPackageManager().install([`@genezio/nextjs-isr-${region}@${tag}`], cwd, installArgs); + async set(key, data, options) { + try { + await this.incrementalCache.set(deployment, token, key, data, options); + + if (options?.tags?.length) { + await this.tagCache.writeTags(deployment, token, key, options.tags); + } + } catch (error) { + console.error('Cache set error:', error); + } + } + + async revalidateTag(tag) { + try { + const paths = await this.tagCache.getByTag(deployment, token, tag); + + if (paths?.length) { + await this.queue.send(deployment, token, { + type: 'revalidate', + paths + }); + } + } catch (error) { + console.error('Tag revalidation error:', error); + } + } +}`; +} + +function writeConfigFiles(cwd: string, extension: "js" | "mjs" | "ts", region: string): void { + fs.writeFileSync(path.join(cwd, `next.config.${extension}`), getConfigContent(extension)); + + fs.writeFileSync( + path.join(cwd, `cache-handler.${extension}`), + getCacheHandlerContent(extension as "js" | "ts" | "mjs", region), + ); } diff --git a/src/commands/deploy/nextjs/edge.ts b/src/commands/deploy/nextjs/edge.ts deleted file mode 100644 index 4daff8de3..000000000 --- a/src/commands/deploy/nextjs/edge.ts +++ /dev/null @@ -1,168 +0,0 @@ -import ts from "typescript"; -import fs from "fs"; -import path from "path"; - -interface ExportedVariable { - name: string; - value: string; -} - -export interface EdgeFunction { - name: string; - path: string; - pattern: string; -} - -function extractExportedVariables(filePath: string): ExportedVariable[] { - const exportedVariables: ExportedVariable[] = []; - - // Read the file (either JS or TS) - const sourceCode = fs.readFileSync(filePath, "utf8"); - - // Infer the script kind based on the file extension (.ts or .js) - const scriptKind = filePath.endsWith(".ts") ? ts.ScriptKind.TS : ts.ScriptKind.JS; - - // Create a SourceFile with the appropriate script kind - const sourceFile = ts.createSourceFile( - filePath, - sourceCode, - ts.ScriptTarget.ES2015, - true, - scriptKind, - ); - - // Function to extract exported variables - function extractExports(node: ts.Node) { - // Check if the node is a variable statement with an 'export' modifier - if ( - ts.isVariableStatement(node) && - node.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword) - ) { - node.declarationList.declarations.forEach((declaration) => { - if (ts.isIdentifier(declaration.name)) { - const variableName = declaration.name.text; - - if (declaration.initializer) { - // Case 1: If the initializer is an object literal (e.g., `export const config = { runtime: 'edge', preferredRegion: 'lhr1' };`) - if (ts.isObjectLiteralExpression(declaration.initializer)) { - declaration.initializer.properties.forEach((prop) => { - if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { - const propName = prop.name.text; - if (ts.isStringLiteral(prop.initializer)) { - const propValue = prop.initializer.getText(); // Get the text with quotes - exportedVariables.push({ - name: propName, - value: propValue, - }); - } - } - }); - } - // Case 2: If it's a direct variable assignment (e.g., `export const runtime = "edge";`) - else if (ts.isStringLiteral(declaration.initializer)) { - const initializerValue = declaration.initializer.getText(); // Get the text with quotes - exportedVariables.push({ name: variableName, value: initializerValue }); - } - } - } - }); - } - - // Continue traversing the children nodes - ts.forEachChild(node, extractExports); - } - - // Traverse the SourceFile and extract exported variables - extractExports(sourceFile); - - return exportedVariables; -} - -function walkDirectory(dir: string, callback: (filePath: string) => void) { - // Read the directory entries synchronously - const entries = fs.readdirSync(dir, { withFileTypes: true }); - - entries.forEach((entry) => { - const fullPath = path.join(dir, entry.name); - - if (entry.isDirectory()) { - // Recursively walk through the subdirectory - walkDirectory(fullPath, callback); - } else if (entry.isFile()) { - // Perform the callback operation on the file - callback(fullPath); - } - }); -} - -function removeExtension(filePath: string) { - const dir = path.dirname(filePath); - const fileName = path.basename(filePath, path.extname(filePath)); - return path.join(dir, fileName); -} - -function getPatternFromPath(filePath: string): string { - // Normalize the path for cross-platform compatibility - const normalizedPath = path.posix.normalize(filePath); - - // Remove the prefix 'app' or 'src/app' regardless of whether './' is present - const cleanedPath = normalizedPath.replace(/^(?:\.\/)?(src\/)?app\//, ""); - - // Remove the filename (page.tsx, page.js, route.tsx, route.js, route.ts) - const pattern = cleanedPath.replace(/\/(page|route)\.(tsx|js|ts)$/, ""); - - // Prepend a slash to the resulting path - return `/${pattern}`; -} - -function walkDirectoryForEdgeFunctions(dir: string): Promise { - return new Promise((resolve) => { - const edgeFunctions: EdgeFunction[] = []; - let counter = 0; - - if (!fs.existsSync(dir)) { - resolve(edgeFunctions); - } - - walkDirectory(dir, (filePath) => { - const filename = path.basename(filePath); - if ( - filename === "route.ts" || - filename === "route.js" || - filename === "page.tsx" || - filename === "page.jsx" || - filename === "page.js" - ) { - const exportedVariables = extractExportedVariables(filePath); - const edgeRuntimeExport = exportedVariables.find( - (variable) => variable.name === "runtime" && variable.value === '"edge"', - ); - - if (edgeRuntimeExport) { - edgeFunctions.push({ - name: `function-edge${counter++}`, - path: removeExtension(filePath), - pattern: getPatternFromPath(filePath), - }); - } - } - }); - - resolve(edgeFunctions); - }); -} - -export async function getEdgeFunctions(cwd: string): Promise { - const edgeFunctions: EdgeFunction[] = []; - const pathForAppAbsolute = path.join(cwd, "app"); - const pathForSrcAbsolute = path.join(cwd, "src", "app"); - - const pathForApp = path.relative(cwd, pathForAppAbsolute); - const pathForSrc = path.relative(cwd, pathForSrcAbsolute); - - const appFolderFunctions = await walkDirectoryForEdgeFunctions(pathForApp); - const srcAppFolderFunctions = await walkDirectoryForEdgeFunctions(pathForSrc); - edgeFunctions.push(...appFolderFunctions, ...srcAppFolderFunctions); - - return edgeFunctions; -} From e97ae8d257543dd0f67a501a53f8accdce79f569 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Wed, 27 Nov 2024 17:06:37 +0200 Subject: [PATCH 57/75] fix --- package-lock.json | 1 - src/cloudAdapter/cloudAdapter.ts | 8 +----- src/commands/deploy/genezio.ts | 7 ----- src/commands/deploy/nextjs/deploy.ts | 7 ++--- src/commands/local.ts | 39 +--------------------------- src/models/projectConfiguration.ts | 4 --- src/projectConfiguration/yaml/v2.ts | 1 - 7 files changed, 6 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ca6e4cc0..a61d5528a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-win32-arm64-msvc": "4.27.4", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", diff --git a/src/cloudAdapter/cloudAdapter.ts b/src/cloudAdapter/cloudAdapter.ts index 79c3d6049..6671de463 100644 --- a/src/cloudAdapter/cloudAdapter.ts +++ b/src/cloudAdapter/cloudAdapter.ts @@ -13,11 +13,10 @@ export enum GenezioCloudInputType { FUNCTION = "function", } -export type GenezioFunctionMetadata = ContainerMetadata | PythonMetadata | HttpServerMetadata; +export type GenezioFunctionMetadata = ContainerMetadata | PythonMetadata; export enum GenezioFunctionMetadataType { Container = "container", Python = "python", - HttpServer = "httpServer", } export type ContainerMetadata = { @@ -32,11 +31,6 @@ export type PythonMetadata = { app_name?: string; }; -export type HttpServerMetadata = { - type: GenezioFunctionMetadataType.HttpServer; - http_port?: string; -}; - export type GenezioCloudInput = | { type: GenezioCloudInputType.CLASS; diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index 01ec5904e..eb446a3f6 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -688,13 +688,6 @@ export async function functionToCloudInput( } let metadata: GenezioFunctionMetadata | undefined; - if (functionElement.type === "httpServer") { - debugLogger.debug(`Http server port: ${functionElement.port}`); - metadata = { - type: GenezioFunctionMetadataType.HttpServer, - http_port: functionElement.port?.toString(), - }; - } // Handle Python projects dependencies if (functionElement.language === "python") { diff --git a/src/commands/deploy/nextjs/deploy.ts b/src/commands/deploy/nextjs/deploy.ts index 9fabc7f4e..a480fe787 100644 --- a/src/commands/deploy/nextjs/deploy.ts +++ b/src/commands/deploy/nextjs/deploy.ts @@ -290,12 +290,11 @@ async function deployFunction(config: YamlProjectConfiguration, cwd: string, sta const cwdRelative = path.relative(process.cwd(), cwd) || "."; const serverFunction = { - path: path.join(cwdRelative, ".next", "standalone"), + path: ".", name: "nextjs", entry: "server.js", handler: "handler", type: FunctionType.httpServer, - port: 3000, }; const deployConfig: YamlProjectConfiguration = { @@ -321,7 +320,9 @@ async function deployFunction(config: YamlProjectConfiguration, cwd: string, sta }, ); const cloudInputs = await Promise.all( - projectConfiguration.functions.map((f) => functionToCloudInput(f, ".")), + projectConfiguration.functions.map((f) => + functionToCloudInput(f, path.join(cwdRelative, ".next", "standalone")), + ), ); const projectGitRepositoryUrl = (await git.listRemotes({ fs, dir: process.cwd() })).find( diff --git a/src/commands/local.ts b/src/commands/local.ts index b0e9ab47d..c4f4bd0ee 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -97,7 +97,6 @@ import { enableEmailIntegration, getProjectIntegrations } from "../requests/inte import { expandEnvironmentVariables, findAnEnvFile } from "../utils/environmentVariables.js"; import { getFunctionHandlerProvider } from "../utils/getFunctionHandlerProvider.js"; import { getFunctionEntryFilename } from "../utils/getFunctionEntryFilename.js"; -import { detectPythonCommand } from "../utils/detectPythonCommand.js"; type UnitProcess = { process: ChildProcess; @@ -649,38 +648,6 @@ async function startProcesses( functionInfo.language as Language, ); - // if handlerProvider is Http, run it with node - if ( - functionInfo.type === FunctionType.httpServer && - (functionInfo.language === Language.js || functionInfo.language === Language.ts) - ) { - return { - configuration: functionInfo, - extra: { - type: "function" as const, - startingCommand: "node", - commandParameters: [path.resolve(functionInfo.path, functionInfo.entry)], - handlerType: FunctionType.httpServer, - }, - }; - } - - // if handlerProvider is Http and language is python - if ( - functionInfo.type === FunctionType.httpServer && - functionInfo.language === Language.python - ) { - return { - configuration: functionInfo, - extra: { - type: "function" as const, - startingCommand: (await detectPythonCommand()) || "python", - commandParameters: [path.resolve(functionInfo.path, functionInfo.entry)], - handlerType: FunctionType.httpServer, - }, - }; - } - await writeToFile( path.join(tmpFolder), getFunctionEntryFilename( @@ -1571,9 +1538,5 @@ function formatTimestamp(date: Date) { } export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { - if (functionObj.type === FunctionType.httpServer) { - return `http://localhost:${functionObj.port ?? 8083}`; - } - - return `http://localhost:${functionObj.port ?? 8083}/.functions/${functionObj.name}`; + return `http://localhost:8083/.functions/${functionObj.name}`; } diff --git a/src/models/projectConfiguration.ts b/src/models/projectConfiguration.ts index 53ef10cef..a5ababd7e 100644 --- a/src/models/projectConfiguration.ts +++ b/src/models/projectConfiguration.ts @@ -113,7 +113,6 @@ export class FunctionConfiguration { storageSize?: number; instanceSize?: InstanceSize; maxConcurrentRequestsPerInstance?: number; - port?: number; constructor( name: string, @@ -126,7 +125,6 @@ export class FunctionConfiguration { storageSize?: number, instanceSize?: InstanceSize, maxConcurrentRequestsPerInstance?: number, - port?: number, ) { this.name = name; this.path = path; @@ -138,7 +136,6 @@ export class FunctionConfiguration { this.storageSize = storageSize; this.instanceSize = instanceSize; this.maxConcurrentRequestsPerInstance = maxConcurrentRequestsPerInstance; - this.port = port; } } @@ -304,7 +301,6 @@ export class ProjectConfiguration { storageSize: f.storageSize, instanceSize: f.instanceSize, maxConcurrentRequestsPerInstance: f.maxConcurrentRequestsPerInstance, - port: f.port, }; }) || []; } diff --git a/src/projectConfiguration/yaml/v2.ts b/src/projectConfiguration/yaml/v2.ts index b708caef5..d39291777 100644 --- a/src/projectConfiguration/yaml/v2.ts +++ b/src/projectConfiguration/yaml/v2.ts @@ -126,7 +126,6 @@ function parseGenezioConfig(config: unknown) { storageSize: zod.number().optional(), instanceSize: zod.nativeEnum(InstanceSize).optional(), maxConcurrentRequestsPerInstance: zod.number().optional(), - port: zod.number().optional(), }) .refine( ({ type, handler }) => !(type === FunctionType.aws && !handler), From d2bbb735e65e2eebfd57ed2e92ddb421a26b3c94 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Wed, 27 Nov 2024 17:08:40 +0200 Subject: [PATCH 58/75] Fix path for next server --- src/commands/deploy/nextjs/deploy.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/deploy/nextjs/deploy.ts b/src/commands/deploy/nextjs/deploy.ts index 9fabc7f4e..c8bedf4b8 100644 --- a/src/commands/deploy/nextjs/deploy.ts +++ b/src/commands/deploy/nextjs/deploy.ts @@ -290,7 +290,7 @@ async function deployFunction(config: YamlProjectConfiguration, cwd: string, sta const cwdRelative = path.relative(process.cwd(), cwd) || "."; const serverFunction = { - path: path.join(cwdRelative, ".next", "standalone"), + path: ".", name: "nextjs", entry: "server.js", handler: "handler", @@ -321,7 +321,9 @@ async function deployFunction(config: YamlProjectConfiguration, cwd: string, sta }, ); const cloudInputs = await Promise.all( - projectConfiguration.functions.map((f) => functionToCloudInput(f, ".")), + projectConfiguration.functions.map((f) => + functionToCloudInput(f, path.join(cwdRelative, ".next", "standalone")), + ), ); const projectGitRepositoryUrl = (await git.listRemotes({ fs, dir: process.cwd() })).find( From d0cc2534904f565024eaa3dcaf0ca4274ab094f9 Mon Sep 17 00:00:00 2001 From: Bogdan Vlad Date: Wed, 27 Nov 2024 17:25:09 +0200 Subject: [PATCH 59/75] Ignore typescript checking in cache handler. (#1543) * Ignore typescript checking in cache handler. * Update deploy.ts --- src/commands/deploy/nextjs/deploy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/deploy/nextjs/deploy.ts b/src/commands/deploy/nextjs/deploy.ts index c8bedf4b8..432be8a28 100644 --- a/src/commands/deploy/nextjs/deploy.ts +++ b/src/commands/deploy/nextjs/deploy.ts @@ -415,7 +415,8 @@ ${isESM ? "export default nextConfig;" : "module.exports = nextConfig;"}`; function getCacheHandlerContent(extension: "ts" | "mjs" | "js", region: string): string { const imports = { - ts: `import { IncrementalCache, Queue, TagCache } from "@genezio/nextjs-isr-${region}"; + ts: `// @ts-nocheck +import { IncrementalCache, Queue, TagCache } from "@genezio/nextjs-isr-${region}"; interface CacheOptions { tags?: string[]; From b29d27aca41d30984048dde2a0a91f83f9c71497 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 00:58:07 +0200 Subject: [PATCH 60/75] add node handler --- src/commands/local.ts | 91 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index c4f4bd0ee..fe386bbe0 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -648,17 +648,47 @@ async function startProcesses( functionInfo.language as Language, ); - await writeToFile( - path.join(tmpFolder), - getFunctionEntryFilename( - functionInfo.language as Language, - "local_function_wrapper", - ), - await handlerProvider!.getLocalFunctionWrapperCode( - functionInfo.handler, - functionInfo.entry, - ), - ); + // if handlerProvider is Http, run it with node + if ( + functionInfo.type === FunctionType.httpServer && + (functionInfo.language === Language.js || functionInfo.language === Language.ts) + ) { + await writeToFile( + path.join(tmpFolder), + getFunctionEntryFilename( + functionInfo.language as Language, + "local_function_wrapper", + ), + await getLocalFunctionHttpServerWrapper(functionInfo.entry), + ); + } + + // if handlerProvider is Http and language is python + else if ( + functionInfo.type === FunctionType.httpServer && + functionInfo.language === Language.python + ) { + await writeToFile( + path.join(tmpFolder), + getFunctionEntryFilename( + functionInfo.language as Language, + "local_function_wrapper", + ), + await getLocalFunctionHttpServerPythonWrapper(functionInfo.entry), + ); + } else { + await writeToFile( + path.join(tmpFolder), + getFunctionEntryFilename( + functionInfo.language as Language, + "local_function_wrapper", + ), + await handlerProvider!.getLocalFunctionWrapperCode( + functionInfo.handler, + functionInfo.entry, + ), + ); + } return { configuration: functionInfo, @@ -1540,3 +1570,42 @@ function formatTimestamp(date: Date) { export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { return `http://localhost:8083/.functions/${functionObj.name}`; } + +function getLocalFunctionHttpServerWrapper(entry: string): string { + return ` +import * as domain from "domain"; +import { createRequire } from "module"; +const require = createRequire(import.meta.url); +const http = require('http') + +const originalCreateServer = http.createServer; +let server; + +http.createServer = function(...args) { + server = originalCreateServer(...args); + + // Store the original listen method + const originalListen = server.listen; + + // Override the listen method to only listen once + server.listen = function(...listenArgs) { + const genezioPort = parseInt(process.argv[process.argv.length - 1], 10); + console.log("[HTTP Server Wrapper] Starting server on port:", genezioPort); + // Only call listen once with the Genezio port + return originalListen.apply(server, [genezioPort, ...listenArgs.slice(1)]); + }; + + return server; +}; + +// Import the original app.js +const app = await import("./${entry}"); +`; +} +function getLocalFunctionHttpServerPythonWrapper(entry: string): string { + return ` +import sys +sys.path.append("${entry}") +from app import app +`; +} From 9fd2c5b15b2311fe8841077bb1b1cbfb59d04d5b Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 09:49:30 +0200 Subject: [PATCH 61/75] fix http server nodejs local --- src/commands/local.ts | 49 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index fe386bbe0..e218941ab 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -803,7 +803,13 @@ async function startServerHttp( const astSummary: AstSummary = projectConfiguration.astSummary; const app = express(); const require = createRequire(import.meta.url); - app.use(cors()); + app.use( + cors({ + origin: "*", + methods: "GET, POST, OPTIONS, PUT, PATCH, DELETE", + allowedHeaders: "*", + }), + ); app.use(bodyParser.raw({ type: () => true, limit: "6mb" })); app.use(genezioRequestParser); const packagePath = path.dirname(require.resolve("@genezio/test-interface-component")); @@ -1481,6 +1487,10 @@ async function startLocalUnitProcess( debugLogger.debug(`[START_Unit_PROCESS] Starting ${localUnitName} on port ${availablePort}`); debugLogger.debug(`[START_Unit_PROCESS] Starting command: ${startingCommand}`); debugLogger.debug(`[START_Unit_PROCESS] Parameters: ${parameters}`); + + // Store the port in the environment variables + const modifyLocalUnitName = localUnitName.replace(/-/g, "_").toUpperCase(); + process.env[`GENEZIO_PORT_${modifyLocalUnitName}`] = availablePort.toString(); const processParameters = [...parameters, availablePort.toString()]; const localUnitProcess = spawn(startingCommand, processParameters, { stdio: ["pipe", "pipe", "pipe"], @@ -1568,10 +1578,14 @@ function formatTimestamp(date: Date) { } export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { + const modifyLocalUnitName = functionObj.name.replace(/-/g, "_").toUpperCase(); + if (functionObj.type === FunctionType.httpServer) { + return `http://localhost:${process.env[`GENEZIO_PORT_${modifyLocalUnitName}`]}`; + } return `http://localhost:8083/.functions/${functionObj.name}`; } -function getLocalFunctionHttpServerWrapper(entry: string): string { +async function getLocalFunctionHttpServerWrapper(entry: string): Promise { return ` import * as domain from "domain"; import { createRequire } from "module"; @@ -1582,6 +1596,26 @@ const originalCreateServer = http.createServer; let server; http.createServer = function(...args) { + // If there's a request handler provided, wrap it with CORS headers + if (args[0] && typeof args[0] === 'function') { + const originalHandler = args[0]; + args[0] = function(req, res) { + // Set CORS headers + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); + res.setHeader('Access-Control-Allow-Headers', '*'); + + // Handle OPTIONS requests for CORS preflight + if (req.method === 'OPTIONS') { + res.writeHead(204); + res.end(); + return; + } + + return originalHandler(req, res); + }; + } + server = originalCreateServer(...args); // Store the original listen method @@ -1590,7 +1624,6 @@ http.createServer = function(...args) { // Override the listen method to only listen once server.listen = function(...listenArgs) { const genezioPort = parseInt(process.argv[process.argv.length - 1], 10); - console.log("[HTTP Server Wrapper] Starting server on port:", genezioPort); // Only call listen once with the Genezio port return originalListen.apply(server, [genezioPort, ...listenArgs.slice(1)]); }; @@ -1602,10 +1635,8 @@ http.createServer = function(...args) { const app = await import("./${entry}"); `; } -function getLocalFunctionHttpServerPythonWrapper(entry: string): string { - return ` -import sys -sys.path.append("${entry}") -from app import app -`; + +async function getLocalFunctionHttpServerPythonWrapper(entry: string): Promise { + // TODO: Implement this + return `${entry}`; } From 2d5c2b7e7ccfd79e1d1078b9dc6de5e3b892c265 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 10:28:15 +0200 Subject: [PATCH 62/75] add python httpserver local wrapper --- src/commands/local.ts | 147 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index e218941ab..3e65a0fef 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -674,7 +674,10 @@ async function startProcesses( functionInfo.language as Language, "local_function_wrapper", ), - await getLocalFunctionHttpServerPythonWrapper(functionInfo.entry), + await getLocalFunctionHttpServerPythonWrapper( + functionInfo.entry, + functionInfo.handler, + ), ); } else { await writeToFile( @@ -1636,7 +1639,143 @@ const app = await import("./${entry}"); `; } -async function getLocalFunctionHttpServerPythonWrapper(entry: string): Promise { - // TODO: Implement this - return `${entry}`; +async function getLocalFunctionHttpServerPythonWrapper( + entry: string, + handler: string, +): Promise { + return ` +from ${entry.split(".")[0]} import ${handler} as application +import asyncio +import sys +import platform +from wsgiref.simple_server import make_server +import logging +import inspect +import importlib.util +import subprocess + +genezio_port = int(sys.argv[len(sys.argv) - 1]) + +is_asgi = callable(application) and asyncio.iscoroutinefunction(application.__call__) + +# WSGI CORS Middleware +class WSGICORSMiddleware: + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + def cors_start_response(status, headers, exc_info=None): + headers.extend([ + ("Access-Control-Allow-Origin", "*"), + ("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE"), + ("Access-Control-Allow-Headers", "*"), + ]) + return start_response(status, headers, exc_info) + + if environ["REQUEST_METHOD"] == "OPTIONS": + headers = [ + ("Access-Control-Allow-Origin", "*"), + ("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE"), + ("Access-Control-Allow-Headers", "*"), + ] + start_response("204 No Content", headers) + return [b""] + + return self.app(environ, cors_start_response) + +# ASGI CORS Middleware +class ASGICORSMiddleware: + def __init__(self, app): + self.app = app + + async def __call__(self, scope, receive, send): + if scope["type"] != "http": + return await self.app(scope, receive, send) + + if scope["method"] == "OPTIONS": + headers = [ + (b"access-control-allow-origin", b"*"), + (b"access-control-allow-methods", b"GET, POST, OPTIONS, PUT, PATCH, DELETE"), + (b"access-control-allow-headers", b"*"), + ] + await send({ + "type": "http.response.start", + "status": 204, + "headers": headers + }) + await send({ + "type": "http.response.body", + "body": b"" + }) + return + + async def wrapped_send(message): + if message["type"] == "http.response.start": + headers = message.get("headers", []) + headers.extend([ + (b"access-control-allow-origin", b"*"), + (b"access-control-allow-methods", b"GET, POST, OPTIONS, PUT, PATCH, DELETE"), + (b"access-control-allow-headers", b"*"), + ]) + message["headers"] = headers + await send(message) + + await self.app(scope, receive, wrapped_send) + +def install_uvicorn(): + system = platform.system().lower() + pip_commands = [] + + if system == "darwin": # MacOS + pip_commands = ["pip3", "pip"] + else: # Windows, Linux and others + pip_commands = ["pip", "pip3"] + + for pip_cmd in pip_commands: + try: + subprocess.check_call([pip_cmd, "install", "uvicorn"], + stderr=subprocess.DEVNULL, + stdout=subprocess.DEVNULL) + print(f"Successfully installed uvicorn using {pip_cmd}!") + return True + except (subprocess.CalledProcessError, FileNotFoundError): + continue + + print("Failed to install uvicorn automatically. Please install it manually using:") + print(" pip install uvicorn") + print(" -- or --") + print(" pip3 install uvicorn") + return False + +if is_asgi: + uvicorn_spec = importlib.util.find_spec("uvicorn") + if uvicorn_spec is None: + print("ASGI application detected but uvicorn is not installed. Installing uvicorn...") + if not install_uvicorn(): + sys.exit(1) + importlib.invalidate_caches() + uvicorn_spec = importlib.util.find_spec("uvicorn") + if uvicorn_spec is None: + print("Failed to import uvicorn after installation. Please try installing it manually.") + sys.exit(1) + + import uvicorn + + if __name__ == "__main__": + # Wrap the ASGI application with CORS middleware + application = ASGICORSMiddleware(application) + uvicorn.run( + application, + host="127.0.0.1", + port=genezio_port, + reload=False + ) +else: + # Wrap the WSGI application with CORS middleware + application = WSGICORSMiddleware(application) + + with make_server("127.0.0.1", genezio_port, application) as httpd: + print(f"Serving WSGI application on port {genezio_port}...") + httpd.serve_forever() +`; } From 909216c4953054dcd701f3fb2239209d2f0e53b6 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 10:29:50 +0200 Subject: [PATCH 63/75] add port-map for httpServer --- src/commands/local.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 3e65a0fef..848d2edf7 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -121,6 +121,12 @@ type LocalProcessSpawnOutput = { sdk: SdkHandlerResponse; }; +type PortMapping = { + [key: string]: number; +}; + +let httpServerPortMapping: PortMapping = {}; + export async function prepareLocalBackendEnvironment( yamlProjectConfiguration: YamlProjectConfiguration, options: GenezioLocalOptions, @@ -1474,6 +1480,11 @@ async function clearAllResources( processForUnits.forEach((unitProcess) => { unitProcess.process.kill(); }); + + // Only clear port mappings if we're doing a full restart + if (process.env["GENEZIO_FULL_RESTART"] === "true") { + clearPortMappings(); + } } async function startLocalUnitProcess( @@ -1486,7 +1497,18 @@ async function startLocalUnitProcess( cwd?: string, configurationEnvVars?: { [key: string]: string | undefined }, ) { - const availablePort = await findAvailablePort(); + // Check if this is an HTTP server and already has an assigned port + let availablePort: number; + if (type === "function" && httpServerPortMapping[localUnitName]) { + availablePort = httpServerPortMapping[localUnitName]; + } else { + availablePort = await findAvailablePort(); + // Store the port mapping for HTTP servers + if (type === "function") { + httpServerPortMapping[localUnitName] = availablePort; + } + } + debugLogger.debug(`[START_Unit_PROCESS] Starting ${localUnitName} on port ${availablePort}`); debugLogger.debug(`[START_Unit_PROCESS] Starting command: ${startingCommand}`); debugLogger.debug(`[START_Unit_PROCESS] Parameters: ${parameters}`); @@ -1779,3 +1801,7 @@ else: httpd.serve_forever() `; } + +function clearPortMappings() { + httpServerPortMapping = {}; +} From fbc89e2ab54713a783df7ba7dc86a1a219fe2a77 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 19:14:52 +0200 Subject: [PATCH 64/75] fix-django --- src/commands/local.ts | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index 848d2edf7..b64d9432e 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -125,7 +125,7 @@ type PortMapping = { [key: string]: number; }; -let httpServerPortMapping: PortMapping = {}; +const httpServerPortMapping: PortMapping = {}; export async function prepareLocalBackendEnvironment( yamlProjectConfiguration: YamlProjectConfiguration, @@ -647,7 +647,11 @@ async function startProcesses( // delete all content in the tmp folder await fsExtra.emptyDir(tmpFolder); - await fsExtra.copy(path.join(backend.path, functionInfo.path), tmpFolder); + if (functionInfo.language === Language.python) { + await fsExtra.copy(backend.path, tmpFolder); + } else { + await fsExtra.copy(path.join(backend.path, functionInfo.path), tmpFolder); + } const handlerProvider = getFunctionHandlerProvider( functionInfo.type, @@ -681,6 +685,7 @@ async function startProcesses( "local_function_wrapper", ), await getLocalFunctionHttpServerPythonWrapper( + functionInfo.path, functionInfo.entry, functionInfo.handler, ), @@ -1480,11 +1485,6 @@ async function clearAllResources( processForUnits.forEach((unitProcess) => { unitProcess.process.kill(); }); - - // Only clear port mappings if we're doing a full restart - if (process.env["GENEZIO_FULL_RESTART"] === "true") { - clearPortMappings(); - } } async function startLocalUnitProcess( @@ -1662,19 +1662,37 @@ const app = await import("./${entry}"); } async function getLocalFunctionHttpServerPythonWrapper( + pathString: string, entry: string, handler: string, ): Promise { + const nameModule = path + .join(pathString, entry) + .replace(/\\/g, ".") // Convert backslashes to dots (Windows) + .replace(/\//g, ".") // Convert slashes to dots (Unix) + .replace(/^\.+/, "") // Remove leading dots + .replace(/\.+/g, ".") // Remove duplicate dots + .replace(/\.py$/, ""); // Remove extension + return ` -from ${entry.split(".")[0]} import ${handler} as application import asyncio import sys import platform from wsgiref.simple_server import make_server -import logging -import inspect import importlib.util import subprocess +import os +from ${nameModule} import ${handler} as application + +# Try to configure Django's ALLOWED_HOSTS before importing the application +try: + import django + from django.conf import settings + if not settings.configured: + settings.configure() + settings.ALLOWED_HOSTS.extend(['localhost', '127.0.0.1']) +except (ImportError, AttributeError): + pass # Not a Django application genezio_port = int(sys.argv[len(sys.argv) - 1]) @@ -1746,13 +1764,8 @@ class ASGICORSMiddleware: def install_uvicorn(): system = platform.system().lower() - pip_commands = [] + pip_commands = ["pip3", "pip"] if system == "darwin" else ["pip", "pip3"] - if system == "darwin": # MacOS - pip_commands = ["pip3", "pip"] - else: # Windows, Linux and others - pip_commands = ["pip", "pip3"] - for pip_cmd in pip_commands: try: subprocess.check_call([pip_cmd, "install", "uvicorn"], @@ -1784,7 +1797,6 @@ if is_asgi: import uvicorn if __name__ == "__main__": - # Wrap the ASGI application with CORS middleware application = ASGICORSMiddleware(application) uvicorn.run( application, @@ -1793,15 +1805,9 @@ if is_asgi: reload=False ) else: - # Wrap the WSGI application with CORS middleware application = WSGICORSMiddleware(application) - with make_server("127.0.0.1", genezio_port, application) as httpd: print(f"Serving WSGI application on port {genezio_port}...") httpd.serve_forever() `; } - -function clearPortMappings() { - httpServerPortMapping = {}; -} From 3358ce9e8755927e97a4ba295d8a2fa9b6f5580c Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Thu, 28 Nov 2024 19:50:45 +0200 Subject: [PATCH 65/75] fix iac function url --- src/commands/local.ts | 16 ++++++++++++---- src/utils/scripts.ts | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/commands/local.ts b/src/commands/local.ts index b64d9432e..029497542 100644 --- a/src/commands/local.ts +++ b/src/commands/local.ts @@ -1602,12 +1602,20 @@ function formatTimestamp(date: Date) { return formattedDate; } -export function retrieveLocalFunctionUrl(functionObj: FunctionConfiguration): string { - const modifyLocalUnitName = functionObj.name.replace(/-/g, "_").toUpperCase(); +export function retrieveLocalFunctionUrl( + functionObj: FunctionConfiguration, + isIac: boolean = false, +): string { + const BASE_PORT = 8083; + const functionName = isIac ? `function-${functionObj.name}` : functionObj.name; + const normalizedName = functionName.replace(/-/g, "_").toUpperCase(); + if (functionObj.type === FunctionType.httpServer) { - return `http://localhost:${process.env[`GENEZIO_PORT_${modifyLocalUnitName}`]}`; + const port = process.env[`GENEZIO_PORT_${normalizedName}`]; + return `http://localhost:${port}`; } - return `http://localhost:8083/.functions/${functionObj.name}`; + + return `http://localhost:${BASE_PORT}/.functions/${functionName}`; } async function getLocalFunctionHttpServerWrapper(entry: string): Promise { diff --git a/src/utils/scripts.ts b/src/utils/scripts.ts index 8500559d7..6ffeeab92 100644 --- a/src/utils/scripts.ts +++ b/src/utils/scripts.ts @@ -142,7 +142,7 @@ export async function resolveConfigurationVariable( // Retrieve custom output fields for a function object such as `url` if (field === "url") { if (options?.isLocal) { - return retrieveLocalFunctionUrl(functionObj); + return retrieveLocalFunctionUrl(functionObj, true); } const response = await getProjectInfoByName(configuration.name).catch((error) => { From 90e783a71bdcc362c27475c7478faa38756b90cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:48:08 +0000 Subject: [PATCH 66/75] Bump @sentry/profiling-node from 7.118.0 to 7.120.0 Bumps [@sentry/profiling-node](https://github.com/getsentry/sentry-javascript) from 7.118.0 to 7.120.0. - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.120.0/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.118.0...7.120.0) --- updated-dependencies: - dependency-name: "@sentry/profiling-node" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 ++++-- package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a61d5528a..302d6d6d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", "@sentry/node": "^7.119.1", - "@sentry/profiling-node": "~7.118.0", + "@sentry/profiling-node": "~7.120.0", "@types/adm-zip": "^0.5.6", "@webcontainer/env": "^1.1.1", "adm-zip": "^0.5.16", @@ -4449,7 +4449,9 @@ } }, "node_modules/@sentry/profiling-node": { - "version": "7.118.0", + "version": "7.120.0", + "resolved": "https://registry.npmjs.org/@sentry/profiling-node/-/profiling-node-7.120.0.tgz", + "integrity": "sha512-p75cD74SgxPw6vlDs7GpMNaiNUYVUuODuwje0m3789AKJ0jSWbZVSr7PnejI5ILHomQ1XBFPoGufhOTpdVnEPA==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 641127db4..4ecaeb5b5 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", "@sentry/node": "^7.119.1", - "@sentry/profiling-node": "~7.118.0", + "@sentry/profiling-node": "~7.120.0", "@types/adm-zip": "^0.5.6", "@webcontainer/env": "^1.1.1", "adm-zip": "^0.5.16", From e1e6604e3e081822d72d4c0f90225d8f1c38a6c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:48:20 +0000 Subject: [PATCH 67/75] Bump @babel/preset-env from 7.24.7 to 7.26.0 Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.24.7 to 7.26.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.0/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 924 ++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 444 insertions(+), 482 deletions(-) diff --git a/package-lock.json b/package-lock.json index a61d5528a..6ddd93c35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@babel/core": "^7.26.0", "@babel/parser": "^7.26.2", "@babel/plugin-proposal-decorators": "^7.25.9", - "@babel/preset-env": "^7.24.4", + "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.24.6", "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", @@ -1603,11 +1603,13 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1663,11 +1665,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -1698,37 +1702,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", @@ -1789,12 +1762,14 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1820,11 +1795,13 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1842,16 +1819,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", @@ -1877,13 +1844,14 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1916,11 +1884,28 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1930,10 +1915,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1943,12 +1930,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1958,11 +1947,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1997,39 +1988,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-decorators": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", @@ -2044,31 +2002,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2078,10 +2018,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2090,26 +2032,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.24.7", "license": "MIT", @@ -2123,92 +2045,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.24.7", "license": "MIT", @@ -2237,10 +2073,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2250,13 +2088,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2266,12 +2105,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2281,10 +2122,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2294,10 +2137,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2307,11 +2152,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2321,12 +2168,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2336,16 +2184,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -2356,11 +2204,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2370,10 +2220,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2383,11 +2235,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2397,10 +2251,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2409,12 +2265,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2424,11 +2297,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2438,11 +2313,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2452,11 +2328,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2466,12 +2344,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2481,11 +2361,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2495,10 +2376,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2508,11 +2391,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2522,10 +2406,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2535,11 +2421,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2549,12 +2437,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2564,13 +2454,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2580,11 +2472,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2594,11 +2488,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2608,10 +2504,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2621,11 +2519,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2635,11 +2534,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2649,13 +2549,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2665,11 +2566,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2679,11 +2582,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2693,12 +2597,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2708,10 +2613,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2721,11 +2628,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2735,13 +2644,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2751,10 +2661,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2821,10 +2733,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { @@ -2834,11 +2748,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2848,10 +2780,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2861,11 +2795,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2875,10 +2811,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2888,10 +2826,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2901,10 +2841,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2930,10 +2872,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2943,11 +2887,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2957,11 +2903,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2971,11 +2919,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2985,89 +2935,79 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -3131,12 +3071,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "license": "MIT" - }, "node_modules/@babel/runtime": { - "version": "7.24.7", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -6216,11 +6154,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -6973,10 +6913,12 @@ "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.37.1", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.24.2" }, "funding": { "type": "opencollective", @@ -10629,10 +10571,14 @@ }, "node_modules/regenerate": { "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -10643,23 +10589,29 @@ }, "node_modules/regenerator-runtime": { "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexpu-core": { - "version": "5.3.2", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -10690,22 +10642,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/requires-port": { "version": "1.0.0", "license": "MIT" @@ -11807,7 +11761,9 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "license": "MIT", "engines": { "node": ">=4" @@ -11815,6 +11771,8 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -11825,7 +11783,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "license": "MIT", "engines": { "node": ">=4" @@ -11833,6 +11793,8 @@ }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "license": "MIT", "engines": { "node": ">=4" diff --git a/package.json b/package.json index 641127db4..8a10a6452 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@babel/core": "^7.26.0", "@babel/parser": "^7.26.2", "@babel/plugin-proposal-decorators": "^7.25.9", - "@babel/preset-env": "^7.24.4", + "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.24.6", "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", From ade6c22a93656c4fe1d06534e344a611834b4f8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:48:54 +0000 Subject: [PATCH 68/75] Bump esbuild-node-externals from 1.14.0 to 1.15.0 Bumps [esbuild-node-externals](https://github.com/pradel/esbuild-node-externals) from 1.14.0 to 1.15.0. - [Release notes](https://github.com/pradel/esbuild-node-externals/releases) - [Commits](https://github.com/pradel/esbuild-node-externals/compare/v1.14.0...v1.15.0) --- updated-dependencies: - dependency-name: esbuild-node-externals dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 +++++--- package.json | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index a61d5528a..0f59146bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "dir-compare": "^5.0.0", "dotenv": "^16.4.5", "esbuild": "^0.18.20", - "esbuild-node-externals": "^1.14.0", + "esbuild-node-externals": "^1.15.0", "execa": "^9.4.0", "express": "^4.19.2", "fs-extra": "^11.2.0", @@ -7359,7 +7359,9 @@ } }, "node_modules/esbuild-node-externals": { - "version": "1.14.0", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/esbuild-node-externals/-/esbuild-node-externals-1.15.0.tgz", + "integrity": "sha512-lM5f3CQL9Ctv6mBwwYAEMcphK2qrjVRnemT1mufECpFaidZvFVvQDPcuno/MQfLVk4utVuSVxm1RHLyg/ONQ/A==", "license": "MIT", "dependencies": { "find-up": "^5.0.0", @@ -7369,7 +7371,7 @@ "node": ">=12" }, "peerDependencies": { - "esbuild": "0.12 - 0.23" + "esbuild": "0.12 - 0.24" } }, "node_modules/esbuild/node_modules/@esbuild/android-arm": { diff --git a/package.json b/package.json index 641127db4..347cb7079 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "dir-compare": "^5.0.0", "dotenv": "^16.4.5", "esbuild": "^0.18.20", - "esbuild-node-externals": "^1.14.0", + "esbuild-node-externals": "^1.15.0", "execa": "^9.4.0", "express": "^4.19.2", "fs-extra": "^11.2.0", From fa559e7018725adb500ba4ca8037e150277089b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:49:05 +0000 Subject: [PATCH 69/75] Bump @rollup/rollup-darwin-x64 from 4.18.0 to 4.28.0 Bumps [@rollup/rollup-darwin-x64](https://github.com/rollup/rollup) from 4.18.0 to 4.28.0. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.18.0...v4.28.0) --- updated-dependencies: - dependency-name: "@rollup/rollup-darwin-x64" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 10 ++++++---- package.json | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a61d5528a..c5ab61e07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", "@genezio/test-interface-component": "^1.2.3", + "@rollup/rollup-darwin-x64": "4.28.0", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.118.0", "@types/adm-zip": "^0.5.6", @@ -125,7 +126,7 @@ "@rollup/rollup-android-arm-eabi": "4.22.4", "@rollup/rollup-android-arm64": "4.21.3", "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.28.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", "@rollup/rollup-linux-arm64-gnu": "4.27.4", "@rollup/rollup-linux-arm64-musl": "4.25.0", @@ -4206,12 +4207,13 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", - "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.0.tgz", + "integrity": "sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" diff --git a/package.json b/package.json index 641127db4..dbae795d3 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "@rollup/rollup-android-arm-eabi": "4.22.4", "@rollup/rollup-android-arm64": "4.21.3", "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.28.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", "@rollup/rollup-linux-arm64-gnu": "4.27.4", "@rollup/rollup-linux-arm64-musl": "4.25.0", From 6e9d2a2d9621f8cd411e9ae9f9b4cedfccb790ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:52:04 +0000 Subject: [PATCH 70/75] Bump @genezio/test-interface-component from 1.2.3 to 2.0.8 Bumps [@genezio/test-interface-component](https://github.com/Genez-io/test-interface-component) from 1.2.3 to 2.0.8. - [Release notes](https://github.com/Genez-io/test-interface-component/releases) - [Commits](https://github.com/Genez-io/test-interface-component/compare/v1.2.3...v2.0.8) --- updated-dependencies: - dependency-name: "@genezio/test-interface-component" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 1956 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 1854 insertions(+), 104 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7170da504..993443609 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,7 @@ "@babel/preset-react": "^7.24.6", "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", - "@genezio/test-interface-component": "^1.2.3", - "@rollup/rollup-darwin-x64": "4.28.0", + "@genezio/test-interface-component": "^2.0.8", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.120.0", "@types/adm-zip": "^0.5.6", @@ -3126,6 +3125,158 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.5.tgz", + "integrity": "sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz", + "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz", + "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -3589,9 +3740,65 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, "node_modules/@genezio/test-interface-component": { - "version": "1.2.3", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@genezio/test-interface-component/-/test-interface-component-2.0.8.tgz", + "integrity": "sha512-6f9n9cnWrUtZdg4hCVItVP7v4RdvOCpxmwqeLGyYIVOTz99zYJzRka9LmBHnq/ZH0X3tVxH3TdkbxaowNiVOfw==", "license": "ISC", + "dependencies": { + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@iconify/react": "^5.0.2", + "@monaco-editor/react": "^4.6.0", + "@mui/icons-material": "^6.1.7", + "@mui/material": "^6.1.7", + "@mui/x-tree-view": "^7.22.1", + "@radix-ui/react-dropdown-menu": "^2.1.2", + "@react-spring/web": "^9.7.5", + "file-type": "^19.6.0", + "jszip": "^3.10.1", + "react-awesome-tabs": "^0.1.0", + "react-hot-toast": "^2.4.1", + "react-loading-skeleton": "^3.5.0" + }, "peerDependencies": { "react": "^18.2.0 || >=18.x", "react-dom": "^18.2.0 || >=18.x" @@ -3647,6 +3854,27 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@iconify/react": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@iconify/react/-/react-5.0.2.tgz", + "integrity": "sha512-wtmstbYlEbo4NDxFxBJkhkf9gJBDqMGr7FaqLrAUMneRV3Z+fVHLJjOhWbkAF8xDQNFC/wcTYdrWo1lnRhmagQ==", + "license": "MIT", + "dependencies": { + "@iconify/types": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/cyberalien" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, "node_modules/@inquirer/checkbox": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.1.tgz", @@ -4035,96 +4263,1051 @@ "tslib": "2" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, + "node_modules/@monaco-editor/loader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", + "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "state-local": "^1.0.6" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "monaco-editor": ">= 0.21.0 < 1" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, + "node_modules/@monaco-editor/react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", + "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "license": "MIT", + "dependencies": { + "@monaco-editor/loader": "^1.4.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.9.tgz", + "integrity": "sha512-TWqj7b1w5cmSz4H/uf+y2AHxAH4ldPR7D2bz0XVyn60GCAo/zRbRPx7cF8gTs/i7CiYeHzV6dtat0VpMwOtolw==", "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.9.tgz", + "integrity": "sha512-AzlhIT51rdjkZ/EcUV2dbhNkNSUHIqCnNoUxodpiTw8buyAUBd+qnxg5OBSuPpun/ZEdSSB8Q7Uyh6zqjiMsEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0" + }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^6.1.9", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, + "node_modules/@mui/material": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz", + "integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.1.9", + "@mui/system": "^6.1.9", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.9", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.1.9", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", + "node_modules/@mui/private-theming": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.9.tgz", + "integrity": "sha512-7aum/O1RquBYhfwL/7egDyl9GqJgPM6hoJDFFBbhF6Sgv9yI9v4w3ArKUkuVvR0CtVj4NXRVMKEioh1bjUzvuA==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.1.9", + "prop-types": "^15.8.1" + }, "engines": { - "node": ">=14" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", + "node_modules/@mui/styled-engine": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.9.tgz", + "integrity": "sha512-xynSLlJRxHLzSfQaiDjkaTx8LiFb9ByVa7aOdwFnTxGWFMY1F+mkXwAUY4jDDE+MAxkWxlzzQE0wOohnsxhdQg==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, "engines": { - "node": ">=12.22.0" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } } }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", + "node_modules/@mui/system": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.9.tgz", + "integrity": "sha512-8x+RucnNp21gfFYsklCaZf0COXbv3+v0lrVuXONxvPEkESi2rwLlOi8UPJfcz6LxZOAX3v3oQ7qw18vnpgueRg==", "license": "MIT", "dependencies": { - "graceful-fs": "4.2.10" + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.1.9", + "@mui/styled-engine": "^6.1.9", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.9", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.22.0" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "license": "ISC" + "node_modules/@mui/types": { + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", + "node_modules/@mui/utils": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.9.tgz", + "integrity": "sha512-N7uzBp7p2or+xanXn3aH2OTINC6F/Ru/U8h6amhRZEev8bJhKN86rIDIoxZZ902tj+09LXtH83iLxFMjMHyqNA==", "license": "MIT", "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.19", + "@types/prop-types": "^15.7.13", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" }, "engines": { - "node": ">=12" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", - "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] + "node_modules/@mui/x-internals": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.23.0.tgz", + "integrity": "sha512-bPclKpqUiJYIHqmTxSzMVZi6MH51cQsn5U+8jskaTlo3J4QiMeCYJn/gn7YbeR9GOZFp8hetyHjoQoVHKRXCig==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", - "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", - "cpu": [ + "node_modules/@mui/x-tree-view": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-7.23.0.tgz", + "integrity": "sha512-67e+FCVMD2A5IaNettHFLUg09j+mMOWlN9f0Uw+LGePA9vLCAMFBdPZIFa18J9F3hTurNLrFzjVA0O4QfHlvrQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-internals": "7.23.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", + "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz", + "integrity": "sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.2", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz", + "integrity": "sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", + "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "license": "MIT" + }, + "node_modules/@react-spring/web": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", + "cpu": [ "arm64" ], "optional": true, @@ -5070,6 +6253,12 @@ "node": ">=16.0.0" } }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, "node_modules/@types/adm-zip": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.6.tgz", @@ -5322,6 +6511,18 @@ "@types/node": "*" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "license": "MIT" + }, "node_modules/@types/qs": { "version": "6.9.15", "dev": true, @@ -5332,6 +6533,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/readdir-glob": { "version": "1.1.5", "dev": true, @@ -6073,6 +7293,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "license": "MIT" @@ -6138,6 +7370,21 @@ "version": "1.6.6", "license": "Apache-2.0" }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "license": "MIT", @@ -6512,7 +7759,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6768,6 +8014,15 @@ "node": ">= 12" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6944,6 +8199,31 @@ "node": ">= 0.10" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/crc-32": { "version": "1.2.2", "license": "Apache-2.0", @@ -6998,6 +8278,12 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -7134,6 +8420,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/diff3": { "version": "0.0.3", "license": "MIT" @@ -7186,6 +8478,16 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dotenv": { "version": "16.4.5", "license": "BSD-2-Clause", @@ -7250,6 +8552,15 @@ "string-template": "~0.2.1" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -7648,6 +8959,18 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { "version": "8.57.0", "dev": true, @@ -7752,17 +9075,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "dev": true, @@ -7954,20 +9266,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/execa/node_modules/get-stream": { - "version": "9.0.1", - "license": "MIT", - "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/execa/node_modules/is-stream": { "version": "4.0.1", "license": "MIT", @@ -8165,6 +9463,24 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-type": { + "version": "19.6.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-19.6.0.tgz", + "integrity": "sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==", + "license": "MIT", + "dependencies": { + "get-stream": "^9.0.1", + "strtok3": "^9.0.1", + "token-types": "^6.0.0", + "uint8array-extras": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, "node_modules/fill-range": { "version": "7.1.1", "license": "MIT", @@ -8205,6 +9521,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "license": "MIT", @@ -8351,12 +9673,55 @@ "version": "1.0.0-beta.2", "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=6.9.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/get-east-asian-width": { - "version": "1.2.0", + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, "engines": { "node": ">=18" }, @@ -8364,22 +9729,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, + "node_modules/get-stream/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/glob": { @@ -8445,6 +9804,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8512,6 +9880,21 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -8618,7 +10001,6 @@ }, "node_modules/import-fresh": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -8683,6 +10065,15 @@ "node": ">= 0.10" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "license": "MIT", @@ -8690,6 +10081,12 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, "node_modules/is-binary-path": { "version": "2.1.0", "license": "MIT", @@ -8946,6 +10343,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -8976,6 +10379,57 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "dev": true, @@ -9073,6 +10527,12 @@ "url": "https://github.com/sponsors/antonk52" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/lint-staged": { "version": "15.2.10", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", @@ -9514,7 +10974,6 @@ "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", - "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -9693,6 +11152,13 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/monaco-editor": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz", + "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==", + "license": "MIT", + "peer": true + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -10102,7 +11568,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -10120,6 +11585,24 @@ "node": ">=14" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-ms": { "version": "4.0.0", "license": "MIT", @@ -10192,7 +11675,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10213,6 +11695,19 @@ "node": ">= 14.16" } }, + "node_modules/peek-readable": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.3.1.tgz", + "integrity": "sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", @@ -10383,6 +11878,23 @@ "version": "2.0.1", "license": "MIT" }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/proto-list": { "version": "1.2.4", "license": "ISC" @@ -10505,6 +12017,12 @@ "node": ">=0.10.0" } }, + "node_modules/react-awesome-tabs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/react-awesome-tabs/-/react-awesome-tabs-0.1.0.tgz", + "integrity": "sha512-KSIrypaXXlkk0IIWqJSDyXhnny+znJ/gD3RdjBNuT2OfxptwlVuGc//JzXJq2Jl51aEqWxWud54GH5Aj/pf64w==", + "license": "MIT" + }, "node_modules/react-dom": { "version": "18.3.1", "license": "MIT", @@ -10517,6 +12035,123 @@ "react": "^18.3.1" } }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", + "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "license": "MIT", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-loading-skeleton": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.5.0.tgz", + "integrity": "sha512-gxxSyLbrEAdXTKgfbpBEFZCO/P153DnqSCQau2+o6lNy1jgMRr2MmRmOzMmyrwSaSYLRB8g7b0waYPmUjz7IhQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", + "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.6", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/readable-stream": { "version": "4.5.2", "license": "MIT", @@ -10687,7 +12322,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11160,6 +12794,12 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "license": "ISC" @@ -11372,6 +13012,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -11397,6 +13046,12 @@ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "license": "MIT", @@ -11555,6 +13210,29 @@ "version": "1.0.5", "license": "MIT" }, + "node_modules/strtok3": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-9.1.1.tgz", + "integrity": "sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.3.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "license": "MIT", @@ -11668,6 +13346,23 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.0.0.tgz", + "integrity": "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -11761,6 +13456,18 @@ "node": ">=14.17" } }, + "node_modules/uint8array-extras": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz", + "integrity": "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", @@ -11875,6 +13582,49 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" diff --git a/package.json b/package.json index 0ae8ae9d5..8174264b5 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@babel/preset-react": "^7.24.6", "@babel/preset-typescript": "^7.24.6", "@babel/traverse": "^7.24.1", - "@genezio/test-interface-component": "^1.2.3", + "@genezio/test-interface-component": "^2.0.8", "@sentry/node": "^7.119.1", "@sentry/profiling-node": "~7.120.0", "@types/adm-zip": "^0.5.6", From c8b6e3b66daa2d2d0a498a8e7ff845835f9152c1 Mon Sep 17 00:00:00 2001 From: Bogdan Vlad Date: Mon, 2 Dec 2024 11:38:44 +0200 Subject: [PATCH 71/75] Add support for nextjs image optimization. (#1547) * Add support for nextjs image optimization. * Add mount fs configuration file. --- src/commands/deploy/nextjs/deploy.ts | 122 +++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 5 deletions(-) diff --git a/src/commands/deploy/nextjs/deploy.ts b/src/commands/deploy/nextjs/deploy.ts index d9aeeb4ab..d3f96d0d6 100644 --- a/src/commands/deploy/nextjs/deploy.ts +++ b/src/commands/deploy/nextjs/deploy.ts @@ -1,6 +1,6 @@ +import git from "isomorphic-git"; import fs from "fs"; import { GenezioDeployOptions } from "../../../models/commandOptions.js"; -import git from "isomorphic-git"; import { YamlProjectConfiguration } from "../../../projectConfiguration/yaml/v2.js"; import path from "path"; import { debugLogger, log } from "../../../utils/logging.js"; @@ -83,6 +83,7 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { await checkProjectLimitations(componentPath); const cacheToken = randomUUID(); + const sharpInstallFolder = await installSharp(cwd); const [deploymentResult, domainName] = await Promise.all([ // Deploy NextJs serverless functions @@ -95,7 +96,13 @@ export async function nextJsDeploy(options: GenezioDeployOptions) { // Upload the project code to S3 for in-browser editing uploadUserCode(genezioConfig.name, genezioConfig.region, options.stage, componentPath), // Set environment variables for the Next.js project - setupEnvironmentVariables(deploymentResult, domainName, genezioConfig.region, cacheToken), + setupEnvironmentVariables( + deploymentResult, + domainName, + genezioConfig.region, + cacheToken, + sharpInstallFolder, + ), // Deploy CDN that serves the Next.js app deployCDN( deploymentResult.functions[0], @@ -136,6 +143,7 @@ async function setupEnvironmentVariables( domainName: string, region: string, cacheToken: string, + sharpInstallFolder: string, ) { debugLogger.debug(`Setting Next.js environment variables, ${JSON.stringify(deploymentResult)}`); await setEnvironmentVariables(deploymentResult.projectId, deploymentResult.projectEnvId, [ @@ -163,6 +171,10 @@ async function setupEnvironmentVariables( name: "AWS_SECRET_ACCESS_KEY", value: NEXT_JS_GET_SECRET_ACCESS_KEY, }, + { + name: "NEXT_SHARP_PATH", + value: sharpInstallFolder, + }, { name: "AWS_REGION", value: region, @@ -283,16 +295,21 @@ async function deployStaticAssets( return domain; } -async function deployFunction(config: YamlProjectConfiguration, cwd: string, stage?: string) { +async function deployFunction( + config: YamlProjectConfiguration, + cwd: string, + stage?: string, +): Promise { const cloudProvider = await getCloudProvider(config.name); const cloudAdapter = getCloudAdapter(cloudProvider); const cwdRelative = path.relative(process.cwd(), cwd) || "."; + writeMountFolderConfig(cwd); const serverFunction = { path: ".", name: "nextjs", - entry: "server.js", + entry: "start.js", handler: "handler", type: FunctionType.httpServer, }; @@ -311,6 +328,23 @@ async function deployFunction(config: YamlProjectConfiguration, cwd: string, sta }, }; + await fs.promises.cp( + path.join(cwd, "public"), + path.join(cwd, ".next", "standalone", "public"), + { + recursive: true, + }, + ); + await fs.promises.cp( + path.join(cwd, ".next", "static"), + path.join(cwd, ".next", "standalone", ".next", "static"), + { recursive: true }, + ); + // create mkdir cache folder in .next + await fs.promises.mkdir(path.join(cwd, ".next", "standalone", ".next", "cache", "images"), { + recursive: true, + }); + const projectConfiguration = new ProjectConfiguration( deployConfig, await getCloudProvider(deployConfig.name), @@ -412,6 +446,46 @@ const nextConfig = { ${isESM ? "export default nextConfig;" : "module.exports = nextConfig;"}`; } +function writeMountFolderConfig(cwd: string) { + const configPath = path.join(cwd, ".next", "standalone", "start.js"); + const content = ` +const { exec } = require('child_process'); + +const target = '/tmp/package/.next/cache'; +const source = '/tmp/next-cache'; +exec(\`mkdir -p \${target}\`, (error, stdout, stderr) => { + if (error) { + console.error(\`Error1: \${error.message}\`); + return; + } +}); + +exec(\`mkdir -p \${source}\`, (error, stdout, stderr) => { + if (error) { + console.error(\`Error2: \${error.message}\`); + return; + } +}); + + +exec(\`mount --bind \${source} \${target}\`, (error, stdout, stderr) => { + if (error) { + console.error(\`Error: \${error.message}\`); + return; + } + if (stderr) { + console.error(\`Stderr: \${stderr}\`); + return; + } + console.log(\`Bind mount created successfully:\n\${stdout}\`); +}); + +const app = require("./server.js"); +`; + + fs.writeFileSync(configPath, content); +} + function getCacheHandlerContent(extension: "ts" | "mjs" | "js", region: string): string { const imports = { ts: `// @ts-nocheck @@ -428,10 +502,11 @@ interface CacheOptions { const exportStatement = extension === "js" ? "module.exports = " : "export default "; return `${imports[extension]} - + const deployment = process.env["GENEZIO_DOMAIN_NAME"] || ""; const token = (process.env["GENEZIO_CACHE_TOKEN"] || "") + "/_cache/" + (process.env["NEXT_BUILD_ID"] || ""); + ${exportStatement}class CacheHandler { constructor(options) { this.queue = Queue; @@ -476,6 +551,43 @@ ${exportStatement}class CacheHandler { }`; } +// Install sharp dependency. +// Sharp uses some binary dependencies and we have to install the ones that are compatible with +// Genezio environment. +// +// Another issue is that the nextjs standalone build output includes only the minimal set of +// dependencies, so we have to install sharp in a separate folder and then reference it in the +// nextjs project using the environment variable NEXT_SHARP_PATH. +async function installSharp(cwd: string): Promise { + // Create folder + const sharpPath = path.join(cwd, ".next", "standalone", "sharp"); + await fs.promises.mkdir(sharpPath, { recursive: true }); + + // Create package.json + fs.writeFileSync( + path.join(sharpPath, "package.json"), + JSON.stringify({ + name: "sharp-project", + version: "1.0.0", + }), + ); + + // Install sharp + await $({ + stdio: "inherit", + cwd: sharpPath, + env: { + ...process.env, + NEXT_PRIVATE_STANDALONE: "true", + }, + })`npm install --no-save --os=linux --cpu=x64 sharp`.catch(() => { + throw new UserError("Failed to install sharp deps."); + }); + + // This is relative to where it is used by the nextjs code. + return "../../../../sharp/node_modules/sharp"; +} + function writeConfigFiles(cwd: string, extension: "js" | "mjs" | "ts", region: string): void { fs.writeFileSync(path.join(cwd, `next.config.${extension}`), getConfigContent(extension)); From 5de6cd6e1bf2559a7b5e7e2a352e347a0f19acf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 2 Dec 2024 13:37:26 +0200 Subject: [PATCH 72/75] Add `genezio create` in README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreia Ocănoaia --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 7317ee416..2c4ed02ae 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,12 @@ npm install -g genezio Visit the [Genezio template page](https://app.genez.io/new-project) and create a new project. You can choose from a variety of templates or start from scratch. +If you want to create a new project from scratch, you can run the following command: + +```bash +genezio create +``` + If you already have a project you can either [import it from you GitHub repository](https://app.genez.io/import) or deploy it from your local machine using the following command: ```bash From 631e26e8c5162c8d5b843bc5f2810f23595f24f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreia=20Oc=C4=83noaia?= Date: Mon, 2 Dec 2024 16:06:38 +0200 Subject: [PATCH 73/75] Reimplement the entryfile detection algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now, we are searching the package.json for a main module. If this is found in the filesystem, we are setting that as an entryfile. If the user defined and used the main file as set in package.json, we will trust he set it correctly. Else, we are searching for patterns and set it as an entryfile. This approach is less error-prone. Signed-off-by: Andreia Ocănoaia --- src/commands/analyze/frameworks.ts | 50 +++++++++++------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/src/commands/analyze/frameworks.ts b/src/commands/analyze/frameworks.ts index 425d87d80..85414c495 100644 --- a/src/commands/analyze/frameworks.ts +++ b/src/commands/analyze/frameworks.ts @@ -2,6 +2,7 @@ import { promises as fs } from "fs"; import path from "path"; import { EXCLUDED_DIRECTORIES, KEY_DEPENDENCY_FILES } from "./command.js"; import { FUNCTION_EXTENSIONS } from "../../models/projectOptions.js"; +import { debugLogger } from "../../utils/logging.js"; export interface PackageJSON { name?: string; @@ -40,31 +41,27 @@ export async function isTypescript(contents: Record): Promise, patterns: RegExp[], defaultFile: string, ): Promise { - const { candidateFile, fallback } = await getEntryFileFromPackageJson( - componentPath, - contents, - patterns, - ); - if (candidateFile && !fallback) { + const candidateFile = await getEntryFileFromPackageJson(componentPath, contents); + if (candidateFile) { return candidateFile; } const entryFile = await findFileByPatterns(componentPath, patterns, FUNCTION_EXTENSIONS); - - // If we didn't find a suitable entry file, we set the entry as defined in package.json - // If this is not an option either, we set the default entry file - // Note - this is useful for ts projects where the entry file is not yet compiled - if (!entryFile) { - return candidateFile && fallback ? candidateFile : defaultFile; + if (entryFile) { + return entryFile; } - return entryFile; + return defaultFile; } async function findFileByPatterns( @@ -97,40 +94,29 @@ async function findFileByPatterns( return undefined; } -// Returns an object containing: -// - `candidateFile`: The path to the main file in package.json if it exists and matches patterns. -// - `fallback`: A boolean indicating if the file should be considered a fallback entry. +// Returns an object containing `candidateFile`: The path to the main file in package.json if it exists. async function getEntryFileFromPackageJson( directory: string, contents: Record, - patterns: RegExp[], -): Promise<{ candidateFile: string | undefined; fallback: boolean }> { +): Promise { if (!contents["package.json"]) { - return { candidateFile: undefined, fallback: false }; + return undefined; } const packageJsonContent = JSON.parse(contents["package.json"]) as PackageJSON; const mainPath = packageJsonContent.main; if (!mainPath) { - return { candidateFile: undefined, fallback: false }; + return undefined; } const fullPath = path.join(directory, mainPath); - // Check if the mainPath exists try { - await fs.access(fullPath); + if (fullPath) await fs.access(fullPath); + return mainPath; } catch { - return { candidateFile: mainPath, fallback: true }; + debugLogger.debug(`File ${fullPath} does not exist`); + return undefined; } - - // Check if the main file contains patterns that indicate it is indeed an entry file - const entryFileContent = await fs.readFile(fullPath, "utf-8"); - const allPatternsMatch = patterns.every((pattern) => pattern.test(entryFileContent)); - if (!allPatternsMatch) { - return { candidateFile: mainPath, fallback: true }; - } - - return { candidateFile: mainPath, fallback: false }; } export async function hasPostgresDependency( From 8be3e17cc4f2e869a795baf6473d946ad7c51d40 Mon Sep 17 00:00:00 2001 From: Cristi Miloiu Date: Tue, 3 Dec 2024 14:37:23 +0200 Subject: [PATCH 74/75] Handle pyproject.toml --- src/commands/analyze/command.ts | 4 +-- src/commands/analyze/frameworks.ts | 49 +++++++++++++++--------------- src/commands/deploy/genezio.ts | 39 +++++++++++++++--------- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/commands/analyze/command.ts b/src/commands/analyze/command.ts index 63c314a85..7484d8b41 100644 --- a/src/commands/analyze/command.ts +++ b/src/commands/analyze/command.ts @@ -96,8 +96,8 @@ export enum SUPPORTED_FORMATS { export const DEFAULT_FORMAT = SUPPORTED_FORMATS.TEXT; export const DEFAULT_CI_FORMAT = SUPPORTED_FORMATS.JSON; -export const KEY_FILES = ["package.json", "requirements.txt"]; -export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt"]; +export const KEY_FILES = ["package.json", "requirements.txt", "pyproject.toml"]; +export const KEY_DEPENDENCY_FILES = ["package.json", "requirements.txt", "pyproject.toml"]; export const ENVIRONMENT_EXAMPLE_FILES = [".env.template", ".env.example", ".env.local.example"]; export const EXCLUDED_DIRECTORIES = ["node_modules", ".git", "dist", "build", "tests"]; export const NODE_DEFAULT_ENTRY_FILE = "index.mjs"; diff --git a/src/commands/analyze/frameworks.ts b/src/commands/analyze/frameworks.ts index 85414c495..03b8c6cbe 100644 --- a/src/commands/analyze/frameworks.ts +++ b/src/commands/analyze/frameworks.ts @@ -351,15 +351,9 @@ export async function isSvelteComponent(contents: Record): Promi : false; } -// Checks if the project is a Python component (presence of 'requirements.txt') -// `contents` is a map of important file paths and their contents +// Checks if the project is a Python component (presence of 'requirements.txt' or 'pyproject.toml') export function isPythonComponent(contents: Record): boolean { - if (!contents["requirements.txt"]) { - return false; - } - - const requirementsTxt = contents["requirements.txt"]; - return requirementsTxt !== undefined; + return contents["requirements.txt"] !== undefined || contents["pyproject.toml"] !== undefined; } // Checks if the project is a Golang component (presence of 'go.mod') @@ -386,36 +380,41 @@ export function isContainerComponent(contents: Record): boolean // Checks if the project is a Flask component (presence of 'requirements.txt', and 'flask' in 'requirements.txt') export function isFlaskComponent(contents: Record): boolean { - if (!contents["requirements.txt"]) { - return false; + if (contents["requirements.txt"]) { + return /flask(?:==|$|\s)/i.test(contents["requirements.txt"]); + } + if (contents["pyproject.toml"]) { + const content = contents["pyproject.toml"]; + return /\bflask\b/i.test(content); } - const requirementsTxt = contents["requirements.txt"]; - return requirementsTxt !== undefined && /flask(?:==|$|\s)/i.test(requirementsTxt); // Case-insensitive match for "flask", "Flask", "flask==", or "Flask==" + return false; } // Checks if the project is a Django component (presence of 'requirements.txt', and 'django' in 'requirements.txt') export function isDjangoComponent(contents: Record): boolean { - if (!contents["requirements.txt"]) { - return false; + if (contents["requirements.txt"]) { + return /django(?:==|$|\s)/i.test(contents["requirements.txt"]); } - const requirementsTxt = contents["requirements.txt"]; - return requirementsTxt !== undefined && /django(?:==|$|\s)/i.test(requirementsTxt); + if (contents["pyproject.toml"]) { + const content = contents["pyproject.toml"]; + return /\bdjango\b/i.test(content); + } + return false; } // Checks if the project is a FastAPI component (presence of 'requirements.txt', and 'fastapi' in 'requirements.txt') export function isFastAPIComponent(contents: Record): boolean { - if (!contents["requirements.txt"]) { - return false; + if (contents["requirements.txt"]) { + return /fastapi(?:==|$|\s)/i.test(contents["requirements.txt"]); + } + if (contents["pyproject.toml"]) { + const content = contents["pyproject.toml"]; + return /\bfastapi\b/i.test(content); } - const requirementsTxt = contents["requirements.txt"]; - return requirementsTxt !== undefined && /fastapi(?:==|$|\s)/i.test(requirementsTxt); + return false; } // Checks if the project is a Python function that is compatible with AWS Lambda (presence of 'requirements.txt') export function isPythonLambdaFunction(contents: Record): boolean { - if (!("requirements.txt" in contents)) { - return false; - } - - return true; + return contents["requirements.txt"] !== undefined || contents["pyproject.toml"] !== undefined; } diff --git a/src/commands/deploy/genezio.ts b/src/commands/deploy/genezio.ts index eb446a3f6..96b37b517 100644 --- a/src/commands/deploy/genezio.ts +++ b/src/commands/deploy/genezio.ts @@ -697,26 +697,35 @@ export async function functionToCloudInput( }; // Requirements file must be in the root of the backend folder const requirementsPath = path.join(backendPath, "requirements.txt"); - if (fs.existsSync(requirementsPath)) { - const requirementsOutputPath = path.join(tmpFolderPath, "requirements.txt"); - const requirementsContent = fs.readFileSync(requirementsOutputPath, "utf8").trim(); - if (requirementsContent) { - const pathForDependencies = path.join(tmpFolderPath, "packages"); - const packageManager = getPackageManager(); - let installCommand; - - if (packageManager.command === "pip" || packageManager.command === "pip3") { - installCommand = `${packageManager.command} install -r ${requirementsOutputPath} --platform manylinux2014_x86_64 --only-binary=:all: --python-version ${supportedPythonDepsInstallVersion} -t ${pathForDependencies}`; - } else if (packageManager.command === "poetry") { - installCommand = `${packageManager.command} install --no-root --directory ${pathForDependencies}`; - } else { - throw new UserError(`Unsupported package manager: ${packageManager.command}`); + const pyProjectTomlPath = path.join(backendPath, "pyproject.toml"); + if (fs.existsSync(requirementsPath) || fs.existsSync(pyProjectTomlPath)) { + const pathForDependencies = path.join(tmpFolderPath, "packages"); + const packageManager = getPackageManager(); + let installCommand; + + if (packageManager.command === "pip" || packageManager.command === "pip3") { + if (fs.existsSync(requirementsPath)) { + const requirementsOutputPath = path.join(tmpFolderPath, "requirements.txt"); + const requirementsContent = fs + .readFileSync(requirementsOutputPath, "utf8") + .trim(); + if (requirementsContent) { + installCommand = `${packageManager.command} install -r ${requirementsOutputPath} --platform manylinux2014_x86_64 --only-binary=:all: --python-version ${supportedPythonDepsInstallVersion} -t ${pathForDependencies}`; + } + } else if (fs.existsSync(pyProjectTomlPath)) { + installCommand = `${packageManager.command} install . --platform manylinux2014_x86_64 --only-binary=:all: --python-version ${supportedPythonDepsInstallVersion} -t ${pathForDependencies}`; } + } else if (packageManager.command === "poetry") { + installCommand = `${packageManager.command} install --no-root --directory ${pathForDependencies}`; + } else { + throw new UserError(`Unsupported package manager: ${packageManager.command}`); + } + if (installCommand) { debugLogger.debug(`Installing dependencies using command: ${installCommand}`); await runScript(installCommand, tmpFolderPath); } else { - debugLogger.debug("No requirements.txt file found."); + debugLogger.debug("No valid requirements.txt or pyproject.toml found."); } } } From 14f8691cf80ee853f58b01d3cf3087c88377e556 Mon Sep 17 00:00:00 2001 From: Bogdan Vlad Date: Wed, 4 Dec 2024 14:15:06 +0200 Subject: [PATCH 75/75] Release v3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8174264b5..e36975477 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "genezio", - "version": "2.6.9", + "version": "3.0.0", "description": "Command line utility to interact with Genezio infrastructure.", "exports": "./index.js", "type": "module",