@base44-preview/cli 0.1.16-pr.635.f70a612 → 0.1.17-pr.626.a210a49

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
@@ -31177,7 +31177,7 @@ function cleanDoc(doc) {
31177
31177
  return mapDoc(doc, (currentDoc) => cleanDocFn(currentDoc));
31178
31178
  }
31179
31179
  function replaceEndOfLine(doc, replacement = literalline) {
31180
- return mapDoc(doc, (currentDoc) => typeof currentDoc === "string" ? join28(replacement, currentDoc.split(`
31180
+ return mapDoc(doc, (currentDoc) => typeof currentDoc === "string" ? join30(replacement, currentDoc.split(`
31181
31181
  `)) : currentDoc);
31182
31182
  }
31183
31183
  function canBreakFn(doc) {
@@ -31257,7 +31257,7 @@ function indentIfBreak(contents, options) {
31257
31257
  negate: options.negate
31258
31258
  };
31259
31259
  }
31260
- function join28(separator, docs) {
31260
+ function join30(separator, docs) {
31261
31261
  assertDoc(separator);
31262
31262
  assertDocArray(docs);
31263
31263
  const parts = [];
@@ -31968,7 +31968,7 @@ var init_doc = __esm(() => {
31968
31968
  MODE_FLAT = Symbol("MODE_FLAT");
31969
31969
  DOC_FILL_PRINTED_LENGTH = Symbol("DOC_FILL_PRINTED_LENGTH");
31970
31970
  builders = {
31971
- join: join28,
31971
+ join: join30,
31972
31972
  line,
31973
31973
  softline,
31974
31974
  hardline,
@@ -119090,7 +119090,7 @@ import path52 from "path";
119090
119090
  import * as path42 from "path";
119091
119091
  import * as fs26 from "fs/promises";
119092
119092
  import * as path22 from "path";
119093
- import process23 from "process";
119093
+ import process22 from "process";
119094
119094
  import * as path32 from "path";
119095
119095
  import process32 from "process";
119096
119096
  import path92 from "path";
@@ -119622,7 +119622,7 @@ function partition2(array2, predicate) {
119622
119622
  return result;
119623
119623
  }
119624
119624
  async function findInDirectory(nameOrNames, { typeCheck, cwd, allowSymlinks = true, filter: filter2 }) {
119625
- const directory = toAbsolutePath(cwd) ?? process23.cwd();
119625
+ const directory = toAbsolutePath(cwd) ?? process22.cwd();
119626
119626
  const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
119627
119627
  for (const name of names) {
119628
119628
  const fileOrDirectory = path22.join(directory, name);
@@ -146002,10 +146002,10 @@ __export(exports_supports_color, {
146002
146002
  createSupportsColor: () => createSupportsColor2,
146003
146003
  default: () => supports_color_default2
146004
146004
  });
146005
- import process24 from "node:process";
146005
+ import process21 from "node:process";
146006
146006
  import os9 from "node:os";
146007
146007
  import tty4 from "node:tty";
146008
- function hasFlag2(flag, argv = globalThis.Deno ? globalThis.Deno.args : process24.argv) {
146008
+ function hasFlag2(flag, argv = globalThis.Deno ? globalThis.Deno.args : process21.argv) {
146009
146009
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
146010
146010
  const position = argv.indexOf(prefix + flag);
146011
146011
  const terminatorPosition = argv.indexOf("--");
@@ -146068,7 +146068,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
146068
146068
  if (env3.TERM === "dumb") {
146069
146069
  return min;
146070
146070
  }
146071
- if (process24.platform === "win32") {
146071
+ if (process21.platform === "win32") {
146072
146072
  const osRelease = os9.release().split(".");
146073
146073
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
146074
146074
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
@@ -146130,7 +146130,7 @@ function createSupportsColor2(stream, options = {}) {
146130
146130
  }
146131
146131
  var env3, flagForceColor2, supportsColor2, supports_color_default2;
146132
146132
  var init_supports_color = __esm(() => {
146133
- ({ env: env3 } = process24);
146133
+ ({ env: env3 } = process21);
146134
146134
  if (hasFlag2("no-color") || hasFlag2("no-colors") || hasFlag2("color=false") || hasFlag2("color=never")) {
146135
146135
  flagForceColor2 = 0;
146136
146136
  } else if (hasFlag2("color") || hasFlag2("colors") || hasFlag2("color=true") || hasFlag2("color=always")) {
@@ -228470,6 +228470,17 @@ class DependencyNotFoundError extends UserError {
228470
228470
  });
228471
228471
  }
228472
228472
  }
228473
+ var MAX_RESPONSE_TEXT_CHARS = 500;
228474
+ async function readResponseText(response) {
228475
+ try {
228476
+ const text = (await response.clone().text()).trim();
228477
+ if (!text)
228478
+ return;
228479
+ return text.length > MAX_RESPONSE_TEXT_CHARS ? `${text.slice(0, MAX_RESPONSE_TEXT_CHARS)}…` : text;
228480
+ } catch {
228481
+ return;
228482
+ }
228483
+ }
228473
228484
 
228474
228485
  class ApiError extends SystemError {
228475
228486
  code = "API_ERROR";
@@ -228505,7 +228516,9 @@ class ApiError extends SystemError {
228505
228516
  details = parseErrorDetails(parsedData.extra_data);
228506
228517
  }
228507
228518
  } catch {
228508
- message = error.message;
228519
+ const body = await readResponseText(error.response);
228520
+ responseBody = body;
228521
+ message = body ? `${error.message} — ${body}` : `${error.message} — empty body, content-type ${error.response.headers.get("content-type") ?? "absent"}`;
228509
228522
  }
228510
228523
  const statusCode = ApiError.normalizeStatusCode(error.response.status, responseBody);
228511
228524
  const requestBody = error.options.context?.__requestBody;
@@ -228657,6 +228670,20 @@ function isCLIError(error) {
228657
228670
  function isUserError(error) {
228658
228671
  return error instanceof UserError;
228659
228672
  }
228673
+ var STEP = Symbol.for("base44.commandStep");
228674
+ async function tagStep(step, run) {
228675
+ try {
228676
+ return await run();
228677
+ } catch (error) {
228678
+ if (error !== null && typeof error === "object" && !(STEP in error) && Object.isExtensible(error)) {
228679
+ Object.defineProperty(error, STEP, { value: step, enumerable: false });
228680
+ }
228681
+ throw error;
228682
+ }
228683
+ }
228684
+ function stepOf(error) {
228685
+ return error !== null && typeof error === "object" && STEP in error ? error[STEP] : undefined;
228686
+ }
228660
228687
 
228661
228688
  // src/core/utils/fs.ts
228662
228689
  async function pathExists(path) {
@@ -228783,7 +228810,7 @@ function normalizeBase44Env() {
228783
228810
  loadProjectEnvFiles();
228784
228811
 
228785
228812
  // src/cli/index.ts
228786
- import { dirname as dirname28, join as join37 } from "node:path";
228813
+ import { dirname as dirname29, join as join39 } from "node:path";
228787
228814
  import { fileURLToPath as fileURLToPath6 } from "node:url";
228788
228815
 
228789
228816
  // ../../node_modules/@clack/core/dist/index.mjs
@@ -230705,11 +230732,10 @@ var TemplatesConfigSchema = object({
230705
230732
  templates: array(TemplateSchema)
230706
230733
  });
230707
230734
  var SiteConfigSchema = object({
230708
- buildCommand: string2().optional().default("npm run build"),
230735
+ buildCommand: string2().default("npm run build"),
230709
230736
  serveCommand: string2().optional(),
230710
- outputDirectory: string2().optional().default("./dist"),
230711
- installCommand: string2().optional().default("npm install"),
230712
- devHostFlag: string2().optional().default("--host")
230737
+ outputDirectory: string2().optional(),
230738
+ installCommand: string2().default("npm install")
230713
230739
  });
230714
230740
  var PluginMetadataSchema = object({
230715
230741
  namespace: string2().min(1, "Plugin namespace cannot be empty").regex(/^[a-zA-Z0-9_-]+$/, "Plugin namespace can only contain letters, numbers, underscores, and dashes")
@@ -236546,10 +236572,12 @@ var CreateDeploymentResponseSchema = object({
236546
236572
  url: string2()
236547
236573
  }))
236548
236574
  })
236549
- ]).nullable().optional()
236575
+ ]).nullable().optional(),
236576
+ index_html_staged: boolean2().optional().default(false)
236550
236577
  }).transform((data) => ({
236551
236578
  deploymentId: data.deployment_id,
236552
236579
  sessionId: data.session_id,
236580
+ indexHtmlStaged: data.index_html_staged,
236553
236581
  assetUploads: data.asset_uploads == null ? null : data.asset_uploads.type === "cf" ? data.asset_uploads : {
236554
236582
  type: "s3",
236555
236583
  uploads: data.asset_uploads.uploads.map((upload) => ({
@@ -239237,7 +239265,7 @@ import { join as join13 } from "node:path";
239237
239265
  // package.json
239238
239266
  var package_default = {
239239
239267
  name: "base44",
239240
- version: "0.1.16",
239268
+ version: "0.1.17",
239241
239269
  description: "Base44 CLI - Unified interface for managing Base44 applications",
239242
239270
  type: "module",
239243
239271
  bin: {
@@ -239512,9 +239540,9 @@ async function createDeployment(request) {
239512
239540
  }
239513
239541
  async function finalizeDeployment(deploymentId, sessionId, payload) {
239514
239542
  const formData = new FormData;
239515
- if ("indexHtml" in payload) {
239543
+ if (payload.kind === "static-inline") {
239516
239544
  formData.append("index.html", new File([payload.indexHtml], "index.html", { type: "text/html" }));
239517
- } else {
239545
+ } else if (payload.kind === "worker") {
239518
239546
  formData.append("payload", JSON.stringify({ completion_jwt: payload.completionJwt }));
239519
239547
  for (const module of payload.modules) {
239520
239548
  const content = await readFile(module.absolutePath);
@@ -239591,91 +239619,8 @@ async function createArchive(pathToArchive, targetArchivePath) {
239591
239619
  import { readFile as readFile3 } from "node:fs/promises";
239592
239620
  import { join as join18 } from "node:path";
239593
239621
 
239594
- // src/core/site/manifest.ts
239595
- import { createHash } from "node:crypto";
239596
- import { createReadStream } from "node:fs";
239597
- import { stat } from "node:fs/promises";
239598
- import { basename as basename5, extname, join as join16 } from "node:path";
239599
- var MAX_ASSET_COUNT = 1e5;
239600
- var ASSETS_IGNORE_FILE = ".assetsignore";
239601
- var ALWAYS_IGNORED = new Set([
239602
- ASSETS_IGNORE_FILE,
239603
- "wrangler.json",
239604
- ".dev.vars"
239605
- ]);
239606
- var MIME_TYPES = {
239607
- ".html": "text/html",
239608
- ".htm": "text/html",
239609
- ".css": "text/css",
239610
- ".js": "text/javascript",
239611
- ".mjs": "text/javascript",
239612
- ".json": "application/json",
239613
- ".map": "application/json",
239614
- ".txt": "text/plain",
239615
- ".xml": "application/xml",
239616
- ".svg": "image/svg+xml",
239617
- ".png": "image/png",
239618
- ".jpg": "image/jpeg",
239619
- ".jpeg": "image/jpeg",
239620
- ".gif": "image/gif",
239621
- ".webp": "image/webp",
239622
- ".avif": "image/avif",
239623
- ".ico": "image/x-icon",
239624
- ".woff": "font/woff",
239625
- ".woff2": "font/woff2",
239626
- ".ttf": "font/ttf",
239627
- ".otf": "font/otf",
239628
- ".eot": "application/vnd.ms-fontobject",
239629
- ".mp3": "audio/mpeg",
239630
- ".mp4": "video/mp4",
239631
- ".webm": "video/webm",
239632
- ".pdf": "application/pdf",
239633
- ".wasm": "application/wasm",
239634
- ".webmanifest": "application/manifest+json"
239635
- };
239636
- function getAssetContentType(filePath) {
239637
- return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
239638
- }
239639
- async function hashAssetFile(appId, absolutePath) {
239640
- const hash = createHash("sha256").update(Buffer.from(appId, "utf8"));
239641
- for await (const chunk of createReadStream(absolutePath)) {
239642
- hash.update(chunk);
239643
- }
239644
- return hash.digest("hex").slice(0, 32);
239645
- }
239646
- async function buildAssetManifest(assetsDir, appId) {
239647
- const manifest = {};
239648
- const filesByHash = new Map;
239649
- const found = await globby("**/*", {
239650
- cwd: assetsDir,
239651
- dot: true,
239652
- onlyFiles: true,
239653
- followSymbolicLinks: false,
239654
- ignoreFiles: [ASSETS_IGNORE_FILE]
239655
- });
239656
- const relativeFilePaths = found.filter((path) => !ALWAYS_IGNORED.has(basename5(path)));
239657
- if (relativeFilePaths.length > MAX_ASSET_COUNT) {
239658
- throw new InvalidInputError(`Too many static assets: found ${relativeFilePaths.length}, the limit is ${MAX_ASSET_COUNT} files.`);
239659
- }
239660
- for (const relativePath of relativeFilePaths.sort()) {
239661
- const absolutePath = join16(assetsDir, ...relativePath.split("/"));
239662
- const { size } = await stat(absolutePath);
239663
- const hash = await hashAssetFile(appId, absolutePath);
239664
- manifest[`/${relativePath}`] = { hash, size };
239665
- if (!filesByHash.has(hash)) {
239666
- filesByHash.set(hash, {
239667
- absolutePath,
239668
- hash,
239669
- size,
239670
- contentType: getAssetContentType(absolutePath)
239671
- });
239672
- }
239673
- }
239674
- return { manifest, filesByHash };
239675
- }
239676
-
239677
239622
  // src/core/site/modules.ts
239678
- import { stat as stat2 } from "node:fs/promises";
239623
+ import { stat } from "node:fs/promises";
239679
239624
  import { relative as relative5, resolve as resolve3, sep } from "node:path";
239680
239625
  var MAX_TOTAL_MODULE_BYTES = 40 * 1024 * 1024;
239681
239626
  var MODULE_IGNORE = ["wrangler.json", ".dev.vars"];
@@ -239750,7 +239695,7 @@ async function collectModules(config) {
239750
239695
  const modules = [...modulesByName.values()];
239751
239696
  let totalBytes = 0;
239752
239697
  for (const module of modules) {
239753
- module.size = (await stat2(module.absolutePath)).size;
239698
+ module.size = (await stat(module.absolutePath)).size;
239754
239699
  totalBytes += module.size;
239755
239700
  }
239756
239701
  if (totalBytes > MAX_TOTAL_MODULE_BYTES) {
@@ -239769,8 +239714,104 @@ function addSourcemap(modulesByName, configDir, name) {
239769
239714
  });
239770
239715
  }
239771
239716
 
239772
- // src/core/site/upload.ts
239773
- import { readFile as readFile2 } from "node:fs/promises";
239717
+ // src/core/site/wrangler-config.ts
239718
+ import { dirname as dirname12, join as join16, resolve as resolve4 } from "node:path";
239719
+ var WRANGLER_REDIRECT_PATH = join16(".wrangler", "deploy", "config.json");
239720
+ var RedirectConfigSchema = looseObject({
239721
+ configPath: string2().min(1)
239722
+ });
239723
+ var WranglerConfigSchema = looseObject({
239724
+ main: string2().min(1, "wrangler config is missing a 'main' entry module"),
239725
+ no_bundle: boolean2().optional(),
239726
+ rules: array(looseObject({ type: string2(), globs: array(string2()) })).optional(),
239727
+ assets: looseObject({
239728
+ directory: string2().optional(),
239729
+ html_handling: string2().optional(),
239730
+ not_found_handling: string2().optional(),
239731
+ run_worker_first: union([boolean2(), array(string2())]).optional(),
239732
+ headers: string2().optional(),
239733
+ redirects: string2().optional()
239734
+ }).optional(),
239735
+ compatibility_date: string2().optional(),
239736
+ compatibility_flags: array(string2()).optional(),
239737
+ vars: record(string2(), unknown()).optional(),
239738
+ upload_source_maps: boolean2().optional()
239739
+ });
239740
+ async function detectFullStackArtifact(projectRoot) {
239741
+ const redirectPath = join16(projectRoot, WRANGLER_REDIRECT_PATH);
239742
+ return await pathExists(redirectPath) ? redirectPath : null;
239743
+ }
239744
+ async function resolveWranglerConfig(redirectPath) {
239745
+ const configPath = await resolveRedirectedConfigPath(redirectPath);
239746
+ const parsed = await readJsonFile(configPath);
239747
+ const result = WranglerConfigSchema.safeParse(parsed);
239748
+ if (!result.success) {
239749
+ throw new ConfigInvalidError(`Invalid wrangler config: ${prettifyError(result.error)}`, configPath);
239750
+ }
239751
+ const config = result.data;
239752
+ if (config.no_bundle !== true) {
239753
+ throw new InvalidInputError("This framework's output requires bundling; not yet supported. Base44 only deploys pre-bundled Workers output (no_bundle: true).");
239754
+ }
239755
+ const configDir = dirname12(configPath);
239756
+ const assetsDirectory = config.assets?.directory ? resolve4(configDir, config.assets.directory) : null;
239757
+ return {
239758
+ configPath,
239759
+ configDir,
239760
+ main: config.main,
239761
+ assetsDirectory,
239762
+ assetsConfig: config.assets ? toResolvedAssetsConfig(config.assets) : null,
239763
+ compatibilityDate: config.compatibility_date ?? null,
239764
+ compatibilityFlags: config.compatibility_flags ?? [],
239765
+ rules: (config.rules ?? []).map((rule) => ({
239766
+ type: rule.type,
239767
+ globs: rule.globs
239768
+ })),
239769
+ uploadSourceMaps: config.upload_source_maps ?? false
239770
+ };
239771
+ }
239772
+ async function resolveRedirectedConfigPath(redirectPath) {
239773
+ const parsed = await readJsonFile(redirectPath);
239774
+ const result = RedirectConfigSchema.safeParse(parsed);
239775
+ if (!result.success) {
239776
+ throw new ConfigInvalidError(`Invalid deploy redirect file: ${prettifyError(result.error)}`, redirectPath);
239777
+ }
239778
+ const configPath = resolve4(dirname12(redirectPath), result.data.configPath);
239779
+ if (!await pathExists(configPath)) {
239780
+ throw new ConfigInvalidError(`Wrangler config referenced by ${redirectPath} does not exist: ${configPath}`, redirectPath, {
239781
+ hints: [{ message: "Rebuild the project to regenerate the artifact" }]
239782
+ });
239783
+ }
239784
+ return configPath;
239785
+ }
239786
+ function toResolvedAssetsConfig(assets) {
239787
+ return {
239788
+ htmlHandling: assets.html_handling,
239789
+ notFoundHandling: assets.not_found_handling,
239790
+ runWorkerFirst: assets.run_worker_first,
239791
+ headers: assets.headers,
239792
+ redirects: assets.redirects
239793
+ };
239794
+ }
239795
+
239796
+ // src/core/site/full-stack.ts
239797
+ async function resolveFullStackBuild(projectRoot) {
239798
+ const redirectPath = await detectFullStackArtifact(projectRoot);
239799
+ if (!redirectPath) {
239800
+ return null;
239801
+ }
239802
+ const config = await resolveWranglerConfig(redirectPath);
239803
+ return {
239804
+ config,
239805
+ modules: await collectModules(config),
239806
+ assetsDir: config.assetsDirectory && await pathExists(config.assetsDirectory) ? config.assetsDirectory : null
239807
+ };
239808
+ }
239809
+
239810
+ // src/core/site/manifest.ts
239811
+ import { createHash } from "node:crypto";
239812
+ import { createReadStream } from "node:fs";
239813
+ import { stat as stat2 } from "node:fs/promises";
239814
+ import { basename as basename5, extname, join as join17 } from "node:path";
239774
239815
 
239775
239816
  // ../../node_modules/p-map/index.js
239776
239817
  async function pMap(iterable, mapper, {
@@ -239896,7 +239937,99 @@ async function pMap(iterable, mapper, {
239896
239937
  }
239897
239938
  var pMapSkip = Symbol("skip");
239898
239939
 
239940
+ // src/core/site/manifest.ts
239941
+ var MAX_ASSET_COUNT = 1e5;
239942
+ var ASSETS_IGNORE_FILE = ".assetsignore";
239943
+ var ALWAYS_IGNORED = new Set([
239944
+ ASSETS_IGNORE_FILE,
239945
+ "wrangler.json",
239946
+ ".dev.vars"
239947
+ ]);
239948
+ var MIME_TYPES = {
239949
+ ".html": "text/html",
239950
+ ".htm": "text/html",
239951
+ ".css": "text/css",
239952
+ ".js": "text/javascript",
239953
+ ".mjs": "text/javascript",
239954
+ ".json": "application/json",
239955
+ ".map": "application/json",
239956
+ ".txt": "text/plain",
239957
+ ".xml": "application/xml",
239958
+ ".svg": "image/svg+xml",
239959
+ ".png": "image/png",
239960
+ ".jpg": "image/jpeg",
239961
+ ".jpeg": "image/jpeg",
239962
+ ".gif": "image/gif",
239963
+ ".webp": "image/webp",
239964
+ ".avif": "image/avif",
239965
+ ".ico": "image/x-icon",
239966
+ ".woff": "font/woff",
239967
+ ".woff2": "font/woff2",
239968
+ ".ttf": "font/ttf",
239969
+ ".otf": "font/otf",
239970
+ ".eot": "application/vnd.ms-fontobject",
239971
+ ".mp3": "audio/mpeg",
239972
+ ".mp4": "video/mp4",
239973
+ ".webm": "video/webm",
239974
+ ".pdf": "application/pdf",
239975
+ ".wasm": "application/wasm",
239976
+ ".webmanifest": "application/manifest+json"
239977
+ };
239978
+ function getAssetContentType(filePath) {
239979
+ return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
239980
+ }
239981
+ async function walkBuildOutput(outputDir) {
239982
+ const found = await globby("**/*", {
239983
+ cwd: outputDir,
239984
+ dot: true,
239985
+ onlyFiles: true,
239986
+ followSymbolicLinks: false,
239987
+ ignoreFiles: [ASSETS_IGNORE_FILE]
239988
+ });
239989
+ return found.filter((path) => !ALWAYS_IGNORED.has(basename5(path))).sort();
239990
+ }
239991
+ var STAT_CONCURRENCY = 32;
239992
+ async function describeBuildOutput(outputDir) {
239993
+ const relativePaths = await walkBuildOutput(outputDir);
239994
+ return await pMap(relativePaths, async (path) => {
239995
+ const absolutePath = join17(outputDir, ...path.split("/"));
239996
+ return { path, absolutePath, size: (await stat2(absolutePath)).size };
239997
+ }, { concurrency: STAT_CONCURRENCY });
239998
+ }
239999
+ async function hashFileInto(hash, absolutePath) {
240000
+ for await (const chunk of createReadStream(absolutePath)) {
240001
+ hash.update(chunk);
240002
+ }
240003
+ return hash;
240004
+ }
240005
+ async function hashAssetFile(appId, absolutePath) {
240006
+ const hash = await hashFileInto(createHash("sha256").update(Buffer.from(appId, "utf8")), absolutePath);
240007
+ return hash.digest("hex").slice(0, 32);
240008
+ }
240009
+ async function buildAssetManifest(assetsDir, appId) {
240010
+ const manifest = {};
240011
+ const filesByHash = new Map;
240012
+ const files = await describeBuildOutput(assetsDir);
240013
+ if (files.length > MAX_ASSET_COUNT) {
240014
+ throw new InvalidInputError(`Too many static assets: found ${files.length}, the limit is ${MAX_ASSET_COUNT} files.`);
240015
+ }
240016
+ for (const { path: relativePath, absolutePath, size } of files) {
240017
+ const hash = await hashAssetFile(appId, absolutePath);
240018
+ manifest[`/${relativePath}`] = { hash, size };
240019
+ if (!filesByHash.has(hash)) {
240020
+ filesByHash.set(hash, {
240021
+ absolutePath,
240022
+ hash,
240023
+ size,
240024
+ contentType: getAssetContentType(absolutePath)
240025
+ });
240026
+ }
240027
+ }
240028
+ return { manifest, filesByHash };
240029
+ }
240030
+
239899
240031
  // src/core/site/upload.ts
240032
+ import { readFile as readFile2 } from "node:fs/promises";
239900
240033
  var DEFAULT_UPLOAD_CONCURRENCY = 3;
239901
240034
  var MAX_UPLOAD_CONCURRENCY = 50;
239902
240035
  var MAX_UPLOAD_ATTEMPTS = 3;
@@ -239995,11 +240128,17 @@ async function uploadPresignedAsset(upload, assets) {
239995
240128
  if (!file) {
239996
240129
  throw new InternalError(`Server requested upload of unknown asset path: ${upload.path}`);
239997
240130
  }
239998
- const content = await readFile2(file.absolutePath);
240131
+ await putPresigned(upload, file.absolutePath);
240132
+ }
240133
+ async function putPresigned(upload, absolutePath) {
240134
+ const content = await readFile2(absolutePath);
239999
240135
  try {
240000
240136
  await distribution_default.put(upload.url, {
240001
240137
  body: new Uint8Array(content),
240002
- headers: { "Content-Type": upload.contentType },
240138
+ headers: {
240139
+ "Content-Type": upload.contentType,
240140
+ ...upload.checksumSha256 ? { "x-amz-checksum-sha256": upload.checksumSha256 } : {}
240141
+ },
240003
240142
  timeout: 120000,
240004
240143
  retry: UPLOAD_RETRY
240005
240144
  });
@@ -240008,85 +240147,6 @@ async function uploadPresignedAsset(upload, assets) {
240008
240147
  }
240009
240148
  }
240010
240149
 
240011
- // src/core/site/wrangler-config.ts
240012
- import { dirname as dirname12, join as join17, resolve as resolve4 } from "node:path";
240013
- var WRANGLER_REDIRECT_PATH = join17(".wrangler", "deploy", "config.json");
240014
- var RedirectConfigSchema = looseObject({
240015
- configPath: string2().min(1)
240016
- });
240017
- var WranglerConfigSchema = looseObject({
240018
- main: string2().min(1, "wrangler config is missing a 'main' entry module"),
240019
- no_bundle: boolean2().optional(),
240020
- rules: array(looseObject({ type: string2(), globs: array(string2()) })).optional(),
240021
- assets: looseObject({
240022
- directory: string2().optional(),
240023
- html_handling: string2().optional(),
240024
- not_found_handling: string2().optional(),
240025
- run_worker_first: union([boolean2(), array(string2())]).optional(),
240026
- headers: string2().optional(),
240027
- redirects: string2().optional()
240028
- }).optional(),
240029
- compatibility_date: string2().optional(),
240030
- compatibility_flags: array(string2()).optional(),
240031
- vars: record(string2(), unknown()).optional(),
240032
- upload_source_maps: boolean2().optional()
240033
- });
240034
- async function detectFullStackArtifact(projectRoot) {
240035
- const redirectPath = join17(projectRoot, WRANGLER_REDIRECT_PATH);
240036
- return await pathExists(redirectPath) ? redirectPath : null;
240037
- }
240038
- async function resolveWranglerConfig(redirectPath) {
240039
- const configPath = await resolveRedirectedConfigPath(redirectPath);
240040
- const parsed = await readJsonFile(configPath);
240041
- const result = WranglerConfigSchema.safeParse(parsed);
240042
- if (!result.success) {
240043
- throw new ConfigInvalidError(`Invalid wrangler config: ${prettifyError(result.error)}`, configPath);
240044
- }
240045
- const config = result.data;
240046
- if (config.no_bundle !== true) {
240047
- throw new InvalidInputError("This framework's output requires bundling; not yet supported. Base44 only deploys pre-bundled Workers output (no_bundle: true).");
240048
- }
240049
- const configDir = dirname12(configPath);
240050
- const assetsDirectory = config.assets?.directory ? resolve4(configDir, config.assets.directory) : null;
240051
- return {
240052
- configPath,
240053
- configDir,
240054
- main: config.main,
240055
- assetsDirectory,
240056
- assetsConfig: config.assets ? toResolvedAssetsConfig(config.assets) : null,
240057
- compatibilityDate: config.compatibility_date ?? null,
240058
- compatibilityFlags: config.compatibility_flags ?? [],
240059
- rules: (config.rules ?? []).map((rule) => ({
240060
- type: rule.type,
240061
- globs: rule.globs
240062
- })),
240063
- uploadSourceMaps: config.upload_source_maps ?? false
240064
- };
240065
- }
240066
- async function resolveRedirectedConfigPath(redirectPath) {
240067
- const parsed = await readJsonFile(redirectPath);
240068
- const result = RedirectConfigSchema.safeParse(parsed);
240069
- if (!result.success) {
240070
- throw new ConfigInvalidError(`Invalid deploy redirect file: ${prettifyError(result.error)}`, redirectPath);
240071
- }
240072
- const configPath = resolve4(dirname12(redirectPath), result.data.configPath);
240073
- if (!await pathExists(configPath)) {
240074
- throw new ConfigInvalidError(`Wrangler config referenced by ${redirectPath} does not exist: ${configPath}`, redirectPath, {
240075
- hints: [{ message: "Rebuild the project to regenerate the artifact" }]
240076
- });
240077
- }
240078
- return configPath;
240079
- }
240080
- function toResolvedAssetsConfig(assets) {
240081
- return {
240082
- htmlHandling: assets.html_handling,
240083
- notFoundHandling: assets.not_found_handling,
240084
- runWorkerFirst: assets.run_worker_first,
240085
- headers: assets.headers,
240086
- redirects: assets.redirects
240087
- };
240088
- }
240089
-
240090
240150
  // src/core/site/deployment.ts
240091
240151
  var NO_ASSETS = { manifest: {}, filesByHash: new Map };
240092
240152
  var DEPLOYMENTS_API_ENV = "BASE44_DEPLOYMENTS_API";
@@ -240099,26 +240159,28 @@ async function deployToDeployments(options) {
240099
240159
  const worker = await resolveWorkerBuild(projectRoot, progress);
240100
240160
  const assetsDir = worker ? worker.assetsDir : outputDir;
240101
240161
  const assets = assetsDir ? await buildAssetManifest(assetsDir, getAppContext().id) : NO_ASSETS;
240102
- const completion = worker ? { modules: worker.modules } : { indexHtml: await readIndexHtml(assetsDir, assets) };
240162
+ if (!worker) {
240163
+ requireStaticEntryPoint(assetsDir, assets);
240164
+ }
240103
240165
  const created = await createDeployment({
240104
240166
  git_hash: gitHash,
240105
240167
  config: worker?.config,
240106
240168
  asset_manifest: assets.manifest
240107
240169
  });
240108
240170
  const completionJwt = await uploadDeploymentAssets(created.assetUploads, assets, { concurrency, progress });
240109
- if ("modules" in completion) {
240171
+ const completion = worker ? { kind: "worker", modules: worker.modules, completionJwt } : await resolveStaticCompletion(assetsDir, assets, created.indexHtmlStaged);
240172
+ if (completion.kind === "worker") {
240110
240173
  progress?.onWorker?.({ moduleCount: completion.modules.length });
240111
240174
  }
240112
- const finalized = await finalizeDeployment(created.deploymentId, created.sessionId, "modules" in completion ? { ...completion, completionJwt } : completion);
240175
+ const finalized = await finalizeDeployment(created.deploymentId, created.sessionId, completion);
240113
240176
  return { deploymentId: finalized.deploymentId, gitHash };
240114
240177
  }
240115
240178
  async function resolveWorkerBuild(projectRoot, progress) {
240116
- const redirectPath = await detectFullStackArtifact(projectRoot);
240117
- if (!redirectPath) {
240179
+ const built = await resolveFullStackBuild(projectRoot);
240180
+ if (!built) {
240118
240181
  return null;
240119
240182
  }
240120
- const config = await resolveWranglerConfig(redirectPath);
240121
- const assetsDir = config.assetsDirectory && await pathExists(config.assetsDirectory) ? config.assetsDirectory : null;
240183
+ const { config, modules, assetsDir } = built;
240122
240184
  return {
240123
240185
  config: {
240124
240186
  main: config.main,
@@ -240126,15 +240188,24 @@ async function resolveWorkerBuild(projectRoot, progress) {
240126
240188
  compatibility_flags: config.compatibilityFlags,
240127
240189
  assets: buildAssetsConfig(config.assetsConfig, progress)
240128
240190
  },
240129
- modules: await collectModules(config),
240191
+ modules,
240130
240192
  assetsDir
240131
240193
  };
240132
240194
  }
240133
- async function readIndexHtml(assetsDir, assets) {
240195
+ function requireStaticEntryPoint(assetsDir, assets) {
240134
240196
  if (!assetsDir || !assets.manifest["/index.html"]) {
240135
240197
  throw new InvalidInputError(`No index.html found in "${assetsDir ?? "the site output directory"}" — a static site needs one at the output directory root.`);
240136
240198
  }
240137
- return new Uint8Array(await readFile3(join18(assetsDir, "index.html")));
240199
+ return assetsDir;
240200
+ }
240201
+ async function resolveStaticCompletion(assetsDir, assets, indexHtmlStaged) {
240202
+ if (indexHtmlStaged)
240203
+ return { kind: "static-staged" };
240204
+ const dir = requireStaticEntryPoint(assetsDir, assets);
240205
+ return {
240206
+ kind: "static-inline",
240207
+ indexHtml: new Uint8Array(await readFile3(join18(dir, "index.html")))
240208
+ };
240138
240209
  }
240139
240210
  function buildAssetsConfig(assetsConfig, progress) {
240140
240211
  if (!assetsConfig)
@@ -246670,6 +246741,13 @@ async function resolveGitHash(projectRoot, explicit) {
246670
246741
  }
246671
246742
  return hash;
246672
246743
  }
246744
+ async function resolveProvenanceCommit(projectRoot, explicit) {
246745
+ if (explicit) {
246746
+ return await resolveGitHash(projectRoot, explicit);
246747
+ }
246748
+ const hash = await gitHead(projectRoot);
246749
+ return hash && isGitCommitHash(hash) ? hash : undefined;
246750
+ }
246673
246751
  async function gitHead(projectRoot) {
246674
246752
  try {
246675
246753
  const { stdout } = await execa("git", ["rev-parse", "HEAD"], {
@@ -246680,22 +246758,6 @@ async function gitHead(projectRoot) {
246680
246758
  return null;
246681
246759
  }
246682
246760
  }
246683
- // src/core/site/serve-command.ts
246684
- var DEFAULT_SERVE_COMMAND = "npm run dev";
246685
- var NPM_RUN_COMMAND = /^npm(\s+--prefix\s+\S+)?\s+run\s+\S+$/;
246686
- function withServeAddress(serveCommand, { host, port, hostFlag }) {
246687
- const args = [
246688
- ...host ? [hostFlag, host] : [],
246689
- ...port === undefined ? [] : ["--port", String(port)]
246690
- ];
246691
- if (args.length === 0 || !NPM_RUN_COMMAND.test(serveCommand.trim())) {
246692
- return serveCommand;
246693
- }
246694
- return `${serveCommand} -- ${args.join(" ")}`;
246695
- }
246696
- function forwardsServeAddress(serveCommand) {
246697
- return NPM_RUN_COMMAND.test(serveCommand.trim());
246698
- }
246699
246761
  // src/core/project/deploy.ts
246700
246762
  function hasResourcesToDeploy(projectData) {
246701
246763
  const {
@@ -246708,7 +246770,7 @@ function hasResourcesToDeploy(projectData) {
246708
246770
  connectors,
246709
246771
  authConfig
246710
246772
  } = projectData;
246711
- const hasSite = project.site !== undefined;
246773
+ const hasSite = Boolean(project.site?.outputDirectory);
246712
246774
  const hasEntities = entities.length > 0;
246713
246775
  const hasFunctions = functions.length > 0;
246714
246776
  const hasActors = actors.length > 0;
@@ -246774,6 +246836,49 @@ async function deployAll(projectData, options) {
246774
246836
  }
246775
246837
  return { connectorResults };
246776
246838
  }
246839
+ // src/core/project/target.ts
246840
+ import { dirname as dirname13, join as join19, resolve as resolve6 } from "node:path";
246841
+ var DEFAULT_BUILD_COMMAND = "npm run build";
246842
+ var DEFAULT_OUTPUT_DIRECTORY = "dist";
246843
+ async function resolveBuildTarget(projectRoot, overrides = {}) {
246844
+ const project = await readSettingsIfPresent(projectRoot);
246845
+ const root = project?.root ?? projectRoot ?? process.cwd();
246846
+ return {
246847
+ root,
246848
+ configDir: project ? dirname13(project.configPath) : join19(root, PROJECT_SUBDIR),
246849
+ buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
246850
+ outputDir: outputDirectory(project, root, overrides.outputDir),
246851
+ entitiesDir: project?.entitiesDir ?? "entities",
246852
+ agentsDir: project?.agentsDir ?? "agents"
246853
+ };
246854
+ }
246855
+ function outputDirectory(project, root, override) {
246856
+ const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
246857
+ return configured ? resolve6(root, configured) : null;
246858
+ }
246859
+ function requireOutputDir(target) {
246860
+ if (target.outputDir === null) {
246861
+ throw new ConfigNotFoundError("No site configuration found.", {
246862
+ hints: [
246863
+ {
246864
+ message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
246865
+ },
246866
+ { message: `Or pass --output-dir <dir>, relative to ${target.root}` }
246867
+ ]
246868
+ });
246869
+ }
246870
+ return target.outputDir;
246871
+ }
246872
+ async function readSettingsIfPresent(projectRoot) {
246873
+ try {
246874
+ return await readProjectSettings(projectRoot);
246875
+ } catch (error) {
246876
+ if (error instanceof ConfigNotFoundError) {
246877
+ return null;
246878
+ }
246879
+ throw error;
246880
+ }
246881
+ }
246777
246882
  // src/core/clients/base44-client.ts
246778
246883
  var retriedRequests = new WeakSet;
246779
246884
  async function captureRequestBody(request, options) {
@@ -247055,6 +247160,12 @@ async function ensureAppContext(ctx, options = {}) {
247055
247160
  ctx.app = appContext;
247056
247161
  ctx.errorReporter.setContext({ appId: appContext.id });
247057
247162
  }
247163
+ function requireApp(ctx) {
247164
+ if (!ctx.app) {
247165
+ throw new InternalError("This command read an app context it never resolved — it is declared with requireAppContext: false.");
247166
+ }
247167
+ return ctx.app;
247168
+ }
247058
247169
 
247059
247170
  // src/cli/utils/version-check.ts
247060
247171
  async function checkForUpgrade() {
@@ -247238,6 +247349,10 @@ function writeJsonError(error) {
247238
247349
  const envelope = {
247239
247350
  error: error instanceof Error ? error.message : String(error)
247240
247351
  };
247352
+ const step = stepOf(error);
247353
+ if (step !== undefined) {
247354
+ envelope.step = step;
247355
+ }
247241
247356
  if (isCLIError(error)) {
247242
247357
  envelope.code = error.code;
247243
247358
  if (error.details.length > 0) {
@@ -247607,7 +247722,7 @@ function getActorsCommand() {
247607
247722
  }
247608
247723
 
247609
247724
  // src/cli/commands/agent-skills/pull.ts
247610
- import { dirname as dirname13, join as join19 } from "node:path";
247725
+ import { dirname as dirname14, join as join20 } from "node:path";
247611
247726
  // src/core/utils/dependencies.ts
247612
247727
  import { spawnSync as spawnSync2 } from "node:child_process";
247613
247728
  function verifyDenoInstalled(context) {
@@ -247696,7 +247811,7 @@ async function pullAction({
247696
247811
  runTask
247697
247812
  }) {
247698
247813
  const { project } = await readProjectConfig();
247699
- const dir = join19(dirname13(project.configPath), project.agentSkillsDir);
247814
+ const dir = join20(dirname14(project.configPath), project.agentSkillsDir);
247700
247815
  const remote = await runTask("Fetching agent skills from Base44", () => fetchAgentSkills(), {
247701
247816
  successMessage: "Agent skills fetched successfully",
247702
247817
  errorMessage: "Failed to fetch agent skills"
@@ -247752,14 +247867,14 @@ function getAgentSkillsCommand() {
247752
247867
  }
247753
247868
 
247754
247869
  // src/cli/commands/agents/pull.ts
247755
- import { dirname as dirname14, join as join20 } from "node:path";
247870
+ import { dirname as dirname15, join as join21 } from "node:path";
247756
247871
  async function pullAgentsAction({
247757
247872
  log,
247758
247873
  runTask
247759
247874
  }) {
247760
247875
  const { project } = await readProjectConfig();
247761
- const configDir = dirname14(project.configPath);
247762
- const agentsDir = join20(configDir, project.agentsDir);
247876
+ const configDir = dirname15(project.configPath);
247877
+ const agentsDir = join21(configDir, project.agentsDir);
247763
247878
  const remoteAgents = await runTask("Fetching agents from Base44", async () => {
247764
247879
  return await fetchAgents();
247765
247880
  }, {
@@ -247829,12 +247944,12 @@ function getAgentsCommand() {
247829
247944
  }
247830
247945
 
247831
247946
  // src/cli/commands/auth/password-login.ts
247832
- import { dirname as dirname15, join as join21 } from "node:path";
247947
+ import { dirname as dirname16, join as join22 } from "node:path";
247833
247948
  async function passwordLoginAction({ log, runTask }, action) {
247834
247949
  const shouldEnable = action === "enable";
247835
247950
  const { project } = await readProjectConfig();
247836
- const configDir = dirname15(project.configPath);
247837
- const authDir = join21(configDir, project.authDir);
247951
+ const configDir = dirname16(project.configPath);
247952
+ const authDir = join22(configDir, project.authDir);
247838
247953
  const updated = await runTask("Updating local auth config", async () => {
247839
247954
  const current = await readAuthConfig(authDir) ?? DEFAULT_AUTH_CONFIG;
247840
247955
  const merged = { ...current, enableUsernamePassword: shouldEnable };
@@ -247854,14 +247969,14 @@ function getPasswordLoginCommand() {
247854
247969
  }
247855
247970
 
247856
247971
  // src/cli/commands/auth/pull.ts
247857
- import { dirname as dirname16, join as join22 } from "node:path";
247972
+ import { dirname as dirname17, join as join23 } from "node:path";
247858
247973
  async function pullAuthAction({
247859
247974
  log,
247860
247975
  runTask
247861
247976
  }) {
247862
247977
  const { project } = await readProjectConfig();
247863
- const configDir = dirname16(project.configPath);
247864
- const authDir = join22(configDir, project.authDir);
247978
+ const configDir = dirname17(project.configPath);
247979
+ const authDir = join23(configDir, project.authDir);
247865
247980
  const remoteConfig = await runTask("Fetching auth config from Base44", async () => {
247866
247981
  return await pullAuthConfig();
247867
247982
  }, {
@@ -247925,7 +248040,7 @@ function getAuthPushCommand() {
247925
248040
  }
247926
248041
 
247927
248042
  // src/cli/commands/auth/social-login.ts
247928
- import { dirname as dirname17, join as join23, resolve as resolve6 } from "node:path";
248043
+ import { dirname as dirname18, join as join24, resolve as resolve7 } from "node:path";
247929
248044
  var PROVIDER_LABELS = {
247930
248045
  google: "Google",
247931
248046
  microsoft: "Microsoft",
@@ -247965,7 +248080,7 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
247965
248080
  let clientSecret;
247966
248081
  if (useCustomOAuth && oauth && oauthCli && hasSecretOptions(options)) {
247967
248082
  if (options.envFile) {
247968
- const secrets = await parseEnvFile(resolve6(options.envFile));
248083
+ const secrets = await parseEnvFile(resolve7(options.envFile));
247969
248084
  const value = secrets[oauthCli.envVar];
247970
248085
  if (!value) {
247971
248086
  throw new InvalidInputError(`Key "${oauthCli.envVar}" not found in ${options.envFile}.`);
@@ -247995,8 +248110,8 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
247995
248110
  }
247996
248111
  }
247997
248112
  const { project } = await readProjectConfig();
247998
- const configDir = dirname17(project.configPath);
247999
- const authDir = join23(configDir, project.authDir);
248113
+ const configDir = dirname18(project.configPath);
248114
+ const authDir = join24(configDir, project.authDir);
248000
248115
  const { config: updated } = await runTask("Updating local auth config", async () => updateSocialLoginConfig(authDir, provider, shouldEnable, useCustomOAuth && options.clientId ? { clientId: options.clientId } : undefined));
248001
248116
  if (clientSecret) {
248002
248117
  await runTask("Saving client secret", async () => pushCustomOAuthSecret(provider, clientSecret));
@@ -248021,7 +248136,7 @@ function getSocialLoginCommand() {
248021
248136
  }
248022
248137
 
248023
248138
  // src/cli/commands/auth/sso.ts
248024
- import { dirname as dirname18, join as join24, resolve as resolve7 } from "node:path";
248139
+ import { dirname as dirname19, join as join25, resolve as resolve8 } from "node:path";
248025
248140
  var SSOConfigFileSchema = object({
248026
248141
  provider: _enum(Object.values(KNOWN_SSO_PROVIDERS)),
248027
248142
  clientId: string2(),
@@ -248037,7 +248152,7 @@ var SSOConfigFileSchema = object({
248037
248152
  ssoName: string2().optional()
248038
248153
  });
248039
248154
  async function loadSSOConfigFile(filePath) {
248040
- const resolved = resolve7(filePath);
248155
+ const resolved = resolve8(filePath);
248041
248156
  const raw = await readJsonFile(resolved);
248042
248157
  const result = SSOConfigFileSchema.safeParse(raw);
248043
248158
  if (!result.success) {
@@ -248125,7 +248240,7 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
248125
248240
  }
248126
248241
  let clientSecret;
248127
248242
  if (merged.envFile && !merged.clientSecret) {
248128
- const secrets = await parseEnvFile(resolve7(merged.envFile));
248243
+ const secrets = await parseEnvFile(resolve8(merged.envFile));
248129
248244
  const value = secrets.sso_client_secret;
248130
248245
  if (!value) {
248131
248246
  throw new InvalidInputError(`Key "sso_client_secret" not found in ${merged.envFile}.`);
@@ -248184,8 +248299,8 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
248184
248299
  throw error;
248185
248300
  }
248186
248301
  const { project } = await readProjectConfig();
248187
- const configDir = dirname18(project.configPath);
248188
- const authDir = join24(configDir, project.authDir);
248302
+ const configDir = dirname19(project.configPath);
248303
+ const authDir = join25(configDir, project.authDir);
248189
248304
  await runTask("Updating local auth config", async () => updateSSOConfig(authDir, provider, true));
248190
248305
  await runTask("Saving SSO credentials", async () => pushSSOSecrets(secrets));
248191
248306
  return {
@@ -248200,8 +248315,8 @@ async function ssoDisableAction({ log, runTask }, options) {
248200
248315
  throw new InvalidInputError("Configuration options cannot be used with disable. To disable SSO: base44 auth sso disable");
248201
248316
  }
248202
248317
  const { project } = await readProjectConfig();
248203
- const configDir = dirname18(project.configPath);
248204
- const authDir = join24(configDir, project.authDir);
248318
+ const configDir = dirname19(project.configPath);
248319
+ const authDir = join25(configDir, project.authDir);
248205
248320
  const updated = await runTask("Updating local auth config", async () => updateSSOConfig(authDir, null, false));
248206
248321
  await runTask("Removing SSO credentials", async () => deleteSSOSecrets());
248207
248322
  if (!hasAnyLoginMethod(updated)) {
@@ -249083,13 +249198,13 @@ function getConnectorsListAvailableCommand() {
249083
249198
  }
249084
249199
 
249085
249200
  // src/cli/commands/connectors/pull.ts
249086
- import { dirname as dirname19, join as join25, resolve as resolve8 } from "node:path";
249201
+ import { dirname as dirname20, join as join26, resolve as resolve9 } from "node:path";
249087
249202
  async function resolveConnectorsDir(options) {
249088
249203
  if (!getAppContext().projectRoot) {
249089
- return resolve8(options.dir ?? "connectors");
249204
+ return resolve9(options.dir ?? "connectors");
249090
249205
  }
249091
249206
  const { project } = await readProjectConfig();
249092
- return join25(dirname19(project.configPath), project.connectorsDir);
249207
+ return join26(dirname20(project.configPath), project.connectorsDir);
249093
249208
  }
249094
249209
  async function pullConnectorsAction({ log, runTask, jsonMode }, options) {
249095
249210
  const connectorsDir = await resolveConnectorsDir(options);
@@ -249130,10 +249245,10 @@ function getConnectorsPullCommand() {
249130
249245
  }
249131
249246
 
249132
249247
  // src/cli/commands/connectors/push.ts
249133
- import { resolve as resolve9 } from "node:path";
249248
+ import { resolve as resolve10 } from "node:path";
249134
249249
  async function readConnectorsToPush(options) {
249135
249250
  if (!getAppContext().projectRoot) {
249136
- return readAllConnectors(resolve9(options.dir ?? "connectors"));
249251
+ return readAllConnectors(resolve10(options.dir ?? "connectors"));
249137
249252
  }
249138
249253
  const { connectors } = await readProjectConfig();
249139
249254
  return connectors;
@@ -249476,11 +249591,11 @@ function getListCommand() {
249476
249591
  }
249477
249592
 
249478
249593
  // src/cli/commands/functions/pull.ts
249479
- import { dirname as dirname20, join as join26 } from "node:path";
249594
+ import { dirname as dirname21, join as join27 } from "node:path";
249480
249595
  async function pullFunctionsAction({ log, runTask }, name) {
249481
249596
  const { project, functions } = await readProjectConfig();
249482
- const configDir = dirname20(project.configPath);
249483
- const functionsDir = join26(configDir, project.functionsDir);
249597
+ const configDir = dirname21(project.configPath);
249598
+ const functionsDir = join27(configDir, project.functionsDir);
249484
249599
  const pluginFunctionNames = new Set(functions.filter((fn) => fn.source.type === "plugin").map((fn) => fn.name));
249485
249600
  const remoteFunctions = await runTask("Fetching functions from Base44", async () => {
249486
249601
  const { functions } = await listDeployedFunctions();
@@ -249583,14 +249698,11 @@ async function maybeAskToBuild(isNonInteractive, buildCommand) {
249583
249698
 
249584
249699
  // src/cli/commands/project/build.ts
249585
249700
  async function buildAction(ctx) {
249586
- const { app } = ctx;
249587
- if (!app?.projectRoot) {
249588
- throw new ConfigInvalidError("base44 build requires a linked local project. Run it from a project with base44/.app.jsonc.");
249589
- }
249590
- const { project } = await readProjectConfig(app.projectRoot);
249701
+ const app = requireApp(ctx);
249702
+ const target = await resolveBuildTarget(app.projectRoot);
249591
249703
  await runSiteBuild(ctx, {
249592
- root: project.root,
249593
- buildCommand: project.site?.buildCommand,
249704
+ root: target.root,
249705
+ buildCommand: target.buildCommand,
249594
249706
  appId: app.id
249595
249707
  });
249596
249708
  return {
@@ -249598,15 +249710,15 @@ async function buildAction(ctx) {
249598
249710
  };
249599
249711
  }
249600
249712
  function getBuildCommand() {
249601
- return new Base44Command("build").description("Build the site with the Base44 app id injected").action(buildAction);
249713
+ return new Base44Command("build", { requireAuth: false }).description("Build the site with the Base44 app id injected").action(buildAction);
249602
249714
  }
249603
249715
 
249604
249716
  // src/cli/commands/project/create.ts
249605
- import { basename as basename6, resolve as resolve10 } from "node:path";
249717
+ import { basename as basename6, resolve as resolve11 } from "node:path";
249606
249718
  var import_kebabCase = __toESM(require_kebabCase(), 1);
249607
249719
 
249608
249720
  // src/cli/commands/project/scaffold-shared.ts
249609
- import { join as join27 } from "node:path";
249721
+ import { join as join28 } from "node:path";
249610
249722
  var DEFAULT_TEMPLATE_ID = "backend-only";
249611
249723
  async function getTemplateById(templateId) {
249612
249724
  const templates = await listTemplates();
@@ -249669,7 +249781,7 @@ async function completeProjectSetup({
249669
249781
  env: { VITE_BASE44_APP_ID: projectId }
249670
249782
  })`${buildCommand}`;
249671
249783
  updateMessage("Deploying site...");
249672
- return await deploySite(join27(resolvedPath, outputDirectory));
249784
+ return await deploySite(join28(resolvedPath, outputDirectory));
249673
249785
  }, {
249674
249786
  successMessage: theme.colors.base44Orange("Site deployed successfully"),
249675
249787
  errorMessage: "Failed to deploy site"
@@ -249798,7 +249910,7 @@ async function createInteractive(options, ctx) {
249798
249910
  }, ctx);
249799
249911
  }
249800
249912
  async function createNonInteractive(options, ctx) {
249801
- ctx.log.info(`Creating a new project at ${resolve10(options.path)}`);
249913
+ ctx.log.info(`Creating a new project at ${resolve11(options.path)}`);
249802
249914
  const template = await getTemplateById(options.template ?? DEFAULT_TEMPLATE_ID);
249803
249915
  return await executeCreate({
249804
249916
  template,
@@ -249822,7 +249934,7 @@ async function executeCreate({
249822
249934
  }, ctx) {
249823
249935
  const { log, runTask } = ctx;
249824
249936
  const name = rawName.trim();
249825
- const resolvedPath = resolve10(projectPath);
249937
+ const resolvedPath = resolve11(projectPath);
249826
249938
  const organizationId = await resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive);
249827
249939
  const { projectId } = await runTask("Setting up your project...", async () => {
249828
249940
  return await createProjectFiles({
@@ -249995,36 +250107,6 @@ function printStripeResult(r, log) {
249995
250107
  log.info(` Connectors dashboard: ${theme.colors.links(getConnectorsUrl())}`);
249996
250108
  }
249997
250109
 
249998
- // src/cli/commands/project/install.ts
249999
- async function installAction({
250000
- runTask
250001
- }) {
250002
- const { project } = await readProjectConfig();
250003
- const installCommand = project.site?.installCommand;
250004
- if (!installCommand) {
250005
- throw new ConfigNotFoundError("No site install command found.", {
250006
- hints: [
250007
- {
250008
- message: `Add a 'site' block to your config.jsonc (e.g., "site": { "installCommand": "npm ci" }). Inside one, installCommand defaults to "npm install".`
250009
- }
250010
- ]
250011
- });
250012
- }
250013
- await runTask("Installing site dependencies...", () => execa({ cwd: project.root, shell: true })`${installCommand}`, {
250014
- successMessage: "Dependencies installed",
250015
- errorMessage: "Install failed"
250016
- });
250017
- return {
250018
- outroMessage: `Installed with ${theme.styles.bold(installCommand)}`
250019
- };
250020
- }
250021
- function getInstallCommand() {
250022
- return new Base44Command("install", {
250023
- requireAuth: false,
250024
- requireAppContext: false
250025
- }).description("Install the site's dependencies with its configured command").action(installAction);
250026
- }
250027
-
250028
250110
  // src/cli/commands/project/app-id-options.ts
250029
250111
  function readExplicitAppId(command) {
250030
250112
  const { appId } = command.optsWithGlobals();
@@ -250493,7 +250575,7 @@ function getLogsCommand() {
250493
250575
  }
250494
250576
 
250495
250577
  // src/cli/commands/project/scaffold.ts
250496
- import { basename as basename7, resolve as resolve11 } from "node:path";
250578
+ import { basename as basename7, resolve as resolve12 } from "node:path";
250497
250579
  function resolveAppId(options) {
250498
250580
  const appId = options.appId;
250499
250581
  if (!appId) {
@@ -250509,7 +250591,7 @@ function resolveAppId(options) {
250509
250591
  async function scaffoldAction(ctx, name, options, command) {
250510
250592
  const { log, runTask } = ctx;
250511
250593
  const appId = resolveAppId(command.optsWithGlobals());
250512
- const resolvedPath = resolve11("./");
250594
+ const resolvedPath = resolve12("./");
250513
250595
  const projectName = (name ?? basename7(resolvedPath)).trim();
250514
250596
  const template = await getTemplateById("backend-only");
250515
250597
  log.info(`Scaffolding project at ${resolvedPath}`);
@@ -250557,6 +250639,315 @@ function getVisibilityCommand() {
250557
250639
  ])).action(setVisibility);
250558
250640
  }
250559
250641
 
250642
+ // src/core/version/schema.ts
250643
+ var DeclareVersionResponseSchema = object({
250644
+ session_id: string2(),
250645
+ uploads: array(object({
250646
+ path: string2(),
250647
+ url: string2(),
250648
+ content_type: string2(),
250649
+ content_length: number2(),
250650
+ checksum_sha256: string2()
250651
+ }))
250652
+ }).transform((data) => ({
250653
+ sessionId: data.session_id,
250654
+ uploads: data.uploads.map((upload) => ({
250655
+ path: upload.path,
250656
+ url: upload.url,
250657
+ contentType: upload.content_type,
250658
+ contentLength: upload.content_length,
250659
+ checksumSha256: upload.checksum_sha256
250660
+ }))
250661
+ }));
250662
+ var CreateVersionResponseSchema = object({
250663
+ version_id: string2(),
250664
+ manifest_hash: string2()
250665
+ }).transform((data) => ({
250666
+ versionId: data.version_id,
250667
+ manifestHash: data.manifest_hash
250668
+ }));
250669
+ var EnvironmentResponseSchema = object({
250670
+ name: string2(),
250671
+ version_id: string2(),
250672
+ manifest_hash: string2(),
250673
+ deployment_id: string2()
250674
+ }).transform((data) => ({
250675
+ name: data.name,
250676
+ versionId: data.version_id,
250677
+ manifestHash: data.manifest_hash,
250678
+ deploymentId: data.deployment_id
250679
+ }));
250680
+
250681
+ // src/core/version/api.ts
250682
+ var DEFAULT_VERSION_UPLOAD_CONCURRENCY = 8;
250683
+ var MAX_VERSION_UPLOAD_CONCURRENCY = 16;
250684
+ function declaredFile({ path, size, digest }) {
250685
+ return { path, size, digest };
250686
+ }
250687
+ function declaredModule(module) {
250688
+ return { ...declaredFile(module), type: module.type };
250689
+ }
250690
+ function declaredServingConfig(config) {
250691
+ const stated = {
250692
+ html_handling: config?.htmlHandling ?? null,
250693
+ not_found_handling: config?.notFoundHandling ?? null,
250694
+ run_worker_first: config?.runWorkerFirst ?? null,
250695
+ headers: config?.headers ?? null,
250696
+ redirects: config?.redirects ?? null
250697
+ };
250698
+ return Object.values(stated).every((v) => v === null) ? null : stated;
250699
+ }
250700
+ async function post(path, json, doing) {
250701
+ try {
250702
+ return await getAppClient().post(path, { json, timeout: 180000 });
250703
+ } catch (error) {
250704
+ throw await ApiError.fromHttpError(error, doing);
250705
+ }
250706
+ }
250707
+ var KEYED_RETRY = {
250708
+ limit: 3,
250709
+ methods: ["patch"],
250710
+ statusCodes: [408, 500, 502, 503, 504],
250711
+ retryOnTimeout: true
250712
+ };
250713
+ async function patch(path, json, doing, retry) {
250714
+ try {
250715
+ return await getAppClient().patch(path, {
250716
+ json,
250717
+ timeout: 180000,
250718
+ ...retry ? { retry } : {}
250719
+ });
250720
+ } catch (error) {
250721
+ throw await ApiError.fromHttpError(error, doing);
250722
+ }
250723
+ }
250724
+ function parse10(schema, body, what) {
250725
+ const result = schema.safeParse(body);
250726
+ if (!result.success) {
250727
+ throw new SchemaValidationError(`Invalid ${what} response from server`, result.error);
250728
+ }
250729
+ return result.data;
250730
+ }
250731
+ async function createVersion(artifacts, options = {}) {
250732
+ const declared = parse10(DeclareVersionResponseSchema, await (await post("versions", {
250733
+ assets: artifacts.assets.map(declaredFile),
250734
+ ...artifacts.siteWorker ? {
250735
+ site_worker: {
250736
+ main: artifacts.siteWorker.main,
250737
+ modules: artifacts.siteWorker.modules.map(declaredModule),
250738
+ compatibility_date: artifacts.siteWorker.compatibilityDate,
250739
+ compatibility_flags: artifacts.siteWorker.compatibilityFlags,
250740
+ serving_config: declaredServingConfig(artifacts.siteWorker.servingConfig)
250741
+ }
250742
+ } : {},
250743
+ entities: artifacts.entities,
250744
+ agents: artifacts.agents,
250745
+ source_commit: options.sourceCommit
250746
+ }, "declaring a version")).json(), "declare");
250747
+ const declaredFiles = [
250748
+ ...artifacts.assets,
250749
+ ...artifacts.siteWorker?.modules ?? []
250750
+ ];
250751
+ options.progress?.onDeclared?.({ fileCount: declaredFiles.length });
250752
+ if (declared.uploads.length !== declaredFiles.length) {
250753
+ throw new InternalError(`Declared ${declaredFiles.length} files but the server signed ${declared.uploads.length} upload URLs.`);
250754
+ }
250755
+ const drifted = declared.uploads.findIndex((upload, index) => upload.path !== declaredFiles[index].path);
250756
+ if (drifted !== -1) {
250757
+ throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
250758
+ }
250759
+ let uploadedFiles = 0;
250760
+ await pMap(declared.uploads, async (upload, index) => {
250761
+ await putPresigned(upload, declaredFiles[index].absolutePath);
250762
+ uploadedFiles++;
250763
+ options.progress?.onUpload?.({
250764
+ uploadedFiles,
250765
+ totalFiles: declared.uploads.length
250766
+ });
250767
+ }, { concurrency: options.concurrency ?? DEFAULT_VERSION_UPLOAD_CONCURRENCY });
250768
+ return parse10(CreateVersionResponseSchema, await (await post(`versions/${encodeURIComponent(declared.sessionId)}/finalize`, {}, "creating a version")).json(), "create version");
250769
+ }
250770
+ async function setEnvironmentVersion(environment, versionId, options = {}) {
250771
+ return parse10(EnvironmentResponseSchema, await (await patch(`environments/${encodeURIComponent(environment)}`, {
250772
+ version_id: versionId,
250773
+ ...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
250774
+ }, "setting the environment's version", options.idempotencyKey ? KEYED_RETRY : undefined)).json(), "environment");
250775
+ }
250776
+ // src/core/version/artifacts.ts
250777
+ import { createHash as createHash2 } from "node:crypto";
250778
+ import { join as join29, resolve as resolve13 } from "node:path";
250779
+ var MAX_FILE_COUNT = 50000;
250780
+ var HASH_CONCURRENCY = 32;
250781
+ var ENTRY2 = "index.html";
250782
+ async function digestFile(absolutePath) {
250783
+ const hash = await hashFileInto(createHash2("sha256"), absolutePath);
250784
+ return `sha256:${hash.digest("hex")}`;
250785
+ }
250786
+ async function collectBuildOutput(outputDir, options = {}) {
250787
+ const found = await describeBuildOutput(outputDir);
250788
+ if (found.length > MAX_FILE_COUNT) {
250789
+ throw new InvalidInputError(`Too many files: found ${found.length}, the limit is ${MAX_FILE_COUNT}.`);
250790
+ }
250791
+ if (options.entryFile) {
250792
+ if (found.length === 0) {
250793
+ throw new InvalidInputError(`No files found in ${outputDir}. Build the site before creating a version.`, {
250794
+ hints: [
250795
+ { message: "Run 'base44 build' first", command: "base44 build" }
250796
+ ]
250797
+ });
250798
+ }
250799
+ if (!found.some((f) => f.path === options.entryFile)) {
250800
+ throw new InvalidInputError(`${outputDir} has no ${options.entryFile}, so nothing could enter the site.`);
250801
+ }
250802
+ }
250803
+ return await pMap(found, async (file) => ({ ...file, digest: await digestFile(file.absolutePath) }), { concurrency: HASH_CONCURRENCY });
250804
+ }
250805
+ async function describeSiteWorker(built) {
250806
+ const { config, modules } = built;
250807
+ const entry = resolve13(config.configDir, config.main);
250808
+ const main = modules.find((m) => m.absolutePath === entry)?.name;
250809
+ if (!main) {
250810
+ throw new InvalidInputError(`The Worker's entry module ${config.main} is not among the ${modules.length} modules collected from ${config.configDir}.`);
250811
+ }
250812
+ return {
250813
+ main,
250814
+ modules: await pMap(modules, async ({ name, absolutePath, size, type }) => ({
250815
+ path: name,
250816
+ absolutePath,
250817
+ size,
250818
+ digest: await digestFile(absolutePath),
250819
+ type
250820
+ }), { concurrency: HASH_CONCURRENCY }),
250821
+ compatibilityDate: config.compatibilityDate,
250822
+ compatibilityFlags: config.compatibilityFlags,
250823
+ servingConfig: config.assetsConfig
250824
+ };
250825
+ }
250826
+ async function readRawResources(dir) {
250827
+ if (!await pathExists(dir)) {
250828
+ return {};
250829
+ }
250830
+ const files = await globby(`**/*.${CONFIG_FILE_EXTENSION_GLOB}`, {
250831
+ cwd: dir,
250832
+ onlyFiles: true,
250833
+ followSymbolicLinks: false
250834
+ });
250835
+ const payloads = {};
250836
+ for (const relativePath of files.sort()) {
250837
+ const name = relativePath.replace(/\.jsonc?$/, "");
250838
+ payloads[name] = await readJsonFile(join29(dir, ...relativePath.split("/")));
250839
+ }
250840
+ return payloads;
250841
+ }
250842
+ async function collectResources(configDir, dirs) {
250843
+ const [entities, agents] = await Promise.all([
250844
+ readRawResources(join29(configDir, dirs.entitiesDir)),
250845
+ readRawResources(join29(configDir, dirs.agentsDir))
250846
+ ]);
250847
+ return { entities, agents };
250848
+ }
250849
+ async function collectArtifacts(target) {
250850
+ const built = await resolveFullStackBuild(target.root);
250851
+ const siteWorker = built ? await describeSiteWorker(built) : null;
250852
+ return {
250853
+ assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(requireOutputDir(target), {
250854
+ entryFile: ENTRY2
250855
+ }),
250856
+ ...siteWorker ? { siteWorker } : {},
250857
+ ...await collectResources(target.configDir, target)
250858
+ };
250859
+ }
250860
+ // src/core/version/gate.ts
250861
+ var VERSIONS_API_ENV = "BASE44_VERSIONS_API";
250862
+ function versionsApiEnabled(env = process.env) {
250863
+ const value = env[VERSIONS_API_ENV];
250864
+ return value === "1" || value === "true";
250865
+ }
250866
+ // src/core/version/publish.ts
250867
+ import { randomUUID as randomUUID4 } from "node:crypto";
250868
+ var DEFAULT_ENVIRONMENT = "production";
250869
+ async function tagStep2(step, run) {
250870
+ return await tagStep(step, run);
250871
+ }
250872
+ async function publishVersion(artifacts, options = {}) {
250873
+ const version = await tagStep2("create_version", () => createVersion(artifacts, {
250874
+ sourceCommit: options.sourceCommit,
250875
+ concurrency: options.concurrency,
250876
+ progress: options.progress
250877
+ }));
250878
+ const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
250879
+ idempotencyKey: randomUUID4()
250880
+ }));
250881
+ return {
250882
+ environment: environment.name,
250883
+ versionId: environment.versionId,
250884
+ manifestHash: environment.manifestHash,
250885
+ deploymentId: environment.deploymentId
250886
+ };
250887
+ }
250888
+ // src/cli/commands/versions/options.ts
250889
+ function outputDirOption() {
250890
+ return new Option2("--output-dir <dir>", "Build output directory (defaults to the project's, else dist)");
250891
+ }
250892
+ function targetOption() {
250893
+ return new Option2("--target <name>", "Environment to serve the version at");
250894
+ }
250895
+ function gitHashOption() {
250896
+ return new Option2("--git-hash <hash>", "Commit the build came from (defaults to the checkout's HEAD)").argParser((value) => {
250897
+ if (!isGitCommitHash(value)) {
250898
+ throw new InvalidArgumentError2("Expected a git commit hash (7-64 hex chars).");
250899
+ }
250900
+ return value;
250901
+ });
250902
+ }
250903
+ function concurrencyOption() {
250904
+ return new Option2("--concurrency <n>", "Parallel file uploads").default(DEFAULT_VERSION_UPLOAD_CONCURRENCY).argParser((value) => {
250905
+ const parsed = Number(value);
250906
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_VERSION_UPLOAD_CONCURRENCY) {
250907
+ throw new InvalidArgumentError2(`Expected a whole number between 1 and ${MAX_VERSION_UPLOAD_CONCURRENCY}.`);
250908
+ }
250909
+ return parsed;
250910
+ });
250911
+ }
250912
+
250913
+ // src/cli/commands/publish.ts
250914
+ async function publishAction(ctx, options) {
250915
+ const { runTask, log, jsonMode } = ctx;
250916
+ const app = requireApp(ctx);
250917
+ const target = await tagStep2("create_version", () => resolveBuildTarget(app.projectRoot, { outputDir: options.outputDir }));
250918
+ if (options.build !== false) {
250919
+ await tagStep2("build", () => runSiteBuild(ctx, {
250920
+ root: target.root,
250921
+ buildCommand: target.buildCommand,
250922
+ appId: app.id
250923
+ }));
250924
+ }
250925
+ const gitHash = await resolveProvenanceCommit(target.root, options.gitHash);
250926
+ const result = await runTask("Publishing...", async (updateMessage) => {
250927
+ const artifacts = await tagStep2("create_version", () => collectArtifacts(target));
250928
+ return await publishVersion(artifacts, {
250929
+ sourceCommit: gitHash,
250930
+ target: options.target,
250931
+ concurrency: options.concurrency,
250932
+ progress: {
250933
+ onDeclared: ({ fileCount }) => updateMessage(`Uploading ${fileCount} files`),
250934
+ onUpload: ({ uploadedFiles, totalFiles }) => updateMessage(`Uploaded ${uploadedFiles} of ${totalFiles} files`)
250935
+ }
250936
+ });
250937
+ }, { successMessage: "Published", errorMessage: "Publish failed" });
250938
+ if (!jsonMode) {
250939
+ log.message(theme.styles.dim(`version ${result.versionId}`));
250940
+ }
250941
+ return {
250942
+ outroMessage: `${result.environment} now serves ${result.versionId}`,
250943
+ stdout: jsonMode ? `${JSON.stringify(result, null, 2)}
250944
+ ` : undefined
250945
+ };
250946
+ }
250947
+ function getPublishCommand() {
250948
+ return new Base44Command("publish").description("Build the app, record it as a version, and serve that version").option("--no-build", "Publish the existing build output without rebuilding").addOption(outputDirOption()).addOption(targetOption()).addOption(gitHashOption()).addOption(concurrencyOption()).action(publishAction);
250949
+ }
250950
+
250560
250951
  // src/core/resources/sandbox/schema.ts
