@base44-preview/cli 0.1.25-pr.647.62db7ea → 0.1.25-pr.649.02c0574

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
@@ -236708,8 +236708,74 @@ async function getSiteUrl() {
236708
236708
  return result.data.url;
236709
236709
  }
236710
236710
  // src/core/project/config.ts
236711
+ import { existsSync } from "node:fs";
236711
236712
  import { dirname as dirname10, join as join12 } from "node:path";
236712
236713
 
236714
+ // src/core/project/fallback.ts
236715
+ var DEFAULT_SITE = Object.freeze({
236716
+ installCommand: "npm install",
236717
+ buildCommand: "npm run build",
236718
+ serveCommand: "npm run dev",
236719
+ outputDirectory: "./dist"
236720
+ });
236721
+ var PLACEHOLDER_APP_NAME = "base44-app";
236722
+ var DEFAULTABLE_FIELDS = new Set(["name", "description", "site"]);
236723
+ var warningHandler = () => {};
236724
+ var warned = new Set;
236725
+ function setConfigWarningHandler(handler) {
236726
+ warningHandler = handler;
236727
+ }
236728
+ function warnConfigFallback(message) {
236729
+ if (warned.has(message)) {
236730
+ return;
236731
+ }
236732
+ warned.add(message);
236733
+ warningHandler(message);
236734
+ }
236735
+ function defaultProjectConfig() {
236736
+ return ProjectConfigSchema.parse({
236737
+ name: PLACEHOLDER_APP_NAME,
236738
+ site: DEFAULT_SITE
236739
+ });
236740
+ }
236741
+ function onlyDefaultableFieldsInvalid(error) {
236742
+ return error.issues.every((issue) => issue.path.length > 0 && DEFAULTABLE_FIELDS.has(String(issue.path[0])));
236743
+ }
236744
+ function salvageProjectConfig(raw, error) {
236745
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
236746
+ return defaultProjectConfig();
236747
+ }
236748
+ const fixed = { ...raw };
236749
+ for (const issue of error.issues) {
236750
+ if (issue.path.length === 0) {
236751
+ return defaultProjectConfig();
236752
+ }
236753
+ const [key, field] = issue.path.map(String);
236754
+ if (key === "name") {
236755
+ fixed.name = PLACEHOLDER_APP_NAME;
236756
+ } else if (key === "site") {
236757
+ fixed.site = field !== undefined && isPlainObject2(fixed.site) ? withoutKey(fixed.site, field) : DEFAULT_SITE;
236758
+ } else {
236759
+ fixed[key] = undefined;
236760
+ }
236761
+ }
236762
+ const result = ProjectConfigSchema.safeParse(fixed);
236763
+ return result.success ? result.data : defaultProjectConfig();
236764
+ }
236765
+ function siteOrDefault(project) {
236766
+ if (project.site) {
236767
+ return project.site;
236768
+ }
236769
+ warnConfigFallback(`${project.configPath} has no 'site' block; using the default site commands.`);
236770
+ return DEFAULT_SITE;
236771
+ }
236772
+ function withoutKey(record, key) {
236773
+ return Object.fromEntries(Object.entries(record).filter(([k]) => k !== key));
236774
+ }
236775
+ function isPlainObject2(value) {
236776
+ return typeof value === "object" && value !== null && !Array.isArray(value);
236777
+ }
236778
+
236713
236779
  // src/core/project/plugins.ts
236714
236780
  import { createRequire as createRequire2 } from "node:module";
236715
236781
  import { dirname as dirname5, isAbsolute as isAbsolute2, join as join4, resolve } from "node:path";
@@ -239066,14 +239132,24 @@ async function openLogStream(filters) {
239066
239132
  return { kind: "stream", events: readStreamEvents(response.body) };
239067
239133
  }
239068
239134
  // src/core/project/config.ts
