@base44-preview/cli 0.0.13-pr.86.f208957 → 0.0.13-pr.87.2565e16

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +180 -51
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -26329,6 +26329,58 @@ async function printBanner() {
26329
26329
  else console.log(theme.colors.base44Orange(BANNER_LINES.join("\n")));
26330
26330
  }
26331
26331
 
26332
+ //#endregion
26333
+ //#region src/cli/utils/json.ts
26334
+ /**
26335
+ * JSON output utilities for CLI commands.
26336
+ *
26337
+ * These utilities support the `--json` flag which outputs machine-readable JSON
26338
+ * instead of human-friendly formatted output.
26339
+ */
26340
+ let jsonModeEnabled = false;
26341
+ /**
26342
+ * Enable JSON output mode. Called by runCommand when --json flag is detected.
26343
+ */
26344
+ function setJsonMode(enabled) {
26345
+ jsonModeEnabled = enabled;
26346
+ }
26347
+ /**
26348
+ * Check if JSON output mode is currently active.
26349
+ */
26350
+ function isJsonMode() {
26351
+ return jsonModeEnabled;
26352
+ }
26353
+ /**
26354
+ * Output a success JSON response to stdout.
26355
+ * Only outputs if JSON mode is enabled.
26356
+ */
26357
+ function outputJson(data) {
26358
+ if (!jsonModeEnabled) return;
26359
+ const response = {
26360
+ success: true,
26361
+ data
26362
+ };
26363
+ console.log(JSON.stringify(response, null, 2));
26364
+ }
26365
+ /**
26366
+ * Output an error JSON response to stderr.
26367
+ * Only outputs if JSON mode is enabled.
26368
+ *
26369
+ * @param error - The error to output
26370
+ * @param code - Optional error code
26371
+ */
26372
+ function outputJsonError(error, code$1) {
26373
+ if (!jsonModeEnabled) return;
26374
+ const response = {
26375
+ success: false,
26376
+ error: {
26377
+ message: error instanceof Error ? error.message : error,
26378
+ ...code$1 && { code: code$1 }
26379
+ }
26380
+ };
26381
+ console.error(JSON.stringify(response, null, 2));
26382
+ }
26383
+
26332
26384
  //#endregion
26333
26385
  //#region src/cli/utils/runCommand.ts
26334
26386
  /**
@@ -26370,25 +26422,35 @@ async function printBanner() {
26370
26422
  * });
26371
26423
  */
26372
26424
  async function runCommand(commandFn, options) {
26373
- console.log();
26374
- if (options?.fullBanner) {
26375
- await printBanner();
26376
- Ie("");
26377
- } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
26425
+ const jsonMode = isJsonMode();
26426
+ if (!jsonMode) {
26427
+ console.log();
26428
+ if (options?.fullBanner) {
26429
+ await printBanner();
26430
+ Ie("");
26431
+ } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
26432
+ }
26378
26433
  await loadProjectEnv();
26379
26434
  try {
26380
26435
  if (options?.requireAuth) {
26381
26436
  if (!await isLoggedIn()) {
26437
+ if (jsonMode) throw new Error("Authentication required. Please run 'base44 login' first.");
26382
26438
  M.info("You need to login first to continue.");
26383
26439
  await login();
26384
26440
  }
26385
26441
  }
26386
- const { outroMessage } = await commandFn();
26387
- Se(outroMessage || "");
26442
+ const { outroMessage, data } = await commandFn();
26443
+ if (jsonMode) outputJson(data ?? {});
26444
+ else Se(outroMessage || "");
26388
26445
  } catch (e$1) {
26389
- if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
26390
- else M.error(String(e$1));
26391
- process.exit(1);
26446
+ if (jsonMode) {
26447
+ outputJsonError(e$1 instanceof Error ? e$1 : String(e$1));
26448
+ process.exit(1);
26449
+ } else {
26450
+ if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
26451
+ else M.error(String(e$1));
26452
+ process.exit(1);
26453
+ }
26392
26454
  }
26393
26455
  }
26394
26456
 