250561
250952
  var FileErrorSchema = object({
250562
250953
  code: string2(),
@@ -250942,7 +251333,7 @@ function getSecretsListCommand() {
250942
251333
  }
250943
251334
 
250944
251335
  // src/cli/commands/secrets/set.ts
250945
- import { resolve as resolve12 } from "node:path";
251336
+ import { resolve as resolve14 } from "node:path";
250946
251337
  function parseEntries(entries) {
250947
251338
  const secrets = {};
250948
251339
  for (const entry of entries) {
@@ -250973,7 +251364,7 @@ async function setSecretsAction({ log, runTask }, entries, options) {
250973
251364
  validateInput(entries, options);
250974
251365
  let secrets;
250975
251366
  if (options.envFile) {
250976
- secrets = await parseEnvFile(resolve12(options.envFile));
251367
+ secrets = await parseEnvFile(resolve14(options.envFile));
250977
251368
  if (Object.keys(secrets).length === 0) {
250978
251369
  throw new InvalidInputError("The env file contains no valid KEY=VALUE entries.");
250979
251370
  }
@@ -251002,7 +251393,7 @@ function getSecretsCommand() {
251002
251393
  }
251003
251394
 
251004
251395
  // src/cli/commands/site/deploy.ts
251005
- import { resolve as resolve13 } from "node:path";
251396
+ import { resolve as resolve15 } from "node:path";
251006
251397
  async function deployAction2(ctx, options) {
251007
251398
  const { isNonInteractive } = ctx;
251008
251399
  if (isNonInteractive && !options.yes) {
@@ -251067,7 +251458,7 @@ async function deployTarball({ runTask }, project) {
251067
251458
  throw new ConfigNotFoundError("No site configuration found.", {
251068
251459
  hints: [
251069
251460
  {
251070
- message: `Add a 'site' block to your config.jsonc (e.g., "site": { "outputDirectory": "dist" }). Inside one, outputDirectory defaults to "./dist".`
251461
+ message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
251071
251462
  }
251072
251463
  ]
251073
251464
  });
@@ -251080,7 +251471,7 @@ async function deployTarball({ runTask }, project) {
251080
251471
  }
251081
251472
  function siteOutputDir(project) {
251082
251473
  const outputDirectory = project.site?.outputDirectory;
251083
- return outputDirectory ? resolve13(project.root, outputDirectory) : null;
251474
+ return outputDirectory ? resolve15(project.root, outputDirectory) : null;
251084
251475
  }
251085
251476
  function getSiteDeployCommand() {
251086
251477
  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)");
@@ -251104,213 +251495,6 @@ function parseConcurrency(value) {
251104
251495
  return parsed;
251105
251496
  }
251106
251497
 
251107
- // src/cli/dev/createDevLogger.ts
251108
- var colorByType = {
251109
- error: theme.styles.error,
251110
- warn: theme.styles.warn,
251111
- log: (input) => input
251112
- };
251113
- var stringify = (item) => {
251114
- if (typeof item === "string") {
251115
- return item;
251116
- }
251117
- if (item instanceof Error) {
251118
- return item.toString();
251119
- }
251120
- try {
251121
- return JSON.stringify(item, null, 2) ?? String(item);
251122
- } catch {
251123
- return String(item);
251124
- }
251125
- };
251126
- function createDevLogger(label, labelColor = theme.styles.dim) {
251127
- const prefix = label ? `${labelColor(`[${label}]`)} ` : "";
251128
- const print = (type, ...args) => {
251129
- const colorize = colorByType[type];
251130
- console[type](prefix + args.map((item) => colorize(stringify(item))).join(" "));
251131
- };
251132
- return {
251133
- log: (...args) => print("log", ...args),
251134
- error: (msg, err) => {
251135
- print("error", msg);
251136
- if (err) {
251137
- print("error", err);
251138
- }
251139
- },
251140
- warn: (...args) => print("warn", ...args)
251141
- };
251142
- }
251143
-
251144
- // src/cli/dev/dev-server/serve-runner.ts
251145
- import { spawn as spawn2 } from "node:child_process";
251146
- import process21 from "node:process";
251147
-
251148
- class ServeRunner {
251149
- command;
251150
- cwd;
251151
- env;
251152
- logger;
251153
- child;
251154
- stopping = false;
251155
- stopPromise;
251156
- exitListeners = [];
251157
- constructor(options) {
251158
- this.command = options.command;
251159
- this.cwd = options.cwd;
251160
- this.env = options.env;
251161
- this.logger = options.logger;
251162
- }
251163
- start() {
251164
- if (this.child) {
251165
- return;
251166
- }
251167
- const stdin = process21.platform === "win32" ? "ignore" : "inherit";
251168
- const child = spawn2(this.command, {
251169
- cwd: this.cwd,
251170
- shell: true,
251171
- detached: process21.platform !== "win32",
251172
- env: { ...process21.env, ...this.env },
251173
- stdio: [stdin, "pipe", "pipe"],
251174
- windowsHide: true
251175
- });
251176
- this.child = child;
251177
- this.setupHandlers(child);
251178
- }
251179
- onExit(listener) {
251180
- this.exitListeners.push(listener);
251181
- }
251182
- async stop() {
251183
- if (this.stopPromise) {
251184
- return this.stopPromise;
251185
- }
251186
- this.stopPromise = this.stopChild();
251187
- return this.stopPromise;
251188
- }
251189
- async stopChild() {
251190
- const child = this.child;
251191
- if (!child || child.exitCode !== null) {
251192
- return;
251193
- }
251194
- this.stopping = true;
251195
- const exited = new Promise((resolve) => child.once("exit", () => resolve()));
251196
- if (process21.platform === "win32" && child.pid) {
251197
- const taskkill = spawn2("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
251198
- stdio: "ignore",
251199
- windowsHide: true
251200
- });
251201
- await new Promise((resolve) => {
251202
- taskkill.once("exit", () => resolve());
251203
- taskkill.once("error", () => resolve());
251204
- });
251205
- } else if (child.pid) {
251206
- try {
251207
- process21.kill(-child.pid, "SIGTERM");
251208
- } catch {
251209
- child.kill();
251210
- }
251211
- }
251212
- await exited;
251213
- }
251214
- setupHandlers(child) {
251215
- child.stdout?.on("data", (data) => this.emitLines(data, "log"));
251216
- child.stderr?.on("data", (data) => this.emitLines(data, "error"));
251217
- child.on("error", (error) => {
251218
- this.logger.error("Frontend dev server failed to start:", error);
251219
- this.notifyExit(null);
251220
- });
251221
- child.on("exit", (code) => {
251222
- if (this.stopping) {
251223
- return;
251224
- }
251225
- this.logger.error(`Frontend dev server exited with code ${code}`);
251226
- this.notifyExit(code);
251227
- });
251228
- }
251229
- notifyExit(code) {
251230
- for (const listener of this.exitListeners) {
251231
- listener(code);
251232
- }
251233
- }
251234
- emitLines(data, type) {
251235
- const lines = data.toString().trimEnd().split(`
251236
- `);
251237
- for (const line of lines) {
251238
- if (type === "error") {
251239
- this.logger.error(line);
251240
- } else {
251241
- this.logger.log(line);
251242
- }
251243
- }
251244
- }
251245
- }
251246
-
251247
- // src/cli/dev/serve-command-runner.ts
251248
- function createServeCommandRunner({
251249
- serveCommand,
251250
- projectRoot,
251251
- appId,
251252
- appBaseUrl
251253
- }) {
251254
- return new ServeRunner({
251255
- command: serveCommand,
251256
- cwd: projectRoot,
251257
- env: {
251258
- VITE_BASE44_APP_ID: appId,
251259
- VITE_BASE44_APP_BASE_URL: appBaseUrl
251260
- },
251261
- logger: createDevLogger("frontend", theme.colors.base44Orange)
251262
- });
251263
- }
251264
-
251265
- // src/cli/dev/stop-runner-on-signals.ts
251266
- import process22 from "node:process";
251267
- function stopRunnerOnProcessSignals(runner) {
251268
- const stop = () => void runner.stop();
251269
- process22.on("SIGINT", stop);
251270
- process22.on("SIGTERM", stop);
251271
- }
251272
-
251273
- // src/cli/commands/site/dev.ts
251274
- async function siteDevAction(ctx, options) {
251275
- const { app, log } = ctx;
251276
- if (!app) {
251277
- throw new InvalidInputError("No app id resolved for this project.");
251278
- }
251279
- const port = options.port === undefined ? undefined : Number(options.port);
251280
- if (port !== undefined && !Number.isInteger(port)) {
251281
- throw new InvalidInputError(`--port must be a whole number: ${options.port}`);
251282
- }
251283
- const { project } = await readProjectConfig(app.projectRoot);
251284
- const site = project.site;
251285
- if (!site) {
251286
- throw new InvalidInputError(`This project has no 'site' block in base44/config.jsonc, so there is no frontend to serve. Add one; inside it serveCommand defaults to "npm run dev".`);
251287
- }
251288
- const serveCommand = site.serveCommand ?? DEFAULT_SERVE_COMMAND;
251289
- const command = withServeAddress(serveCommand, {
251290
- host: options.host,
251291
- port,
251292
- hostFlag: site.devHostFlag
251293
- });
251294
- if ((options.host || port !== undefined) && !forwardsServeAddress(serveCommand)) {
251295
- log.warn(`serveCommand '${serveCommand}' is not an 'npm run' invocation, so --host/--port were not passed to it. Put the address in serveCommand itself.`);
251296
- }
251297
- const runner = createServeCommandRunner({
251298
- serveCommand: command,
251299
- projectRoot: project.root,
251300
- appId: app.id,
251301
- appBaseUrl: options.backendUrl
251302
- });
251303
- stopRunnerOnProcessSignals(runner);
251304
- runner.onExit((code) => process.exit(code ?? 1));
251305
- runner.start();
251306
- return {
251307
- outroMessage: `Frontend dev server running '${command}' against ${theme.styles.bold(options.backendUrl)}`
251308
- };
251309
- }
251310
- function getSiteDevCommand() {
251311
- return new Base44Command("dev", { requireAuth: false }).description("Run the site's dev server against a given backend (no local backend)").requiredOption("--backend-url <url>", "Backend the frontend should call, injected as VITE_BASE44_APP_BASE_URL").option("--host <address>", "Address to bind, e.g. 0.0.0.0").option("--port <number>", "Port to bind").action(siteDevAction);
251312
- }
251313
-
251314
251498
  // src/cli/commands/site/open.ts
251315
251499
  async function openAction({
251316
251500
  isNonInteractive
@@ -251327,7 +251511,7 @@ function getSiteOpenCommand() {
251327
251511
 
251328
251512
  // src/cli/commands/site/index.ts
251329
251513
  function getSiteCommand() {
251330
- return new Command2("site").description("Manage app site (frontend app)").addCommand(getSiteDeployCommand()).addCommand(getSiteDevCommand()).addCommand(getSiteOpenCommand());
251514
+ return new Command2("site").description("Manage app site (frontend app)").addCommand(getSiteDeployCommand()).addCommand(getSiteOpenCommand());
251331
251515
  }
251332
251516
 
251333
251517
  // src/core/types/generator.ts
@@ -251419,10 +251603,10 @@ function toPascalCase(name) {
251419
251603
  return name.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
251420
251604
  }
251421
251605
  // src/core/types/update-project.ts
251422
- import { join as join30 } from "node:path";
251606
+ import { join as join33 } from "node:path";
251423
251607
  var TYPES_INCLUDE_PATH = `${PROJECT_SUBDIR}/${TYPES_OUTPUT_SUBDIR}/*.d.ts`;
251424
251608
  async function updateProjectConfig(projectRoot) {
251425
- const tsconfigPath = join30(projectRoot, "tsconfig.json");
251609
+ const tsconfigPath = join33(projectRoot, "tsconfig.json");
251426
251610
  if (!await pathExists(tsconfigPath)) {
251427
251611
  return false;
251428
251612
  }
@@ -251471,6 +251655,59 @@ function getTypesCommand() {
251471
251655
  return new Command2("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
251472
251656
  }
251473
251657
 
251658
+ // src/cli/commands/versions/create.ts
251659
+ async function createAction2(ctx, options) {
251660
+ const { runTask, jsonMode } = ctx;
251661
+ const target = await resolveBuildTarget(requireApp(ctx).projectRoot, {
251662
+ outputDir: options.outputDir
251663
+ });
251664
+ const gitHash = await resolveProvenanceCommit(target.root, options.gitHash);
251665
+ const version = await runTask("Creating version...", async (updateMessage) => await createVersion(await collectArtifacts(target), {
251666
+ sourceCommit: gitHash,
251667
+ concurrency: options.concurrency,
251668
+ progress: {
251669
+ onDeclared: ({ fileCount }) => updateMessage(`Uploading ${fileCount} files`),
251670
+ onUpload: ({ uploadedFiles, totalFiles }) => updateMessage(`Uploaded ${uploadedFiles} of ${totalFiles} files`)
251671
+ }
251672
+ }), {
251673
+ successMessage: "Version created",
251674
+ errorMessage: "Create version failed"
251675
+ });
251676
+ return {
251677
+ outroMessage: `Version ${version.versionId} (${version.manifestHash})`,
251678
+ stdout: jsonMode ? `${JSON.stringify(version, null, 2)}
251679
+ ` : undefined
251680
+ };
251681
+ }
251682
+ function getVersionCreateCommand() {
251683
+ return new Base44Command("create").description("Record the built output as a version, without deploying it").addOption(outputDirOption()).addOption(gitHashOption()).addOption(concurrencyOption()).action(createAction2);
251684
+ }
251685
+
251686
+ // src/cli/commands/versions/deploy.ts
251687
+ import { randomUUID as randomUUID5 } from "node:crypto";
251688
+ async function deployAction3({ runTask, jsonMode }, versionId, options) {
251689
+ const environment = options.target ?? DEFAULT_ENVIRONMENT;
251690
+ const result = await runTask(`Pointing ${environment} at ${versionId}...`, async () => await setEnvironmentVersion(environment, versionId, {
251691
+ idempotencyKey: randomUUID5()
251692
+ }), {
251693
+ successMessage: "Environment updated",
251694
+ errorMessage: "Could not update the environment"
251695
+ });
251696
+ return {
251697
+ outroMessage: `${result.name} now serves ${result.versionId}`,
251698
+ stdout: jsonMode ? `${JSON.stringify(result, null, 2)}
251699
+ ` : undefined
251700
+ };
251701
+ }
251702
+ function getVersionDeployCommand() {
251703
+ return new Base44Command("deploy").description("Point an environment at an already-recorded version (also the rollback)").argument("<version-id>", "The version to serve").addOption(targetOption()).action(deployAction3);
251704
+ }
251705
+
251706
+ // src/cli/commands/versions/index.ts
251707
+ function getVersionsCommand() {
251708
+ return new Command2("versions").description("Record app versions and serve them").addCommand(getVersionCreateCommand()).addCommand(getVersionDeployCommand());
251709
+ }
251710
+
251474
251711
  // src/core/resources/workflow/schema.ts
251475
251712
  var WorkflowRunStatusSchema = _enum([
251476
251713
  "running",
@@ -251847,10 +252084,47 @@ function getWorkspaceCommand() {
251847
252084
  return new Command2("workspace").description("List workspaces, inspect one, and move apps between them").addCommand(getWorkspaceListCommand()).addCommand(getWorkspaceGetCommand()).addCommand(getWorkspaceMoveCommand());
251848
252085
  }
251849
252086
 
252087
+ // src/cli/dev/createDevLogger.ts
252088
+ var colorByType = {
252089
+ error: theme.styles.error,
252090
+ warn: theme.styles.warn,
252091
+ log: (input) => input
252092
+ };
252093
+ var stringify = (item) => {
252094
+ if (typeof item === "string") {
252095
+ return item;
252096
+ }
252097
+ if (item instanceof Error) {
252098
+ return item.toString();
252099
+ }
252100
+ try {
252101
+ return JSON.stringify(item, null, 2) ?? String(item);
252102
+ } catch {
252103
+ return String(item);
252104
+ }
252105
+ };
252106
+ function createDevLogger(label, labelColor = theme.styles.dim) {
252107
+ const prefix = label ? `${labelColor(`[${label}]`)} ` : "";
252108
+ const print = (type, ...args) => {
252109
+ const colorize = colorByType[type];
252110
+ console[type](prefix + args.map((item) => colorize(stringify(item))).join(" "));
252111
+ };
252112
+ return {
252113
+ log: (...args) => print("log", ...args),
252114
+ error: (msg, err) => {
252115
+ print("error", msg);
252116
+ if (err) {
252117
+ print("error", err);
252118
+ }
252119
+ },
252120
+ warn: (...args) => print("warn", ...args)
252121
+ };
252122
+ }
252123
+
251850
252124
  // src/cli/dev/dev-server/main.ts
251851
252125
  var import_cors = __toESM(require_lib4(), 1);
251852
252126
  var import_express6 = __toESM(require_express(), 1);
251853
- import { dirname as dirname26, join as join36 } from "node:path";
252127
+ import { dirname as dirname27, join as join38 } from "node:path";
251854
252128
 
251855
252129
  // ../../node_modules/get-port/index.js
251856
252130
  import net from "node:net";
@@ -251979,8 +252253,8 @@ var $dir = async (options) => dirWithOptions(options);
251979
252253
  var $tmpName = promisify11(tmp.tmpName);
251980
252254
 
251981
252255
  // src/cli/dev/dev-server/function-manager.ts
251982
- import { spawn as spawn3 } from "node:child_process";
251983
- import { dirname as dirname23, join as join31 } from "node:path";
252256
+ import { spawn as spawn2 } from "node:child_process";
252257
+ import { dirname as dirname24, join as join34 } from "node:path";
251984
252258
  import { pathToFileURL } from "node:url";
251985
252259
 
251986
252260
  // src/cli/dev/dev-server/base-function-manager.ts
@@ -252077,7 +252351,7 @@ class FunctionManager extends BaseFunctionManager {
252077
252351
  async stopFunction(_name, { process: proc }) {
252078
252352
  const exited = new Promise((r) => proc.once("exit", () => r()));
252079
252353
  if (process.platform === "win32" && proc.pid) {
252080
- spawn3("taskkill", ["/pid", String(proc.pid), "/T", "/F"]);
252354
+ spawn2("taskkill", ["/pid", String(proc.pid), "/T", "/F"]);
252081
252355
  } else {
252082
252356
  proc.kill();
252083
252357
  }
@@ -252085,8 +252359,8 @@ class FunctionManager extends BaseFunctionManager {
252085
252359
  }
252086
252360
  spawnFunction(func, port) {
252087
252361
  this.logger.log(`Spawning function "${func.name}" on port ${port}`);
252088
- const importMapPath = join31(dirname23(this.wrapperPath), "import-map.json");
252089
- const process2 = spawn3("deno", ["run", "--allow-all", "--import-map", importMapPath, this.wrapperPath], {
252362
+ const importMapPath = join34(dirname24(this.wrapperPath), "import-map.json");
252363
+ const process2 = spawn2("deno", ["run", "--allow-all", "--import-map", importMapPath, this.wrapperPath], {
252090
252364
  env: {
252091
252365
  ...globalThis.process.env,
252092
252366
  FUNCTION_PATH: pathToFileURL(func.entryPath).href,
@@ -252159,7 +252433,7 @@ class FunctionManager extends BaseFunctionManager {
252159
252433
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
252160
252434
  import { isBuiltin } from "node:module";
252161
252435
  import { homedir as homedir3 } from "node:os";
252162
- import { join as join33 } from "node:path";
252436
+ import { join as join35 } from "node:path";
252163
252437
  import { pathToFileURL as pathToFileURL6 } from "node:url";
252164
252438
  var depsPromise;
252165
252439
  function loadDeps() {
@@ -252280,9 +252554,9 @@ export default {
252280
252554
  };
252281
252555
  `;
252282
252556
  function ensureBundlerConfig() {
252283
- const dir = join33(homedir3(), ".base44", "function-bundler");
252557
+ const dir = join35(homedir3(), ".base44", "function-bundler");
252284
252558
  mkdirSync2(dir, { recursive: true });
252285
- const configPath = join33(dir, "deno.json");
252559
+ const configPath = join35(dir, "deno.json");
252286
252560
  writeFileSync2(configPath, `${JSON.stringify({ nodeModulesDir: "auto" }, null, 2)}
252287
252561
  `);
252288
252562
  return configPath;
@@ -253663,11 +253937,11 @@ async function createEntityRoutes(db, logger, broadcast) {
253663
253937
  // src/cli/dev/dev-server/routes/integrations.ts
253664
253938
  var import_express5 = __toESM(require_express(), 1);
253665
253939
  var import_multer = __toESM(require_multer(), 1);
253666
- import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
253940
+ import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
253667
253941
  import fs28 from "node:fs";
253668
253942
  import path18 from "node:path";
253669
253943
  function createFileToken(fileUri) {
253670
- return createHash2("sha256").update(fileUri).digest("hex");
253944
+ return createHash3("sha256").update(fileUri).digest("hex");
253671
253945
  }
253672
253946
  function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger) {
253673
253947
  const router = import_express5.Router({ mergeParams: true });
@@ -253680,14 +253954,14 @@ function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger) {
253680
253954
  destination: mediaFilesDir,
253681
253955
  filename: (_req, file, cb) => {
253682
253956
  const ext = path18.extname(file.originalname);
253683
- cb(null, `${randomUUID4()}${ext}`);
253957
+ cb(null, `${randomUUID6()}${ext}`);
253684
253958
  }
253685
253959
  });
253686
253960
  const privateStorage = import_multer.default.diskStorage({
253687
253961
  destination: privateFilesDir,
253688
253962
  filename: (_req, file, cb) => {
253689
253963
  const ext = path18.extname(file.originalname);
253690
- cb(null, `${randomUUID4()}${ext}`);
253964
+ cb(null, `${randomUUID6()}${ext}`);
253691
253965
  }
253692
253966
  });
253693
253967
  const upload = import_multer.default({ storage, limits: { fileSize: MAX_FILE_SIZE } });
@@ -255549,8 +255823,8 @@ async function createDevServer(options) {
255549
255823
  broadcastEntityEvent(io, appId, entityName, event);
255550
255824
  };
255551
255825
  const base44ConfigWatcher = new WatchBase44({
255552
- functions: join36(dirname26(project.configPath), project.functionsDir),
255553
- entities: join36(dirname26(project.configPath), project.entitiesDir)
255826
+ functions: join38(dirname27(project.configPath), project.functionsDir),
255827
+ entities: join38(dirname27(project.configPath), project.entitiesDir)
255554
255828
  }, devLogger);
255555
255829
  base44ConfigWatcher.on("change", async (name) => {
255556
255830
  try {
@@ -255616,6 +255890,127 @@ async function createDevServer(options) {
255616
255890
  return { port, server, shutdown };
255617
255891
  }
255618
255892
 
255893
+ // src/cli/dev/dev-server/serve-runner.ts
255894
+ import { spawn as spawn3 } from "node:child_process";
255895
+ import process23 from "node:process";
255896
+
255897
+ class ServeRunner {
255898
+ command;
255899
+ cwd;
255900
+ env;
255901
+ logger;
255902
+ child;
255903
+ stopping = false;
255904
+ stopPromise;
255905
+ exitListeners = [];
255906
+ constructor(options) {
255907
+ this.command = options.command;
255908
+ this.cwd = options.cwd;
255909
+ this.env = options.env;
255910
+ this.logger = options.logger;
255911
+ }
255912
+ start() {
255913
+ if (this.child) {
255914
+ return;
255915
+ }
255916
+ const stdin = process23.platform === "win32" ? "ignore" : "inherit";
255917
+ const child = spawn3(this.command, {
255918
+ cwd: this.cwd,
255919
+ shell: true,
255920
+ detached: process23.platform !== "win32",
255921
+ env: { ...process23.env, ...this.env },
255922
+ stdio: [stdin, "pipe", "pipe"],
255923
+ windowsHide: true
255924
+ });
255925
+ this.child = child;
255926
+ this.setupHandlers(child);
255927
+ }
255928
+ onExit(listener) {
255929
+ this.exitListeners.push(listener);
255930
+ }
255931
+ async stop() {
255932
+ if (this.stopPromise) {
255933
+ return this.stopPromise;
255934
+ }
255935
+ this.stopPromise = this.stopChild();
255936
+ return this.stopPromise;
255937
+ }
255938
+ async stopChild() {
255939
+ const child = this.child;
255940
+ if (!child || child.exitCode !== null) {
255941
+ return;
255942
+ }
255943
+ this.stopping = true;
255944
+ const exited = new Promise((resolve) => child.once("exit", () => resolve()));
255945
+ if (process23.platform === "win32" && child.pid) {
255946
+ const taskkill = spawn3("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
255947
+ stdio: "ignore",
255948
+ windowsHide: true
255949
+ });
255950
+ await new Promise((resolve) => {
255951
+ taskkill.once("exit", () => resolve());
255952
+ taskkill.once("error", () => resolve());
255953
+ });
255954
+ } else if (child.pid) {
255955
+ try {
255956
+ process23.kill(-child.pid, "SIGTERM");
255957
+ } catch {
255958
+ child.kill();
255959
+ }
255960
+ }
255961
+ await exited;
255962
+ }
255963
+ setupHandlers(child) {
255964
+ child.stdout?.on("data", (data) => this.emitLines(data, "log"));
255965
+ child.stderr?.on("data", (data) => this.emitLines(data, "error"));
255966
+ child.on("error", (error) => {
255967
+ this.logger.error("Frontend dev server failed to start:", error);
255968
+ this.notifyExit(null);
255969
+ });
255970
+ child.on("exit", (code) => {
255971
+ if (this.stopping) {
255972
+ return;
255973
+ }
255974
+ this.logger.error(`Frontend dev server exited with code ${code}`);
255975
+ this.notifyExit(code);
255976
+ });
255977
+ }
255978
+ notifyExit(code) {
255979
+ for (const listener of this.exitListeners) {
255980
+ listener(code);
255981
+ }
255982
+ }
255983
+ emitLines(data, type) {
255984
+ const lines = data.toString().trimEnd().split(`
255985
+ `);
255986
+ for (const line of lines) {
255987
+ if (type === "error") {
255988
+ this.logger.error(line);
255989
+ } else {
255990
+ this.logger.log(line);
255991
+ }
255992
+ }
255993
+ }
255994
+ }
255995
+
255996
+ // src/cli/dev/serve-command-runner.ts
255997
+ function createServeCommandRunner({
255998
+ serveCommand,
255999
+ projectRoot,
256000
+ appId,
256001
+ appBaseUrl
256002
+ }) {
256003
+ return new ServeRunner({
256004
+ command: serveCommand,
256005
+ cwd: projectRoot,
256006
+ env: {
256007
+ VITE_BASE44_APP_ID: appId,
256008
+ VITE_BASE44_APP_BASE_URL: appBaseUrl
256009
+ },
256010
+ logger: createDevLogger("frontend", theme.colors.base44Orange)
256011
+ });
256012
+ }
256013
+
255619
256014
  // src/cli/commands/dev.ts
255620
256015
  function localServerUrl(port) {
255621
256016
  return `http://localhost:${port}`;
@@ -255641,6 +256036,11 @@ async function resolveConfiguredSite(app) {
255641
256036
  const serveCommand = project.site?.serveCommand;
255642
256037
  return serveCommand ? { serveCommand, projectRoot: project.root } : undefined;
255643
256038
  }
256039
+ function stopRunnerOnProcessSignals(runner) {
256040
+ const stop = () => void runner.stop();
256041
+ process.on("SIGINT", stop);
256042
+ process.on("SIGTERM", stop);
256043
+ }
255644
256044
  function startServeCommand(runner, backend) {
255645
256045
  stopRunnerOnProcessSignals(runner);
255646
256046
  runner.onExit(() => {
@@ -255821,7 +256221,7 @@ Examples:
255821
256221
  }
255822
256222
 
255823
256223
  // src/cli/commands/project/eject.ts
255824
- import { resolve as resolve17 } from "node:path";
256224
+ import { resolve as resolve19 } from "node:path";
255825
256225
  var import_kebabCase2 = __toESM(require_kebabCase(), 1);
255826
256226
  async function eject(ctx, options, command) {
255827
256227
  const { log, runTask, isNonInteractive } = ctx;
@@ -255885,7 +256285,7 @@ async function eject(ctx, options, command) {
255885
256285
  Ne("Operation cancelled.");
255886
256286
  throw new CLIExitError(0);
255887
256287
  }
255888
- const resolvedPath = resolve17(selectedPath);
256288
+ const resolvedPath = resolve19(selectedPath);
255889
256289
  await runTask("Downloading your project's code...", async (updateMessage) => {
255890
256290
  await createProjectFilesForExistingProject({
255891
256291
  projectId,
@@ -255903,17 +256303,22 @@ async function eject(ctx, options, command) {
255903
256303
  errorMessage: "Failed to pull project"
255904
256304
  });
255905
256305
  const { project } = await readProjectConfig(resolvedPath);
255906
- const installCommand = project.site?.installCommand;
255907
- const buildCommand = project.site?.buildCommand;
255908
- if (installCommand && buildCommand) {
256306
+ const site = project.site;
256307
+ if (site) {
255909
256308
  const shouldDeploy = options.yes ? true : await Re({
255910
256309
  message: "Would you like to deploy your project now?"
255911
256310
  });
255912
256311
  if (!Ct(shouldDeploy) && shouldDeploy) {
255913
256312
  await runTask("Installing dependencies...", async (updateMessage) => {
255914
- await execa({ cwd: resolvedPath, shell: true })`${installCommand}`;
256313
+ await execa({
256314
+ cwd: resolvedPath,
256315
+ shell: true
256316
+ })`${site.installCommand}`;
255915
256317
  updateMessage("Building project...");
255916
- await execa({ cwd: resolvedPath, shell: true })`${buildCommand}`;
256318
+ await execa({
256319
+ cwd: resolvedPath,
256320
+ shell: true
256321
+ })`${site.buildCommand}`;
255917
256322
  }, {
255918
256323
  successMessage: theme.colors.base44Orange("Project built successfully"),
255919
256324
  errorMessage: "Failed to build project"
@@ -255951,7 +256356,6 @@ function createProgram(context) {
255951
256356
  program.addCommand(getCreateCommand());
255952
256357
  program.addCommand(getScaffoldCommand());
255953
256358
  program.addCommand(getDashboardCommand());
255954
- program.addCommand(getInstallCommand());
255955
256359
  program.addCommand(getBuildCommand());
255956
256360
  program.addCommand(getDeployCommand3());
255957
256361
  program.addCommand(getVisibilityCommand());
@@ -255970,6 +256374,10 @@ function createProgram(context) {
255970
256374
  program.addCommand(getBranchesCommand());
255971
256375
  program.addCommand(getAuthCommand());
255972
256376
  program.addCommand(getSiteCommand());
256377
+ if (versionsApiEnabled()) {
256378
+ program.addCommand(getPublishCommand());
256379
+ program.addCommand(getVersionsCommand());
256380
+ }
255973
256381
  program.addCommand(getTypesCommand());
255974
256382
  program.addCommand(getExecCommand());
255975
256383
  program.addCommand(getDevCommand());
@@ -255982,7 +256390,7 @@ var import_detect_agent = __toESM(require_dist5(), 1);
255982
256390
  import { release, type } from "node:os";
255983
256391
 
255984
256392
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
255985
- import { dirname as dirname27, posix, sep as sep2 } from "path";
256393
+ import { dirname as dirname28, posix, sep as sep2 } from "path";
255986
256394
  function createModulerModifier() {
255987
256395
  const getModuleFromFileName = createGetModuleFromFilename();
255988
256396
  return async (frames) => {
@@ -255991,7 +256399,7 @@ function createModulerModifier() {
255991
256399
  return frames;
255992
256400
  };
255993
256401
  }
255994
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname27(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
256402
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname28(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
255995
256403
  const normalizedBase = isWindows ? normalizeWindowsPath2(basePath) : basePath;
255996
256404
  return (filename) => {
255997
256405
  if (!filename)
@@ -259980,9 +260388,9 @@ function addCommandInfoToErrorReporter(program, errorReporter) {
259980
260388
  });
259981
260389
  }
259982
260390
  // src/cli/index.ts
259983
- var __dirname4 = dirname28(fileURLToPath6(import.meta.url));
260391
+ var __dirname4 = dirname29(fileURLToPath6(import.meta.url));
259984
260392
  async function runCLI(options) {
259985
- ensureNpmAssets(join37(__dirname4, "../assets"));
260393
+ ensureNpmAssets(join39(__dirname4, "../assets"));
259986
260394
  const errorReporter = new ErrorReporter;
259987
260395
  errorReporter.registerProcessErrorHandlers();
259988
260396
  const jsonMode = process.argv.includes("--json");
@@ -260021,4 +260429,4 @@ export {
260021
260429
  runCLI
260022
260430
  };
260023
260431
 
260024
- //# debugId=4448173CB414506864756E2164756E21
260432
+ //# debugId=53FA3E8A10325F7E64756E2164756E21