@base44-preview/cli 0.0.1-pr.13.e830fa0 → 0.0.1-pr.14.987d307
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js
CHANGED
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
-
import { intro, log, spinner } from "@clack/prompts";
|
|
4
|
+
import { cancel, intro, isCancel, log, spinner, text } from "@clack/prompts";
|
|
5
5
|
import pWaitFor from "p-wait-for";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
7
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
+
import { config } from "dotenv";
|
|
9
10
|
import ky from "ky";
|
|
10
11
|
import { access, mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
11
12
|
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
12
13
|
import { globby } from "globby";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import ejs from "ejs";
|
|
13
16
|
|
|
17
|
+
//#region rolldown:runtime
|
|
18
|
+
var __defProp = Object.defineProperty;
|
|
19
|
+
var __exportAll = (all, symbols) => {
|
|
20
|
+
let target = {};
|
|
21
|
+
for (var name in all) {
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (symbols) {
|
|
28
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
14
34
|
//#region src/core/auth/schema.ts
|
|
15
35
|
const AuthDataSchema = z.object({
|
|
16
36
|
accessToken: z.string().min(1, "Token cannot be empty"),
|
|
@@ -73,9 +93,11 @@ var AuthValidationError = class extends Error {
|
|
|
73
93
|
};
|
|
74
94
|
|
|
75
95
|
//#endregion
|
|
76
|
-
//#region src/core/
|
|
96
|
+
//#region src/core/config.ts
|
|
77
97
|
const PROJECT_SUBDIR = "base44";
|
|
78
98
|
const FUNCTION_CONFIG_FILE = "function.jsonc";
|
|
99
|
+
const AUTH_CLIENT_ID = "base44_cli";
|
|
100
|
+
const DEFAULT_API_URL = "https://app.base44.com";
|
|
79
101
|
function getBase44Dir() {
|
|
80
102
|
return join(homedir(), ".base44");
|
|
81
103
|
}
|
|
@@ -90,15 +112,34 @@ function getProjectConfigPatterns() {
|
|
|
90
112
|
"config.json"
|
|
91
113
|
];
|
|
92
114
|
}
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Load .env.local from the project root if it exists.
|
|
117
|
+
* Values won't override existing process.env variables.
|
|
118
|
+
* Safe to call multiple times - only loads once.
|
|
119
|
+
*/
|
|
120
|
+
async function loadProjectEnv(projectRoot) {
|
|
121
|
+
const { findProjectRoot: findProjectRoot$1 } = await Promise.resolve().then(() => config_exports);
|
|
122
|
+
const found = projectRoot ? { root: projectRoot } : await findProjectRoot$1();
|
|
123
|
+
if (!found) return;
|
|
124
|
+
config({
|
|
125
|
+
path: join(found.root, ".env.local"),
|
|
126
|
+
override: false
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get the Base44 API URL.
|
|
131
|
+
* Priority: process.env.BASE44_API_URL > .env.local > default
|
|
132
|
+
*/
|
|
95
133
|
function getBase44ApiUrl() {
|
|
96
134
|
return process.env.BASE44_API_URL || DEFAULT_API_URL;
|
|
97
135
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Get the Base44 Client ID (app ID).
|
|
138
|
+
* Priority: process.env.BASE44_CLIENT_ID > .env.local
|
|
139
|
+
* Returns undefined if not set.
|
|
140
|
+
*/
|
|
141
|
+
function getBase44ClientId() {
|
|
142
|
+
return process.env.BASE44_CLIENT_ID;
|
|
102
143
|
}
|
|
103
144
|
|
|
104
145
|
//#endregion
|
|
@@ -181,8 +222,18 @@ async function getUserInfo(accessToken) {
|
|
|
181
222
|
|
|
182
223
|
//#endregion
|
|
183
224
|
//#region src/core/utils/fs.ts
|
|
184
|
-
function pathExists(path) {
|
|
185
|
-
|
|
225
|
+
async function pathExists(path) {
|
|
226
|
+
try {
|
|
227
|
+
await access(path);
|
|
228
|
+
return true;
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function writeFile$1(filePath, content) {
|
|
234
|
+
const dir = dirname(filePath);
|
|
235
|
+
if (!await pathExists(dir)) await mkdir(dir, { recursive: true });
|
|
236
|
+
await writeFile(filePath, content, "utf-8");
|
|
186
237
|
}
|
|
187
238
|
async function readJsonFile(filePath) {
|
|
188
239
|
if (!await pathExists(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
@@ -201,21 +252,13 @@ async function readJsonFile(filePath) {
|
|
|
201
252
|
}
|
|
202
253
|
}
|
|
203
254
|
async function writeJsonFile(filePath, data) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
208
|
-
} catch (error) {
|
|
209
|
-
throw new Error(`Failed to write file ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
210
|
-
}
|
|
255
|
+
const dir = dirname(filePath);
|
|
256
|
+
if (!await pathExists(dir)) await mkdir(dir, { recursive: true });
|
|
257
|
+
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
211
258
|
}
|
|
212
259
|
async function deleteFile(filePath) {
|
|
213
260
|
if (!await pathExists(filePath)) return;
|
|
214
|
-
|
|
215
|
-
await unlink(filePath);
|
|
216
|
-
} catch (error) {
|
|
217
|
-
throw new Error(`Failed to delete file ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
218
|
-
}
|
|
261
|
+
await unlink(filePath);
|
|
219
262
|
}
|
|
220
263
|
|
|
221
264
|
//#endregion
|
|
@@ -290,11 +333,13 @@ const base44Color = chalk.bgHex("#E86B3C");
|
|
|
290
333
|
/**
|
|
291
334
|
* Wraps a command function with the Base44 intro banner.
|
|
292
335
|
* All CLI commands should use this utility to ensure consistent branding.
|
|
336
|
+
* Also loads .env.local from the project root if available.
|
|
293
337
|
*
|
|
294
338
|
* @param commandFn - The async function to execute as the command
|
|
295
339
|
*/
|
|
296
340
|
async function runCommand(commandFn) {
|
|
297
341
|
intro(base44Color(" Base 44 "));
|
|
342
|
+
await loadProjectEnv();
|
|
298
343
|
try {
|
|
299
344
|
await commandFn();
|
|
300
345
|
} catch (e) {
|
|
@@ -328,6 +373,42 @@ async function runTask(startMessage, operation, options) {
|
|
|
328
373
|
}
|
|
329
374
|
}
|
|
330
375
|
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/cli/utils/prompts.ts
|
|
378
|
+
/**
|
|
379
|
+
* Handles prompt cancellation by exiting gracefully.
|
|
380
|
+
*/
|
|
381
|
+
function handleCancel(value) {
|
|
382
|
+
if (isCancel(value)) {
|
|
383
|
+
cancel("Operation cancelled.");
|
|
384
|
+
process.exit(0);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Wrapper around @clack/prompts text() that handles cancellation automatically.
|
|
389
|
+
* Returns the string value directly, exits process if cancelled.
|
|
390
|
+
*/
|
|
391
|
+
async function textPrompt(options) {
|
|
392
|
+
const value = await text(options);
|
|
393
|
+
handleCancel(value);
|
|
394
|
+
return value;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
//#endregion
|
|
398
|
+
//#region src/cli/utils/banner.ts
|
|
399
|
+
const orange = chalk.hex("#E86B3C");
|
|
400
|
+
const BANNER = `
|
|
401
|
+
${orange("██████╗ █████╗ ███████╗███████╗ ██╗ ██╗██╗ ██╗")}
|
|
402
|
+
${orange("██╔══██╗██╔══██╗██╔════╝██╔════╝ ██║ ██║██║ ██║")}
|
|
403
|
+
${orange("██████╔╝███████║███████╗█████╗ ███████║███████║")}
|
|
404
|
+
${orange("██╔══██╗██╔══██║╚════██║██╔══╝ ╚════██║╚════██║")}
|
|
405
|
+
${orange("██████╔╝██║ ██║███████║███████╗ ██║ ██║")}
|
|
406
|
+
${orange("╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝")}
|
|
407
|
+
`;
|
|
408
|
+
function printBanner() {
|
|
409
|
+
console.log(BANNER);
|
|
410
|
+
}
|
|
411
|
+
|
|
331
412
|
//#endregion
|
|
332
413
|
//#region src/cli/commands/auth/login.ts
|
|
333
414
|
async function generateAndDisplayDeviceCode() {
|
|
@@ -500,19 +581,14 @@ const base44Client = ky.create({
|
|
|
500
581
|
* Returns an HTTP client scoped to the current app.
|
|
501
582
|
*/
|
|
502
583
|
function getAppClient() {
|
|
503
|
-
return base44Client.extend({ prefixUrl: new URL(`/api/apps/${
|
|
584
|
+
return base44Client.extend({ prefixUrl: new URL(`/api/apps/${getBase44ClientId()}/`, getBase44ApiUrl()).href });
|
|
504
585
|
}
|
|
505
586
|
|
|
506
587
|
//#endregion
|
|
507
588
|
//#region src/core/resources/entity/api.ts
|
|
508
589
|
async function pushEntities(entities) {
|
|
509
590
|
const appClient = getAppClient();
|
|
510
|
-
const schemaSyncPayload = entities.
|
|
511
|
-
return {
|
|
512
|
-
...acc,
|
|
513
|
-
[current.name]: current
|
|
514
|
-
};
|
|
515
|
-
}, {});
|
|
591
|
+
const schemaSyncPayload = Object.fromEntries(entities.map((entity) => [entity.name, entity]));
|
|
516
592
|
const response = await appClient.put("entities-schemas/sync-all", {
|
|
517
593
|
json: { entityNameToSchema: schemaSyncPayload },
|
|
518
594
|
throwHttpErrors: false
|
|
@@ -588,13 +664,15 @@ async function readAllFunctions(functionsDir) {
|
|
|
588
664
|
|
|
589
665
|
//#endregion
|
|
590
666
|
//#region src/core/resources/function/resource.ts
|
|
591
|
-
const functionResource = {
|
|
592
|
-
readAll: readAllFunctions,
|
|
593
|
-
push: async () => {}
|
|
594
|
-
};
|
|
667
|
+
const functionResource = { readAll: readAllFunctions };
|
|
595
668
|
|
|
596
669
|
//#endregion
|
|
597
|
-
//#region src/core/config
|
|
670
|
+
//#region src/core/project/config.ts
|
|
671
|
+
var config_exports = /* @__PURE__ */ __exportAll({
|
|
672
|
+
ProjectConfigSchema: () => ProjectConfigSchema,
|
|
673
|
+
findProjectRoot: () => findProjectRoot,
|
|
674
|
+
readProjectConfig: () => readProjectConfig
|
|
675
|
+
});
|
|
598
676
|
const ProjectConfigSchema = z.looseObject({
|
|
599
677
|
name: z.string().min(1, "Project name cannot be empty"),
|
|
600
678
|
entitiesDir: z.string().default("./entities"),
|
|
@@ -666,7 +744,7 @@ const showProjectCommand = new Command("show-project").description("Display proj
|
|
|
666
744
|
});
|
|
667
745
|
|
|
668
746
|
//#endregion
|
|
669
|
-
//#region src/core/
|
|
747
|
+
//#region src/core/project/schema.ts
|
|
670
748
|
const SiteConfigSchema = z.object({
|
|
671
749
|
buildCommand: z.string().optional(),
|
|
672
750
|
serveCommand: z.string().optional(),
|
|
@@ -679,6 +757,60 @@ const AppConfigSchema = z.object({
|
|
|
679
757
|
site: SiteConfigSchema.optional(),
|
|
680
758
|
domains: z.array(z.string()).optional()
|
|
681
759
|
});
|
|
760
|
+
const CreateProjectResponseSchema = z.looseObject({ id: z.string() });
|
|
761
|
+
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/core/project/api.ts
|
|
764
|
+
async function createProject(projectName, description) {
|
|
765
|
+
const response = await base44Client.post("api/apps", { json: {
|
|
766
|
+
name: projectName,
|
|
767
|
+
user_description: description ?? `Backend for '${projectName}'`,
|
|
768
|
+
app_type: "baas"
|
|
769
|
+
} });
|
|
770
|
+
return { projectId: CreateProjectResponseSchema.parse(await response.json()).id };
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
//#endregion
|
|
774
|
+
//#region src/core/project/templates/index.ts
|
|
775
|
+
const TEMPLATES_DIR = join(dirname(fileURLToPath(import.meta.url)), "templates");
|
|
776
|
+
const CONFIG_TEMPLATE_PATH = join(TEMPLATES_DIR, "config.jsonc.ejs");
|
|
777
|
+
const ENV_TEMPLATE_PATH = join(TEMPLATES_DIR, "env.local.ejs");
|
|
778
|
+
async function renderConfigTemplate(data) {
|
|
779
|
+
return ejs.renderFile(CONFIG_TEMPLATE_PATH, data);
|
|
780
|
+
}
|
|
781
|
+
async function renderEnvTemplate(data) {
|
|
782
|
+
return ejs.renderFile(ENV_TEMPLATE_PATH, data);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region src/core/project/init.ts
|
|
787
|
+
/**
|
|
788
|
+
* Initialize a new Base44 project.
|
|
789
|
+
* Creates the base44 directory, config.jsonc, and .env.local files.
|
|
790
|
+
*/
|
|
791
|
+
async function initProject(options) {
|
|
792
|
+
const { name, description, path: basePath } = options;
|
|
793
|
+
const projectDir = join(basePath, PROJECT_SUBDIR);
|
|
794
|
+
const configPath = join(projectDir, "config.jsonc");
|
|
795
|
+
const envPath = join(projectDir, ".env.local");
|
|
796
|
+
const existingConfigs = await globby(getProjectConfigPatterns(), {
|
|
797
|
+
cwd: basePath,
|
|
798
|
+
absolute: true
|
|
799
|
+
});
|
|
800
|
+
if (existingConfigs.length > 0) throw new Error(`A Base44 project already exists at ${existingConfigs[0]}. Please choose a different location.`);
|
|
801
|
+
const { projectId } = await createProject(name, description);
|
|
802
|
+
await writeFile$1(configPath, await renderConfigTemplate({
|
|
803
|
+
name,
|
|
804
|
+
description
|
|
805
|
+
}));
|
|
806
|
+
await writeFile$1(envPath, await renderEnvTemplate({ projectId }));
|
|
807
|
+
return {
|
|
808
|
+
projectId,
|
|
809
|
+
projectDir,
|
|
810
|
+
configPath,
|
|
811
|
+
envPath
|
|
812
|
+
};
|
|
813
|
+
}
|
|
682
814
|
|
|
683
815
|
//#endregion
|
|
684
816
|
//#region src/cli/commands/entities/push.ts
|
|
@@ -704,6 +836,50 @@ const entitiesPushCommand = new Command("entities").description("Manage project
|
|
|
704
836
|
await runCommand(pushEntitiesAction);
|
|
705
837
|
}));
|
|
706
838
|
|
|
839
|
+
//#endregion
|
|
840
|
+
//#region src/cli/commands/project/init.ts
|
|
841
|
+
async function init() {
|
|
842
|
+
printBanner();
|
|
843
|
+
await loadProjectEnv();
|
|
844
|
+
const name = await textPrompt({
|
|
845
|
+
message: "What is the name of your project?",
|
|
846
|
+
placeholder: "my-app-backend",
|
|
847
|
+
validate: (value) => {
|
|
848
|
+
if (!value || value.trim().length === 0) return "Project name is required";
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
const description = await textPrompt({
|
|
852
|
+
message: "Project description (optional)",
|
|
853
|
+
placeholder: "A brief description of your project"
|
|
854
|
+
});
|
|
855
|
+
const defaultPath = "./";
|
|
856
|
+
const resolvedPath = resolve(await textPrompt({
|
|
857
|
+
message: "Where should we create the base44 folder?",
|
|
858
|
+
placeholder: defaultPath,
|
|
859
|
+
initialValue: defaultPath
|
|
860
|
+
}) || defaultPath);
|
|
861
|
+
await runTask("Creating project...", async () => {
|
|
862
|
+
return await initProject({
|
|
863
|
+
name: name.trim(),
|
|
864
|
+
description: description ? description.trim() : void 0,
|
|
865
|
+
path: resolvedPath
|
|
866
|
+
});
|
|
867
|
+
}, {
|
|
868
|
+
successMessage: "Project created successfully",
|
|
869
|
+
errorMessage: "Failed to create project"
|
|
870
|
+
});
|
|
871
|
+
log.success(`Project ${chalk.bold(name)} has been initialized!`);
|
|
872
|
+
}
|
|
873
|
+
const initCommand = new Command("init").alias("create").description("Initialize a new Base44 project").action(async () => {
|
|
874
|
+
try {
|
|
875
|
+
await init();
|
|
876
|
+
} catch (e) {
|
|
877
|
+
if (e instanceof Error) log.error(e.stack ?? e.message);
|
|
878
|
+
else log.error(String(e));
|
|
879
|
+
process.exit(1);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
|
|
707
883
|
//#endregion
|
|
708
884
|
//#region package.json
|
|
709
885
|
var version = "0.0.1";
|
|
@@ -715,9 +891,10 @@ program.name("base44").description("Base44 CLI - Unified interface for managing
|
|
|
715
891
|
program.addCommand(loginCommand);
|
|
716
892
|
program.addCommand(whoamiCommand);
|
|
717
893
|
program.addCommand(logoutCommand);
|
|
894
|
+
program.addCommand(initCommand);
|
|
718
895
|
program.addCommand(showProjectCommand);
|
|
719
896
|
program.addCommand(entitiesPushCommand);
|
|
720
897
|
program.parse();
|
|
721
898
|
|
|
722
899
|
//#endregion
|
|
723
|
-
export {
|
|
900
|
+
export { findProjectRoot as n, readProjectConfig as r, ProjectConfigSchema as t };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Base44 Project Configuration
|
|
2
|
+
// JSONC enables inline documentation and discoverability directly in config files.
|
|
3
|
+
// Commented-out properties show available options you can enable.
|
|
4
|
+
|
|
5
|
+
{
|
|
6
|
+
"name": "<%= name %>"<% if (description) { %>,
|
|
7
|
+
"description": "<%= description %>"<% } %>
|
|
8
|
+
|
|
9
|
+
// Site/hosting configuration
|
|
10
|
+
// Docs: https://docs.base44.com/configuration/hosting
|
|
11
|
+
// "site": {
|
|
12
|
+
// "buildCommand": "npm run build",
|
|
13
|
+
// "serveCommand": "npm run dev",
|
|
14
|
+
// "outputDirectory": "./dist",
|
|
15
|
+
// "installCommand": "npm ci"
|
|
16
|
+
// }
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import ejs from "ejs";
|
|
4
|
+
|
|
5
|
+
// After bundling, import.meta.url points to dist/cli/index.js
|
|
6
|
+
// Templates are copied to dist/cli/templates/
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const TEMPLATES_DIR = join(__dirname, "templates");
|
|
9
|
+
|
|
10
|
+
const CONFIG_TEMPLATE_PATH = join(TEMPLATES_DIR, "config.jsonc.ejs");
|
|
11
|
+
const ENV_TEMPLATE_PATH = join(TEMPLATES_DIR, "env.local.ejs");
|
|
12
|
+
|
|
13
|
+
interface ConfigTemplateData {
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface EnvTemplateData {
|
|
19
|
+
projectId: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function renderConfigTemplate(
|
|
23
|
+
data: ConfigTemplateData
|
|
24
|
+
): Promise<string> {
|
|
25
|
+
return ejs.renderFile(CONFIG_TEMPLATE_PATH, data);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function renderEnvTemplate(data: EnvTemplateData): Promise<string> {
|
|
29
|
+
return ejs.renderFile(ENV_TEMPLATE_PATH, data);
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@base44-preview/cli",
|
|
3
|
-
"version": "0.0.1-pr.
|
|
3
|
+
"version": "0.0.1-pr.14.987d307",
|
|
4
4
|
"description": "Base44 CLI - Unified interface for managing Base44 applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli/index.js",
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"@clack/prompts": "^0.11.0",
|
|
37
37
|
"chalk": "^5.6.2",
|
|
38
38
|
"commander": "^12.1.0",
|
|
39
|
+
"dotenv": "^17.2.3",
|
|
40
|
+
"ejs": "^3.1.10",
|
|
39
41
|
"globby": "^16.1.0",
|
|
40
42
|
"jsonc-parser": "^3.3.1",
|
|
41
43
|
"ky": "^1.14.2",
|
|
@@ -44,6 +46,7 @@
|
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"@stylistic/eslint-plugin": "^5.6.1",
|
|
49
|
+
"@types/ejs": "^3.1.5",
|
|
47
50
|
"@types/node": "^22.10.5",
|
|
48
51
|
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
49
52
|
"@typescript-eslint/parser": "^8.51.0",
|