@@ -26398,6 +26460,8 @@ async function runCommand(commandFn, options) {
26398
26460
  * Wraps an async operation with automatic spinner management.
26399
26461
  * The spinner is automatically started, and stopped on both success and error.
26400
26462
  *
26463
+ * In JSON mode, the spinner is suppressed and the operation runs silently.
26464
+ *
26401
26465
  * @param startMessage - Message to show when spinner starts
26402
26466
  * @param operation - The async operation to execute. Receives an updateMessage function
26403
26467
  * to update the spinner text during long-running operations.
@@ -26433,6 +26497,10 @@ async function runCommand(commandFn, options) {
26433
26497
  * );
26434
26498
  */
26435
26499
  async function runTask(startMessage, operation, options) {
26500
+ if (isJsonMode()) {
26501
+ const noopUpdateMessage = () => {};
26502
+ return await operation(noopUpdateMessage);
26503
+ }
26436
26504
  const s = Y();
26437
26505
  s.start(startMessage);
26438
26506
  const updateMessage = (message) => s.message(message);
@@ -26459,6 +26527,10 @@ const onPromptCancel = () => {
26459
26527
 
26460
26528
  //#endregion
26461
26529
  //#region src/cli/commands/auth/login.ts
26530
+ /**
26531
+ * Login command does not support --json output.
26532
+ * It requires interactive browser authentication via device code flow.
26533
+ */
26462
26534
  async function generateAndDisplayDeviceCode() {
26463
26535
  const deviceCodeResponse = await runTask("Generating device code...", async () => {
26464
26536
  return await generateDeviceCode();
@@ -26520,7 +26592,13 @@ const loginCommand = new Command("login").description("Authenticate with Base44"
26520
26592
  //#region src/cli/commands/auth/whoami.ts
26521
26593
  async function whoami() {
26522
26594
  const auth = await readAuth();
26523
- return { outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}` };
26595
+ return {
26596
+ outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}`,
26597
+ data: {
26598
+ email: auth.email,
26599
+ name: auth.name
26600
+ }
26601
+ };
26524
26602
  }
26525
26603
  const whoamiCommand = new Command("whoami").description("Display current authenticated user").action(async () => {
26526
26604
  await runCommand(whoami, { requireAuth: true });
@@ -26528,6 +26606,10 @@ const whoamiCommand = new Command("whoami").description("Display current authent
26528
26606
 
26529
26607
  //#endregion
26530
26608
  //#region src/cli/commands/auth/logout.ts
26609
+ /**
26610
+ * Logout command does not support --json output.
26611
+ * It is a user-facing auth command that is rarely scripted.
26612
+ */
26531
26613
  async function logout() {
26532
26614
  await deleteAuth();
26533
26615
  return { outroMessage: "Logged out successfully" };
@@ -31523,18 +31605,31 @@ async function createArchive(pathToArchive, targetArchivePath) {
31523
31605
  //#region src/cli/commands/entities/push.ts
31524
31606
  async function pushEntitiesAction() {
31525
31607
  const { entities } = await readProjectConfig();
31526
- if (entities.length === 0) return { outroMessage: "No entities found in project" };
31527
- M.info(`Found ${entities.length} entities to push`);
31608
+ if (entities.length === 0) return {
31609
+ outroMessage: "No entities found in project",
31610
+ data: {
31611
+ created: [],
31612
+ updated: [],
31613
+ deleted: []
31614
+ }
31615
+ };
31616
+ if (!isJsonMode()) M.info(`Found ${entities.length} entities to push`);
31528
31617
  const result = await runTask("Pushing entities to Base44", async () => {
31529
31618
  return await pushEntities(entities);
31530
31619
  }, {
31531
31620
  successMessage: "Entities pushed successfully",
31532
31621
  errorMessage: "Failed to push entities"
31533
31622
  });
31534
- if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31535
- if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31536
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31537
- return {};
31623
+ if (!isJsonMode()) {
31624
+ if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31625
+ if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31626
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31627
+ }
31628
+ return { data: {
31629
+ created: result.created,
31630
+ updated: result.updated,
31631
+ deleted: result.deleted
31632
+ } };
31538
31633
  }
31539
31634
  const entitiesPushCommand = new Command("entities").description("Manage project entities").addCommand(new Command("push").description("Push local entities to Base44").action(async () => {
31540
31635
  await runCommand(pushEntitiesAction, { requireAuth: true });
@@ -31544,21 +31639,32 @@ const entitiesPushCommand = new Command("entities").description("Manage project
31544
31639
  //#region src/cli/commands/functions/deploy.ts
31545
31640
  async function deployFunctionsAction() {
31546
31641
  const { functions } = await readProjectConfig();
31547
- if (functions.length === 0) return { outroMessage: "No functions found. Create functions in the 'functions' directory." };
31548
- M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31642
+ if (functions.length === 0) return {
31643
+ outroMessage: "No functions found. Create functions in the 'functions' directory.",
31644
+ data: {
31645
+ deployed: [],
31646
+ deleted: []
31647
+ }
31648
+ };
31649
+ if (!isJsonMode()) M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31549
31650
  const result = await runTask("Deploying functions to Base44", async () => {
31550
31651
  return await pushFunctions(functions);
31551
31652
  }, {
31552
31653
  successMessage: "Functions deployed successfully",
31553
31654
  errorMessage: "Failed to deploy functions"
31554
31655
  });
31555
- if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31556
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31656
+ if (!isJsonMode()) {
31657
+ if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31658
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31659
+ }
31557
31660
  if (result.errors && result.errors.length > 0) {
31558
31661
  const errorMessages = result.errors.map((e$1) => `'${e$1.name}' function: ${e$1.message}`).join("\n");
31559
31662
  throw new Error(`Function deployment errors:\n${errorMessages}`);
31560
31663
  }
31561
- return {};
31664
+ return { data: {
31665
+ deployed: result.deployed,
31666
+ deleted: result.deleted
31667
+ } };
31562
31668
  }
31563
31669
  const functionsDeployCommand = new Command("functions").description("Manage project functions").addCommand(new Command("deploy").description("Deploy local functions to Base44").action(async () => {
31564
31670
  await runCommand(deployFunctionsAction, { requireAuth: true });
@@ -38238,18 +38344,10 @@ async function getDefaultTemplate() {
38238
38344
  if (!template) throw new Error(`Default template "${DEFAULT_TEMPLATE_ID}" not found`);
38239
38345
  return template;
38240
38346
  }
38241
- async function getTemplateById(templateId) {
38242
- const templates = await listTemplates();
38243
- const template = templates.find((t) => t.id === templateId);
38244
- if (!template) {
38245
- const validIds = templates.map((t) => t.id).join(", ");
38246
- throw new Error(`Template "${templateId}" not found. Available templates: ${validIds}`);
38247
- }
38248
- return template;
38249
- }
38250
38347
  function validateNonInteractiveFlags$1(command) {
38251
- const { name: name$1, path: path$17 } = command.opts();
38348
+ const { name: name$1, path: path$17, json } = command.optsWithGlobals();
38252
38349
  const providedCount = [name$1, path$17].filter(Boolean).length;
38350
+ if (json && providedCount < 2) command.error("JSON mode requires all flags: --name, --path");
38253
38351
  if (providedCount > 0 && providedCount < 2) command.error("Non-interactive mode requires all flags: --name, --path");
38254
38352
  }
38255
38353
  async function chooseCreate(options) {
@@ -38301,7 +38399,7 @@ async function createInteractive(options) {
38301
38399
  }
38302
38400
  async function createNonInteractive(options) {
38303
38401
  return await executeCreate({
38304
- template: options.template ? await getTemplateById(options.template) : await getDefaultTemplate(),
38402
+ template: await getDefaultTemplate(),
38305
38403
  name: options.name,
38306
38404
  description: options.description,
38307
38405
  projectPath: options.path,
@@ -38367,12 +38465,22 @@ async function executeCreate({ template, name: rawName, description, projectPath
38367
38465
  }
38368
38466
  }
38369
38467
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/preview`;
38370
- M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38371
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38372
- if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38373
- return { outroMessage: "Your project is set up and ready to use" };
38468
+ if (!isJsonMode()) {
38469
+ M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38470
+ M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38471
+ if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38472
+ }
38473
+ return {
38474
+ outroMessage: "Your project is set up and ready to use",
38475
+ data: {
38476
+ projectId,
38477
+ path: resolvedPath,
38478
+ dashboardUrl,
38479
+ ...finalAppUrl && { appUrl: finalAppUrl }
38480
+ }
38481
+ };
38374
38482
  }
38375
- const createCommand = new Command("create").description("Create a new Base44 project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-p, --path <path>", "Path where to create the project").option("-t, --template <id>", "Template ID (e.g., backend-only, backend-and-client)").option("--deploy", "Build and deploy the site").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38483
+ const createCommand = new Command("create").description("Create a new Base44 project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-p, --path <path>", "Path where to create the project").option("--deploy", "Build and deploy the site").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38376
38484
  await chooseCreate(options);
38377
38485
  });
38378
38486
 
@@ -38917,22 +39025,27 @@ var open_default = open;
38917
39025
 
38918
39026
  //#endregion
38919
39027
  //#region src/cli/commands/project/dashboard.ts
38920
- async function openDashboard() {
39028
+ async function openDashboard(options) {
38921
39029
  await loadProjectEnv();
38922
39030
  const projectId = getBase44ClientId();
38923
39031
  if (!projectId) throw new Error("App not configured. BASE44_CLIENT_ID environment variable is required. Set it in your .env.local file.");
38924
39032
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/workspace/overview`;
38925
- await open_default(dashboardUrl);
38926
- return { outroMessage: `Dashboard opened at ${dashboardUrl}` };
39033
+ const shouldOpen = !isJsonMode() && !options.noOpen;
39034
+ if (shouldOpen) await open_default(dashboardUrl);
39035
+ return {
39036
+ outroMessage: shouldOpen ? `Dashboard opened at ${dashboardUrl}` : `Dashboard URL: ${dashboardUrl}`,
39037
+ data: { dashboardUrl }
39038
+ };
38927
39039
  }
38928
- const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").action(async () => {
38929
- await runCommand(openDashboard, { requireAuth: true });
39040
+ const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").option("--no-open", "Print the URL without opening the browser").action(async (options) => {
39041
+ await runCommand(() => openDashboard(options), { requireAuth: true });
38930
39042
  });
38931
39043
 
38932
39044
  //#endregion
38933
39045
  //#region src/cli/commands/project/link.ts
38934
39046
  function validateNonInteractiveFlags(command) {
38935
- const { create: create$1, name: name$1 } = command.opts();
39047
+ const { create: create$1, name: name$1, json } = command.optsWithGlobals();
39048
+ if (json && (!create$1 || !name$1)) command.error("JSON mode requires flags: --create, --name");
38936
39049
  if (create$1 && !name$1) command.error("--name is required when using --create");
38937
39050
  }
38938
39051
  async function promptForProjectDetails() {
@@ -38981,8 +39094,14 @@ async function link(options) {
38981
39094
  });
38982
39095
  await writeEnvLocal(projectRoot.root, projectId);
38983
39096
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/workspace/overview`;
38984
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38985
- return { outroMessage: "Project linked" };
39097
+ if (!isJsonMode()) M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
39098
+ return {
39099
+ outroMessage: "Project linked",
39100
+ data: {
39101
+ projectId,
39102
+ dashboardUrl
39103
+ }
39104
+ };
38986
39105
  }
38987
39106
  const linkCommand = new Command("link").description("Link a local project to a Base44 project").option("-c, --create", "Create a new project (skip selection prompt)").option("-n, --name <name>", "Project name (required when --create is used)").option("-d, --description <description>", "Project description").hook("preAction", validateNonInteractiveFlags).action(async (options) => {
38988
39107
  await runCommand(() => link(options), { requireAuth: true });
@@ -38994,16 +39113,23 @@ async function deployAction(options) {
38994
39113
  const { project } = await readProjectConfig();
38995
39114
  if (!project.site?.outputDirectory) throw new Error("No site configuration found. Please add 'site.outputDirectory' to your config.jsonc");
38996
39115
  const outputDir = resolve(project.root, project.site.outputDirectory);
38997
- if (!options.yes) {
39116
+ if (!options.yes && !isJsonMode()) {
38998
39117
  const shouldDeploy = await ye({ message: `Deploy site from ${project.site.outputDirectory}?` });
38999
- if (pD(shouldDeploy) || !shouldDeploy) return { outroMessage: "Deployment cancelled" };
39118
+ if (pD(shouldDeploy) || !shouldDeploy) return {
39119
+ outroMessage: "Deployment cancelled",
39120
+ data: { cancelled: true }
39121
+ };
39000
39122
  }
39001
- return { outroMessage: `Visit your site at: ${(await runTask("Creating archive and deploying site...", async () => {
39123
+ const result = await runTask("Creating archive and deploying site...", async () => {
39002
39124
  return await deploySite(outputDir);
39003
39125
  }, {
39004
39126
  successMessage: "Site deployed successfully",
39005
39127
  errorMessage: "Deployment failed"
39006
- })).appUrl}` };
39128
+ });
39129
+ return {
39130
+ outroMessage: `Visit your site at: ${result.appUrl}`,
39131
+ data: { appUrl: result.appUrl }
39132
+ };
39007
39133
  }
39008
39134
  const siteDeployCommand = new Command("site").description("Manage site deployments").addCommand(new Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
39009
39135
  await runCommand(() => deployAction(options), { requireAuth: true });
@@ -39016,7 +39142,10 @@ var version = "0.0.13";
39016
39142
  //#endregion
39017
39143
  //#region src/cli/index.ts
39018
39144
  const program = new Command();
39019
- program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version);
39145
+ program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version).option("--json", "Output results as JSON (for scripting)");
39146
+ program.hook("preAction", (thisCommand) => {
39147
+ if (thisCommand.optsWithGlobals().json) setJsonMode(true);
39148
+ });
39020
39149
  program.configureHelp({ sortSubcommands: true });
39021
39150
  program.addCommand(loginCommand);
39022
39151
  program.addCommand(whoamiCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.13-pr.86.f208957",
3
+ "version": "0.0.13-pr.87.2565e16",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",