239135
+ var PROJECT_ROOT_NOT_FOUND = `Project root not found. Please ensure config.jsonc or config.json exists in the project directory or ${PROJECT_SUBDIR}/ subdirectory.`;
239136
+
239069
239137
  class ProjectConfigReader {
239070
239138
  pluginSourceByNamespace = new Map;
239071
239139
  async readProjectSettings(projectRoot) {
239072
239140
  const { root, configPath } = await this.findConfigOrThrow(projectRoot);
239073
- const project = await this.readConfigFile(configPath);
239141
+ const project = await this.readConfigFile(configPath, "safe");
239074
239142
  this.assertPluginProjectDoesNotLoadPlugins(project, configPath);
239075
239143
  return { ...project, root, configPath };
239076
239144
  }
239145
+ async readProjectSettingsOrDefaults(projectRoot) {
239146
+ const found = this.findConfig(projectRoot);
239147
+ if (!found) {
239148
+ return this.defaultSettingsOrThrow(projectRoot);
239149
+ }
239150
+ const project = await this.readConfigFile(found.configPath, "lenient");
239151
+ return { ...project, ...found };
239152
+ }
239077
239153
  async readProjectConfig(projectRoot) {
239078
239154
  const project = await this.readProjectSettings(projectRoot);
239079
239155
  const { configPath } = project;
@@ -239103,25 +239179,50 @@ class ProjectConfigReader {
239103
239179
  };
239104
239180
  }
239105
239181
  async findConfigOrThrow(projectRoot) {
239106
- let found;
239107
- if (projectRoot) {
239108
- const configPath = findConfigInDir(projectRoot);
239109
- found = configPath ? { root: projectRoot, configPath } : null;
239110
- } else {
239111
- found = findProjectRoot();
239112
- }
239182
+ const found = this.findConfig(projectRoot);
239113
239183
  if (!found) {
239114
- throw new ConfigNotFoundError(`Project root not found. Please ensure config.jsonc or config.json exists in the project directory or ${PROJECT_SUBDIR}/ subdirectory.`);
239184
+ throw new ConfigNotFoundError(PROJECT_ROOT_NOT_FOUND);
239115
239185
  }
239116
239186
  return found;
239117
239187
  }
239118
- async readConfigFile(configPath) {
239119
- const parsed = await readJsonFile(configPath);
239188
+ findConfig(projectRoot) {
239189
+ if (!projectRoot) {
239190
+ return findProjectRoot();
239191
+ }
239192
+ const configPath = findConfigInDir(projectRoot);
239193
+ return configPath ? { root: projectRoot, configPath } : null;
239194
+ }
239195
+ defaultSettingsOrThrow(projectRoot) {
239196
+ const root = projectRoot ?? process.cwd();
239197
+ if (!existsSync(join12(root, "package.json"))) {
239198
+ throw new ConfigNotFoundError(PROJECT_ROOT_NOT_FOUND);
239199
+ }
239200
+ warnConfigFallback(`No ${PROJECT_SUBDIR}/config.jsonc found in ${root}; using the default project config.`);
239201
+ const configPath = join12(root, PROJECT_SUBDIR, "config.jsonc");
239202
+ return { ...defaultProjectConfig(), root, configPath };
239203
+ }
239204
+ async readConfigFile(configPath, mode = "strict") {
239205
+ let parsed;
239206
+ try {
239207
+ parsed = await readJsonFile(configPath);
239208
+ } catch (error) {
239209
+ if (mode !== "lenient") {
239210
+ throw error;
239211
+ }
239212
+ warnConfigFallback(`${configPath} could not be read (${errorMessage(error)}); using the default project config.`);
239213
+ return defaultProjectConfig();
239214
+ }
239120
239215
  const result = ProjectConfigSchema.safeParse(parsed);
239121
- if (!result.success) {
239216
+ if (result.success) {
239217
+ return result.data;
239218
+ }
239219
+ const defaultable = mode === "lenient" || mode === "safe" && onlyDefaultableFieldsInvalid(result.error);
239220
+ if (!defaultable) {
239122
239221
  throw new SchemaValidationError("Invalid project configuration", result.error, configPath);
239123
239222
  }
239124
- return result.data;
239223
+ warnConfigFallback(`Invalid project configuration in ${configPath}; using defaults for the invalid fields:
239224
+ ${prettifyError(result.error)}`);
239225
+ return salvageProjectConfig(parsed, result.error);
239125
239226
  }
239126
239227
  async readProjectResources(configPath, project, includeActors = true) {
239127
239228
  const configDir = dirname10(configPath);
@@ -239254,13 +239355,20 @@ async function readProjectSettings(projectRoot) {
239254
239355
  const reader = new ProjectConfigReader;
239255
239356
  return await reader.readProjectSettings(projectRoot);
239256
239357
  }
239358
+ async function readProjectSettingsOrDefaults(projectRoot) {
239359
+ const reader = new ProjectConfigReader;
239360
+ return await reader.readProjectSettingsOrDefaults(projectRoot);
239361
+ }
239362
+ function errorMessage(error) {
239363
+ return error instanceof Error ? error.message : String(error);
239364
+ }
239257
239365
  // src/core/project/template.ts
239258
239366
  var import_ejs = __toESM(require_ejs(), 1);
239259
239367
  var import_front_matter2 = __toESM(require_front_matter(), 1);
239260
239368
  import { dirname as dirname11, join as join14 } from "node:path";
239261
239369
 
239262
239370
  // src/core/assets.ts
239263
- import { cpSync, existsSync } from "node:fs";
239371
+ import { cpSync, existsSync as existsSync2 } from "node:fs";
239264
239372
  import { homedir as homedir2 } from "node:os";
239265
239373
  import { join as join13 } from "node:path";
239266
239374
  // package.json
@@ -239386,9 +239494,9 @@ function getExecWrapperPath() {
239386
239494
  return join13(getBackendRuntimeDir(), "exec.ts");
239387
239495
  }
239388
239496
  function ensureNpmAssets(sourceDir) {
239389
- if (existsSync(ASSETS_DIR) && existsSync(getBackendRuntimeDir()))
239497
+ if (existsSync2(ASSETS_DIR) && existsSync2(getBackendRuntimeDir()))
239390
239498
  return;
239391
- if (!existsSync(sourceDir))
239499
+ if (!existsSync2(sourceDir))
239392
239500
  return;
239393
239501
  cpSync(sourceDir, ASSETS_DIR, { recursive: true });
239394
239502
  }
@@ -240227,7 +240335,7 @@ function buildAssetsConfig(assetsConfig, progress) {
240227
240335
  };
240228
240336
  }
240229
240337
  // ../../node_modules/is-plain-obj/index.js
240230
- function isPlainObject2(value) {
240338
+ function isPlainObject3(value) {
240231
240339
  if (typeof value !== "object" || value === null) {
240232
240340
  return false;
240233
240341
  }
@@ -240251,7 +240359,7 @@ var normalizeFileUrl = (file) => file instanceof URL ? fileURLToPath2(file) : fi
240251
240359
  // ../../node_modules/execa/lib/methods/parameters.js
240252
240360
  var normalizeParameters = (rawFile, rawArguments = [], rawOptions = {}) => {
240253
240361
  const filePath = safeNormalizeFileUrl(rawFile, "First argument");
240254
- const [commandArguments, options] = isPlainObject2(rawArguments) ? [[], rawArguments] : [rawArguments, rawOptions];
240362
+ const [commandArguments, options] = isPlainObject3(rawArguments) ? [[], rawArguments] : [rawArguments, rawOptions];
240255
240363
  if (!Array.isArray(commandArguments)) {
240256
240364
  throw new TypeError(`Second argument must be either an array of arguments or an options object: ${commandArguments}`);
240257
240365
  }
@@ -240263,7 +240371,7 @@ var normalizeParameters = (rawFile, rawArguments = [], rawOptions = {}) => {
240263
240371
  if (nullByteArgument !== undefined) {
240264
240372
  throw new TypeError(`Arguments cannot contain null bytes ("\\0"): ${nullByteArgument}`);
240265
240373
  }
240266
- if (!isPlainObject2(options)) {
240374
+ if (!isPlainObject3(options)) {
240267
240375
  throw new TypeError(`Last argument must be an options object: ${options}`);
240268
240376
  }
240269
240377
  return [filePath, normalizedArguments, options];
@@ -240400,7 +240508,7 @@ var parseExpression = (expression) => {
240400
240508
  if (typeOfExpression === "number") {
240401
240509
  return String(expression);
240402
240510
  }
240403
- if (isPlainObject2(expression) && (("stdout" in expression) || ("isMaxBuffer" in expression))) {
240511
+ if (isPlainObject3(expression) && (("stdout" in expression) || ("isMaxBuffer" in expression))) {
240404
240512
  return getSubprocessResult(expression);
240405
240513
  }
240406
240514
  if (expression instanceof ChildProcess || Object.prototype.toString.call(expression) === "[object Promise]") {
@@ -240448,7 +240556,7 @@ var normalizeFdSpecificOption = (options, optionName) => {
240448
240556
  return addDefaultValue(optionArray, optionName);
240449
240557
  };
240450
240558
  var getStdioLength = ({ stdio }) => Array.isArray(stdio) ? Math.max(stdio.length, STANDARD_STREAMS_ALIASES.length) : STANDARD_STREAMS_ALIASES.length;
240451
- var normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject2(optionValue) ? normalizeOptionObject(optionValue, optionArray, optionName) : optionArray.fill(optionValue);
240559
+ var normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject3(optionValue) ? normalizeOptionObject(optionValue, optionArray, optionName) : optionArray.fill(optionValue);
240452
240560
  var normalizeOptionObject = (optionValue, optionArray, optionName) => {
240453
240561
  for (const fdName of Object.keys(optionValue).sort(compareFdName)) {
240454
240562
  for (const fdNumber of parseFdName(fdName, optionName, optionArray)) {
@@ -243524,10 +243632,10 @@ var checkBooleanOption = (value, optionName) => {
243524
243632
  var isGenerator = (value) => isAsyncGenerator(value) || isSyncGenerator(value);
243525
243633
  var isAsyncGenerator = (value) => Object.prototype.toString.call(value) === "[object AsyncGeneratorFunction]";
243526
243634
  var isSyncGenerator = (value) => Object.prototype.toString.call(value) === "[object GeneratorFunction]";
243527
- var isTransformOptions = (value) => isPlainObject2(value) && (value.transform !== undefined || value.final !== undefined);
243635
+ var isTransformOptions = (value) => isPlainObject3(value) && (value.transform !== undefined || value.final !== undefined);
243528
243636
  var isUrl = (value) => Object.prototype.toString.call(value) === "[object URL]";
243529
243637
  var isRegularUrl = (value) => isUrl(value) && value.protocol !== "file:";
243530
- var isFilePathObject = (value) => isPlainObject2(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => FILE_PATH_KEYS.has(key)) && isFilePathString(value.file);
243638
+ var isFilePathObject = (value) => isPlainObject3(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => FILE_PATH_KEYS.has(key)) && isFilePathString(value.file);
243531
243639
  var FILE_PATH_KEYS = new Set(["file", "append"]);
243532
243640
  var isFilePathString = (file) => typeof file === "string";
243533
243641
  var isUnknownStdioString = (type, value) => type === "native" && typeof value === "string" && !KNOWN_STDIO_STRINGS.has(value);
@@ -243644,7 +243752,7 @@ var normalizeDuplex = ({
243644
243752
  };
243645
243753
  };
243646
243754
  var normalizeTransformStream = ({ stdioItem, stdioItem: { value }, index, newTransforms, direction }) => {
243647
- const { transform, objectMode } = isPlainObject2(value) ? value : { transform: value };
243755
+ const { transform, objectMode } = isPlainObject3(value) ? value : { transform: value };
243648
243756
  const { writableObjectMode, readableObjectMode } = getTransformObjectModes(objectMode, index, newTransforms, direction);
243649
243757
  return {
243650
243758
  ...stdioItem,
@@ -243658,7 +243766,7 @@ var normalizeGenerator = ({ stdioItem, stdioItem: { value }, index, newTransform
243658
243766
  binary: binaryOption = false,
243659
243767
  preserveNewlines = false,
243660
243768
  objectMode
243661
- } = isPlainObject2(value) ? value : { transform: value };
243769
+ } = isPlainObject3(value) ? value : { transform: value };
243662
243770
  const binary = binaryOption || BINARY_ENCODINGS.has(encoding);
243663
243771
  const { writableObjectMode, readableObjectMode } = getTransformObjectModes(objectMode, index, newTransforms, direction);
243664
243772
  return {
@@ -245594,7 +245702,7 @@ var unpipeOnSignalAbort = async (unpipeSignal, { sourceStream, mergedStream, fil
245594
245702
 
245595
245703
  // ../../node_modules/execa/lib/pipe/setup.js
245596
245704
  var pipeToSubprocess = (sourceInfo, ...pipeArguments) => {
245597
- if (isPlainObject2(pipeArguments[0])) {
245705
+ if (isPlainObject3(pipeArguments[0])) {
245598
245706
  return pipeToSubprocess.bind(undefined, {
245599
245707
  ...sourceInfo,
245600
245708
  boundOptions: { ...sourceInfo.boundOptions, ...pipeArguments[0] }
@@ -246613,7 +246721,7 @@ var mergeOptions = (boundOptions, options) => {
246613
246721
  return { ...boundOptions, ...newOptions };
246614
246722
  };
246615
246723
  var mergeOption = (optionName, boundOptionValue, optionValue) => {
246616
- if (DEEP_OPTIONS.has(optionName) && isPlainObject2(boundOptionValue) && isPlainObject2(optionValue)) {
246724
+ if (DEEP_OPTIONS.has(optionName) && isPlainObject3(boundOptionValue) && isPlainObject3(optionValue)) {
246617
246725
  return { ...boundOptionValue, ...optionValue };
246618
246726
  }
246619
246727
  return optionValue;
@@ -246636,7 +246744,7 @@ var createExeca = (mapArguments, boundOptions, deepOptions, setBoundExeca) => {
246636
246744
  return boundExeca;
246637
246745
  };
246638
246746
  var callBoundExeca = ({ mapArguments, deepOptions = {}, boundOptions = {}, setBoundExeca, createNested }, firstArgument, ...nextArguments) => {
246639
- if (isPlainObject2(firstArgument)) {
246747
+ if (isPlainObject3(firstArgument)) {
246640
246748
  return createNested(mapArguments, mergeOptions(boundOptions, firstArgument), setBoundExeca);
246641
246749
  }
246642
246750
  const { file, commandArguments, options, isSync } = parseArguments({
@@ -246839,37 +246947,19 @@ async function deployAll(projectData, options) {
246839
246947
  }
246840
246948
  // src/core/project/target.ts
246841
246949
  import { dirname as dirname13, join as join19, resolve as resolve6 } from "node:path";
246842
- var DEFAULT_BUILD_COMMAND = "npm run build";
246843
- var DEFAULT_OUTPUT_DIRECTORY = "dist";
246844
246950
  async function resolveBuildTarget(projectRoot, overrides = {}) {
246845
246951
  const project = await readSettingsIfPresent(projectRoot);
246846
246952
  const root = project?.root ?? projectRoot ?? process.cwd();
246953
+ const site = project ? siteOrDefault(project) : DEFAULT_SITE;
246847
246954
  return {
246848
246955
  root,
246849
246956
  configDir: project ? dirname13(project.configPath) : join19(root, PROJECT_SUBDIR),
246850
- buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
246851
- outputDir: outputDirectory(project, root, overrides.outputDir),
246957
+ buildCommand: site.buildCommand,
246958
+ outputDir: resolve6(root, overrides.outputDir ?? site.outputDirectory ?? DEFAULT_SITE.outputDirectory),
246852
246959
  entitiesDir: project?.entitiesDir ?? "entities",
246853
246960
  agentsDir: project?.agentsDir ?? "agents"
246854
246961
  };
246855
246962
  }
246856
- function outputDirectory(project, root, override) {
246857
- const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
246858
- return configured ? resolve6(root, configured) : null;
246859
- }
246860
- function requireOutputDir(target) {
246861
- if (target.outputDir === null) {
246862
- throw new ConfigNotFoundError("No site configuration found.", {
246863
- hints: [
246864
- {
246865
- message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
246866
- },
246867
- { message: `Or pass --output-dir <dir>, relative to ${target.root}` }
246868
- ]
246869
- });
246870
- }
246871
- return target.outputDir;
246872
- }
246873
246963
  async function readSettingsIfPresent(projectRoot) {
246874
246964
  try {
246875
246965
  return await readProjectSettings(projectRoot);
@@ -247398,6 +247488,7 @@ class Base44Command extends Command2 {
247398
247488
  }
247399
247489
  action(fn) {
247400
247490
  return super.action(async (...args) => {
247491
+ setConfigWarningHandler((message) => this.context.log.warn(message));
247401
247492
  const jsonMode = this.context.jsonMode;
247402
247493
  const quiet = this.context.isNonInteractive || jsonMode;
247403
247494
  if (!quiet) {
@@ -249655,16 +249746,7 @@ function getFunctionsCommand() {
249655
249746
  }
249656
249747
 
249657
249748
  // src/cli/commands/project/site-build.ts
249658
- async function runSiteBuild({ runTask }, { root, buildCommand, appId }) {
249659
- if (!buildCommand) {
249660
- throw new ConfigNotFoundError("No site build command found.", {
249661
- hints: [
249662
- {
249663
- message: `Add a 'site' block to your config.jsonc (e.g., "site": { "buildCommand": "npm run build" }). Inside one, buildCommand defaults to "npm run build".`
249664
- }
249665
- ]
249666
- });
249667
- }
249749
+ async function runSiteBuild({ runTask }, { root, buildCommand = DEFAULT_SITE.buildCommand, appId }) {
249668
249750
  await runTask("Building site...", () => execa({
249669
249751
  cwd: root,
249670
249752
  shell: true,
@@ -250851,7 +250933,7 @@ async function collectArtifacts(target) {
250851
250933
  const built = await resolveFullStackBuild(target.root);
250852
250934
  const siteWorker = built ? await describeSiteWorker(built) : null;
250853
250935
  return {
250854
- assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(requireOutputDir(target), {
250936
+ assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(target.outputDir, {
250855
250937
  entryFile: ENTRY2
250856
250938
  }),
250857
250939
  ...siteWorker ? { siteWorker } : {},
@@ -251455,15 +251537,6 @@ async function deployToDeploymentsApi(ctx, project, options) {
251455
251537
  }
251456
251538
  async function deployTarball({ runTask }, project) {
251457
251539
  const outputDir = siteOutputDir(project);
251458
- if (!outputDir) {
251459
- throw new ConfigNotFoundError("No site configuration found.", {
251460
- hints: [
251461
- {
251462
- message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
251463
- }
251464
- ]
251465
- });
251466
- }
251467
251540
  const { appUrl } = await runTask("Creating archive and deploying site...", async () => await deploySite(outputDir), {
251468
251541
  successMessage: "Site deployed successfully",
251469
251542
  errorMessage: "Deployment failed"
@@ -251471,8 +251544,8 @@ async function deployTarball({ runTask }, project) {
251471
251544
  return { outroMessage: `Visit your site at: ${appUrl}` };
251472
251545
  }
251473
251546
  function siteOutputDir(project) {
251474
- const outputDirectory = project.site?.outputDirectory;
251475
- return outputDirectory ? resolve15(project.root, outputDirectory) : null;
251547
+ const { outputDirectory = DEFAULT_SITE.outputDirectory } = siteOrDefault(project);
251548
+ return resolve15(project.root, outputDirectory);
251476
251549
  }
251477
251550
  function getSiteDeployCommand() {
251478
251551
  const command = new Base44Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").option("--build", "Build the site before deploying (skips the prompt)").option("--no-build", "Deploy without building (skips the prompt)");
@@ -251666,14 +251739,11 @@ function stopRunnerOnProcessSignals(runner) {
251666
251739
  var DEFAULT_SERVE_COMMAND = "npm run dev";
251667
251740
  async function siteDevAction(ctx, forwarded) {
251668
251741
  const { app } = ctx;
251669
- if (!app?.projectRoot) {
251742
+ if (!app) {
251670
251743
  throw new ConfigInvalidError("base44 site dev requires a linked local project. Run it from a project with base44/.app.jsonc.");
251671
251744
  }
251672
- const project = await readProjectSettings(app.projectRoot);
251673
- const site = project.site;
251674
- if (!site) {
251675
- throw new InvalidInputError(`This project has no 'site' block in base44/config.jsonc, so there is no frontend to serve. Add one naming its serveCommand; site dev falls back to "npm run dev".`);
251676
- }
251745
+ const project = await readProjectSettingsOrDefaults(app.projectRoot);
251746
+ const site = siteOrDefault(project);
251677
251747
  const serveCommand = site.serveCommand ?? DEFAULT_SERVE_COMMAND;
251678
251748
  const command = [serveCommand, ...forwarded].join(" ");
251679
251749
  const runner = createServeCommandRunner({
@@ -251694,17 +251764,8 @@ function getSiteDevCommand() {
251694
251764
  async function installAction({
251695
251765
  runTask
251696
251766
  }) {
251697
- const project = await readProjectSettings();
251698
- const installCommand = project.site?.installCommand;
251699
- if (!installCommand) {
251700
- throw new ConfigNotFoundError("No site install command found.", {
251701
- hints: [
251702
- {
251703
- message: `Add a 'site' block to your config.jsonc (e.g., "site": { "installCommand": "npm ci" }). Inside one, installCommand defaults to "npm install".`
251704
- }
251705
- ]
251706
- });
251707
- }
251767
+ const project = await readProjectSettingsOrDefaults();
251768
+ const { installCommand } = siteOrDefault(project);
251708
251769
  await runTask("Installing site dependencies...", () => execa({ cwd: project.root, shell: true })`${installCommand}`, {
251709
251770
  successMessage: "Dependencies installed",
251710
251771
  errorMessage: "Install failed"
@@ -256967,7 +257028,7 @@ function isBuiltin2(candidate, className) {
256967
257028
  function isEvent(candidate) {
256968
257029
  return !isUndefined(Event) && isInstanceOf(candidate, Event);
256969
257030
  }
256970
- function isPlainObject3(candidate) {
257031
+ function isPlainObject4(candidate) {
256971
257032
  return isBuiltin2(candidate, "Object");
256972
257033
  }
256973
257034
  function isInstanceOf(candidate, base) {
@@ -260103,7 +260164,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
260103
260164
  const personProperties = {};
260104
260165
  const groupProperties = {};
260105
260166
  for (const [key, value] of Object.entries(eventProperties))
260106
- if (isPlainObject3(value) && groups && key in groups) {
260167
+ if (isPlainObject4(value) && groups && key in groups) {
260107
260168
  const groupProps = {};
260108
260169
  for (const [groupKey, groupValue] of Object.entries(value))
260109
260170
  groupProps[String(groupKey)] = String(groupValue);
@@ -260580,4 +260641,4 @@ export {
260580
260641
  runCLI
260581
260642
  };
260582
260643
 
260583
- //# debugId=618459366066EF9064756E2164756E21
260644
+ //# debugId=F5BEAB54424CF0ED64756E2164756E21