@base44-preview/cli 0.1.25-pr.649.7ebc862 → 0.1.25-pr.650.2da78af

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -236708,70 +236708,8 @@ async function getSiteUrl() {
236708
236708
  return result.data.url;
236709
236709
  }
236710
236710
  // src/core/project/config.ts
236711
- import { existsSync } from "node:fs";
236712
236711
  import { dirname as dirname10, join as join12 } from "node:path";
236713
236712
 
236714
- // src/core/project/fallback.ts
236715
- var DEFAULT_SITE = {
236716
- installCommand: "npm install",
236717
- buildCommand: "npm run build",
236718
- serveCommand: "npm run dev",
236719
- outputDirectory: "./dist"
236720
- };
236721
- var PLACEHOLDER_APP_NAME = "base44-app";
236722
- var warningHandler = () => {};
236723
- var warned = new Set;
236724
- function setConfigWarningHandler(handler) {
236725
- warningHandler = handler;
236726
- }
236727
- function warnConfigFallback(message) {
236728
- if (warned.has(message)) {
236729
- return;
236730
- }
236731
- warned.add(message);
236732
- warningHandler(message);
236733
- }
236734
- function defaultProjectConfig() {
236735
- return ProjectConfigSchema.parse({
236736
- name: PLACEHOLDER_APP_NAME,
236737
- site: DEFAULT_SITE
236738
- });
236739
- }
236740
- function salvageProjectConfig(raw, error) {
236741
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
236742
- return defaultProjectConfig();
236743
- }
236744
- const fixed = { ...raw };
236745
- for (const issue of error.issues) {
236746
- if (issue.path.length === 0) {
236747
- return defaultProjectConfig();
236748
- }
236749
- const [key, field] = issue.path.map(String);
236750
- if (key === "name") {
236751
- fixed.name = PLACEHOLDER_APP_NAME;
236752
- } else if (key === "site") {
236753
- fixed.site = field !== undefined && isPlainObject2(fixed.site) ? withoutKey(fixed.site, field) : DEFAULT_SITE;
236754
- } else {
236755
- fixed[key] = undefined;
236756
- }
236757
- }
236758
- const result = ProjectConfigSchema.safeParse(fixed);
236759
- return result.success ? result.data : defaultProjectConfig();
236760
- }
236761
- function siteOrDefault(project) {
236762
- if (project.site) {
236763
- return project.site;
236764
- }
236765
- warnConfigFallback(`${project.configPath} has no 'site' block; using the default site commands.`);
236766
- return DEFAULT_SITE;
236767
- }
236768
- function withoutKey(record, key) {
236769
- return Object.fromEntries(Object.entries(record).filter(([k]) => k !== key));
236770
- }
236771
- function isPlainObject2(value) {
236772
- return typeof value === "object" && value !== null && !Array.isArray(value);
236773
- }
236774
-
236775
236713
  // src/core/project/plugins.ts
236776
236714
  import { createRequire as createRequire2 } from "node:module";
236777
236715
  import { dirname as dirname5, isAbsolute as isAbsolute2, join as join4, resolve } from "node:path";
@@ -239130,17 +239068,10 @@ async function openLogStream(filters) {
239130
239068
  class ProjectConfigReader {
239131
239069
  pluginSourceByNamespace = new Map;
239132
239070
  async readProjectSettings(projectRoot) {
239133
- const found = this.findConfig(projectRoot);
239134
- if (!found) {
239135
- return this.defaultSettingsOrThrow(projectRoot);
239136
- }
239137
- const { root, configPath } = found;
239138
- const project = await this.readConfigFileOrDefaults(configPath);
239139
- return {
239140
- ...this.withoutPluginsInPluginProject(project, configPath),
239141
- root,
239142
- configPath
239143
- };
239071
+ const { root, configPath } = await this.findConfigOrThrow(projectRoot);
239072
+ const project = await this.readConfigFile(configPath);
239073
+ this.assertPluginProjectDoesNotLoadPlugins(project, configPath);
239074
+ return { ...project, root, configPath };
239144
239075
  }
239145
239076
  async readProjectConfig(projectRoot) {
239146
239077
  const project = await this.readProjectSettings(projectRoot);
@@ -239170,37 +239101,26 @@ class ProjectConfigReader {
239170
239101
  authConfig: localResources.authConfig
239171
239102
  };
239172
239103
  }
239173
- findConfig(projectRoot) {
239174
- if (!projectRoot) {
239175
- return findProjectRoot();
239104
+ async findConfigOrThrow(projectRoot) {
239105
+ let found;
239106
+ if (projectRoot) {
239107
+ const configPath = findConfigInDir(projectRoot);
239108
+ found = configPath ? { root: projectRoot, configPath } : null;
239109
+ } else {
239110
+ found = findProjectRoot();
239176
239111
  }
239177
- const configPath = findConfigInDir(projectRoot);
239178
- return configPath ? { root: projectRoot, configPath } : null;
239179
- }
239180
- defaultSettingsOrThrow(projectRoot) {
239181
- const root = projectRoot ?? process.cwd();
239182
- if (!existsSync(join12(root, "package.json"))) {
239112
+ if (!found) {
239183
239113
  throw new ConfigNotFoundError(`Project root not found. Please ensure config.jsonc or config.json exists in the project directory or ${PROJECT_SUBDIR}/ subdirectory.`);
239184
239114
  }
239185
- const configPath = join12(root, PROJECT_SUBDIR, "config.jsonc");
239186
- warnConfigFallback(`No ${PROJECT_SUBDIR}/config.jsonc found in ${root}; using the default project config.`);
239187
- return { ...defaultProjectConfig(), root, configPath };
239115
+ return found;
239188
239116
  }
239189
- async readConfigFileOrDefaults(configPath) {
239190
- let parsed;
239191
- try {
239192
- parsed = await readJsonFile(configPath);
239193
- } catch (error) {
239194
- warnConfigFallback(`${configPath} could not be read (${errorMessage(error)}); using the default project config.`);
239195
- return defaultProjectConfig();
239196
- }
239117
+ async readConfigFile(configPath) {
239118
+ const parsed = await readJsonFile(configPath);
239197
239119
  const result = ProjectConfigSchema.safeParse(parsed);
239198
- if (result.success) {
239199
- return result.data;
239120
+ if (!result.success) {
239121
+ throw new SchemaValidationError("Invalid project configuration", result.error, configPath);
239200
239122
  }
239201
- warnConfigFallback(`Invalid project configuration in ${configPath}; using defaults for the invalid fields:
239202
- ${prettifyError(result.error)}`);
239203
- return salvageProjectConfig(parsed, result.error);
239123
+ return result.data;
239204
239124
  }
239205
239125
  async readProjectResources(configPath, project, includeActors = true) {
239206
239126
  const configDir = dirname10(configPath);
@@ -239231,19 +239151,10 @@ ${prettifyError(result.error)}`);
239231
239151
  authConfig
239232
239152
  };
239233
239153
  }
239234
- async readPluginConfigFile(configPath) {
239235
- const result = ProjectConfigSchema.safeParse(await readJsonFile(configPath));
239236
- if (!result.success) {
239237
- throw new SchemaValidationError("Invalid project configuration", result.error, configPath);
239238
- }
239239
- return result.data;
239240
- }
239241
- withoutPluginsInPluginProject(project, configPath) {
239242
- if (!project.plugin || project.plugins.length === 0) {
239243
- return project;
239154
+ assertPluginProjectDoesNotLoadPlugins(project, configPath) {
239155
+ if (project.plugin && project.plugins.length > 0) {
239156
+ throw new ConfigInvalidError("Plugin projects cannot define plugins in this version.", configPath);
239244
239157
  }
239245
- warnConfigFallback(`${configPath}: plugin projects cannot define plugins in this version; ignoring 'plugins'.`);
239246
- return { ...project, plugins: [] };
239247
239158
  }
239248
239159
  registerPluginNamespace(namespace, source, configPath) {
239249
239160
  const existingSource = this.pluginSourceByNamespace.get(namespace);
@@ -239260,15 +239171,10 @@ ${prettifyError(result.error)}`);
239260
239171
  }
239261
239172
  async readPluginConfig(plugin, hostConfigPath) {
239262
239173
  const pluginRoot = resolvePluginRoot(plugin.source, dirname10(hostConfigPath));
239263
- const configPath = findConfigInDir(pluginRoot);
239264
- if (!configPath) {
239265
- throw new ConfigNotFoundError(`Project root not found. Please ensure config.jsonc or config.json exists in the project directory or ${PROJECT_SUBDIR}/ subdirectory.`);
239266
- }
239267
- const project = await this.readPluginConfigFile(configPath);
239174
+ const { configPath } = await this.findConfigOrThrow(pluginRoot);
239175
+ const project = await this.readConfigFile(configPath);
239268
239176
  const namespace = requirePluginNamespace(project, plugin.source, configPath);
239269
- if (project.plugins.length > 0) {
239270
- throw new ConfigInvalidError("Plugin projects cannot define plugins in this version.", configPath);
239271
- }
239177
+ this.assertPluginProjectDoesNotLoadPlugins(project, configPath);
239272
239178
  return { configPath, namespace, project, source: plugin.source };
239273
239179
  }
239274
239180
  async readPluginResources(project, configPath, namespace) {
@@ -239347,16 +239253,13 @@ async function readProjectSettings(projectRoot) {
239347
239253
  const reader = new ProjectConfigReader;
239348
239254
  return await reader.readProjectSettings(projectRoot);
239349
239255
  }
239350
- function errorMessage(error) {
239351
- return error instanceof Error ? error.message : String(error);
239352
- }
239353
239256
  // src/core/project/template.ts
239354
239257
  var import_ejs = __toESM(require_ejs(), 1);
239355
239258
  var import_front_matter2 = __toESM(require_front_matter(), 1);
239356
239259
  import { dirname as dirname11, join as join14 } from "node:path";
239357
239260
 
239358
239261
  // src/core/assets.ts
239359
- import { cpSync, existsSync as existsSync2 } from "node:fs";
239262
+ import { cpSync, existsSync } from "node:fs";
239360
239263
  import { homedir as homedir2 } from "node:os";
239361
239264
  import { join as join13 } from "node:path";
239362
239265
  // package.json
@@ -239458,6 +239361,7 @@ var package_default = {
239458
239361
  node: ">=20.19.0"
239459
239362
  },
239460
239363
  dependencies: {
239364
+ "@base44/functions-compiler": "0.1.3",
239461
239365
  "@deno/loader": "https://npm.jsr.io/~/11/@jsr/deno__loader/0.5.0.tgz",
239462
239366
  esbuild: "0.28.0",
239463
239367
  miniflare: "4.20260722.0"
@@ -239482,9 +239386,9 @@ function getExecWrapperPath() {
239482
239386
  return join13(getBackendRuntimeDir(), "exec.ts");
239483
239387
  }
239484
239388
  function ensureNpmAssets(sourceDir) {
239485
- if (existsSync2(ASSETS_DIR) && existsSync2(getBackendRuntimeDir()))
239389
+ if (existsSync(ASSETS_DIR) && existsSync(getBackendRuntimeDir()))
239486
239390
  return;
239487
- if (!existsSync2(sourceDir))
239391
+ if (!existsSync(sourceDir))
239488
239392
  return;
239489
239393
  cpSync(sourceDir, ASSETS_DIR, { recursive: true });
239490
239394
  }
@@ -240228,10 +240132,12 @@ async function uploadPresignedAsset(upload, assets) {
240228
240132
  await putPresigned(upload, file.absolutePath);
240229
240133
  }
240230
240134
  async function putPresigned(upload, absolutePath) {
240231
- const content = await readFile2(absolutePath);
240135
+ await putPresignedBody(upload, new Uint8Array(await readFile2(absolutePath)));
240136
+ }
240137
+ async function putPresignedBody(upload, body) {
240232
240138
  try {
240233
240139
  await distribution_default.put(upload.url, {
240234
- body: new Uint8Array(content),
240140
+ body,
240235
240141
  headers: {
240236
240142
  "Content-Type": upload.contentType,
240237
240143
  ...upload.checksumSha256 ? { "x-amz-checksum-sha256": upload.checksumSha256 } : {}
@@ -240323,7 +240229,7 @@ function buildAssetsConfig(assetsConfig, progress) {
240323
240229
  };
240324
240230
  }
240325
240231
  // ../../node_modules/is-plain-obj/index.js
240326
- function isPlainObject3(value) {
240232
+ function isPlainObject2(value) {
240327
240233
  if (typeof value !== "object" || value === null) {
240328
240234
  return false;
240329
240235
  }
@@ -240347,7 +240253,7 @@ var normalizeFileUrl = (file) => file instanceof URL ? fileURLToPath2(file) : fi
240347
240253
  // ../../node_modules/execa/lib/methods/parameters.js
240348
240254
  var normalizeParameters = (rawFile, rawArguments = [], rawOptions = {}) => {
240349
240255
  const filePath = safeNormalizeFileUrl(rawFile, "First argument");
240350
- const [commandArguments, options] = isPlainObject3(rawArguments) ? [[], rawArguments] : [rawArguments, rawOptions];
240256
+ const [commandArguments, options] = isPlainObject2(rawArguments) ? [[], rawArguments] : [rawArguments, rawOptions];
240351
240257
  if (!Array.isArray(commandArguments)) {
240352
240258
  throw new TypeError(`Second argument must be either an array of arguments or an options object: ${commandArguments}`);
240353
240259
  }
@@ -240359,7 +240265,7 @@ var normalizeParameters = (rawFile, rawArguments = [], rawOptions = {}) => {
240359
240265
  if (nullByteArgument !== undefined) {
240360
240266
  throw new TypeError(`Arguments cannot contain null bytes ("\\0"): ${nullByteArgument}`);
240361
240267
  }
240362
- if (!isPlainObject3(options)) {
240268
+ if (!isPlainObject2(options)) {
240363
240269
  throw new TypeError(`Last argument must be an options object: ${options}`);
240364
240270
  }
240365
240271
  return [filePath, normalizedArguments, options];
@@ -240496,7 +240402,7 @@ var parseExpression = (expression) => {
240496
240402
  if (typeOfExpression === "number") {
240497
240403
  return String(expression);
240498
240404
  }
240499
- if (isPlainObject3(expression) && (("stdout" in expression) || ("isMaxBuffer" in expression))) {
240405
+ if (isPlainObject2(expression) && (("stdout" in expression) || ("isMaxBuffer" in expression))) {
240500
240406
  return getSubprocessResult(expression);
240501
240407
  }
240502
240408
  if (expression instanceof ChildProcess || Object.prototype.toString.call(expression) === "[object Promise]") {
@@ -240544,7 +240450,7 @@ var normalizeFdSpecificOption = (options, optionName) => {
240544
240450
  return addDefaultValue(optionArray, optionName);
240545
240451
  };
240546
240452
  var getStdioLength = ({ stdio }) => Array.isArray(stdio) ? Math.max(stdio.length, STANDARD_STREAMS_ALIASES.length) : STANDARD_STREAMS_ALIASES.length;
240547
- var normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject3(optionValue) ? normalizeOptionObject(optionValue, optionArray, optionName) : optionArray.fill(optionValue);
240453
+ var normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject2(optionValue) ? normalizeOptionObject(optionValue, optionArray, optionName) : optionArray.fill(optionValue);
240548
240454
  var normalizeOptionObject = (optionValue, optionArray, optionName) => {
240549
240455
  for (const fdName of Object.keys(optionValue).sort(compareFdName)) {
240550
240456
  for (const fdNumber of parseFdName(fdName, optionName, optionArray)) {
@@ -243620,10 +243526,10 @@ var checkBooleanOption = (value, optionName) => {
243620
243526
  var isGenerator = (value) => isAsyncGenerator(value) || isSyncGenerator(value);
243621
243527
  var isAsyncGenerator = (value) => Object.prototype.toString.call(value) === "[object AsyncGeneratorFunction]";
243622
243528
  var isSyncGenerator = (value) => Object.prototype.toString.call(value) === "[object GeneratorFunction]";
243623
- var isTransformOptions = (value) => isPlainObject3(value) && (value.transform !== undefined || value.final !== undefined);
243529
+ var isTransformOptions = (value) => isPlainObject2(value) && (value.transform !== undefined || value.final !== undefined);
243624
243530
  var isUrl = (value) => Object.prototype.toString.call(value) === "[object URL]";
243625
243531
  var isRegularUrl = (value) => isUrl(value) && value.protocol !== "file:";
243626
- var isFilePathObject = (value) => isPlainObject3(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => FILE_PATH_KEYS.has(key)) && isFilePathString(value.file);
243532
+ var isFilePathObject = (value) => isPlainObject2(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => FILE_PATH_KEYS.has(key)) && isFilePathString(value.file);
243627
243533
  var FILE_PATH_KEYS = new Set(["file", "append"]);
243628
243534
  var isFilePathString = (file) => typeof file === "string";
243629
243535
  var isUnknownStdioString = (type, value) => type === "native" && typeof value === "string" && !KNOWN_STDIO_STRINGS.has(value);
@@ -243740,7 +243646,7 @@ var normalizeDuplex = ({
243740
243646
  };
243741
243647
  };
243742
243648
  var normalizeTransformStream = ({ stdioItem, stdioItem: { value }, index, newTransforms, direction }) => {
243743
- const { transform, objectMode } = isPlainObject3(value) ? value : { transform: value };
243649
+ const { transform, objectMode } = isPlainObject2(value) ? value : { transform: value };
243744
243650
  const { writableObjectMode, readableObjectMode } = getTransformObjectModes(objectMode, index, newTransforms, direction);
243745
243651
  return {
243746
243652
  ...stdioItem,
@@ -243754,7 +243660,7 @@ var normalizeGenerator = ({ stdioItem, stdioItem: { value }, index, newTransform
243754
243660
  binary: binaryOption = false,
243755
243661
  preserveNewlines = false,
243756
243662
  objectMode
243757
- } = isPlainObject3(value) ? value : { transform: value };
243663
+ } = isPlainObject2(value) ? value : { transform: value };
243758
243664
  const binary = binaryOption || BINARY_ENCODINGS.has(encoding);
243759
243665
  const { writableObjectMode, readableObjectMode } = getTransformObjectModes(objectMode, index, newTransforms, direction);
243760
243666
  return {
@@ -245690,7 +245596,7 @@ var unpipeOnSignalAbort = async (unpipeSignal, { sourceStream, mergedStream, fil
245690
245596
 
245691
245597
  // ../../node_modules/execa/lib/pipe/setup.js
245692
245598
  var pipeToSubprocess = (sourceInfo, ...pipeArguments) => {
245693
- if (isPlainObject3(pipeArguments[0])) {
245599
+ if (isPlainObject2(pipeArguments[0])) {
245694
245600
  return pipeToSubprocess.bind(undefined, {
245695
245601
  ...sourceInfo,
245696
245602
  boundOptions: { ...sourceInfo.boundOptions, ...pipeArguments[0] }
@@ -246709,7 +246615,7 @@ var mergeOptions = (boundOptions, options) => {
246709
246615
  return { ...boundOptions, ...newOptions };
246710
246616
  };
246711
246617
  var mergeOption = (optionName, boundOptionValue, optionValue) => {
246712
- if (DEEP_OPTIONS.has(optionName) && isPlainObject3(boundOptionValue) && isPlainObject3(optionValue)) {
246618
+ if (DEEP_OPTIONS.has(optionName) && isPlainObject2(boundOptionValue) && isPlainObject2(optionValue)) {
246713
246619
  return { ...boundOptionValue, ...optionValue };
246714
246620
  }
246715
246621
  return optionValue;
@@ -246732,7 +246638,7 @@ var createExeca = (mapArguments, boundOptions, deepOptions, setBoundExeca) => {
246732
246638
  return boundExeca;
246733
246639
  };
246734
246640
  var callBoundExeca = ({ mapArguments, deepOptions = {}, boundOptions = {}, setBoundExeca, createNested }, firstArgument, ...nextArguments) => {
246735
- if (isPlainObject3(firstArgument)) {
246641
+ if (isPlainObject2(firstArgument)) {
246736
246642
  return createNested(mapArguments, mergeOptions(boundOptions, firstArgument), setBoundExeca);
246737
246643
  }
246738
246644
  const { file, commandArguments, options, isSync } = parseArguments({
@@ -246935,19 +246841,38 @@ async function deployAll(projectData, options) {
246935
246841
  }
246936
246842
  // src/core/project/target.ts
246937
246843
  import { dirname as dirname13, join as join19, resolve as resolve6 } from "node:path";
246844
+ var DEFAULT_BUILD_COMMAND = "npm run build";
246845
+ var DEFAULT_OUTPUT_DIRECTORY = "dist";
246938
246846
  async function resolveBuildTarget(projectRoot, overrides = {}) {
246939
246847
  const project = await readSettingsIfPresent(projectRoot);
246940
246848
  const root = project?.root ?? projectRoot ?? process.cwd();
246941
- const site = project ? siteOrDefault(project) : DEFAULT_SITE;
246942
246849
  return {
246943
246850
  root,
246944
246851
  configDir: project ? dirname13(project.configPath) : join19(root, PROJECT_SUBDIR),
246945
- buildCommand: site.buildCommand,
246946
- outputDir: resolve6(root, overrides.outputDir ?? site.outputDirectory ?? DEFAULT_SITE.outputDirectory),
246852
+ buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
246853
+ outputDir: outputDirectory(project, root, overrides.outputDir),
246947
246854
  entitiesDir: project?.entitiesDir ?? "entities",
246948
- agentsDir: project?.agentsDir ?? "agents"
246855
+ agentsDir: project?.agentsDir ?? "agents",
246856
+ functionsDir: project?.functionsDir ?? "functions"
246949
246857
  };
246950
246858
  }
246859
+ function outputDirectory(project, root, override) {
246860
+ const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
246861
+ return configured ? resolve6(root, configured) : null;
246862
+ }
246863
+ function requireOutputDir(target) {
246864
+ if (target.outputDir === null) {
246865
+ throw new ConfigNotFoundError("No site configuration found.", {
246866
+ hints: [
246867
+ {
246868
+ message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
246869
+ },
246870
+ { message: `Or pass --output-dir <dir>, relative to ${target.root}` }
246871
+ ]
246872
+ });
246873
+ }
246874
+ return target.outputDir;
246875
+ }
246951
246876
  async function readSettingsIfPresent(projectRoot) {
246952
246877
  try {
246953
246878
  return await readProjectSettings(projectRoot);
@@ -247476,7 +247401,6 @@ class Base44Command extends Command2 {
247476
247401
  }
247477
247402
  action(fn) {
247478
247403
  return super.action(async (...args) => {
247479
- setConfigWarningHandler((message) => this.context.log.warn(message));
247480
247404
  const jsonMode = this.context.jsonMode;
247481
247405
  const quiet = this.context.isNonInteractive || jsonMode;
247482
247406
  if (!quiet) {
@@ -249734,7 +249658,16 @@ function getFunctionsCommand() {
249734
249658
  }
249735
249659
 
249736
249660
  // src/cli/commands/project/site-build.ts
249737
- async function runSiteBuild({ runTask }, { root, buildCommand = DEFAULT_SITE.buildCommand, appId }) {
249661
+ async function runSiteBuild({ runTask }, { root, buildCommand, appId }) {
249662
+ if (!buildCommand) {
249663
+ throw new ConfigNotFoundError("No site build command found.", {
249664
+ hints: [
249665
+ {
249666
+ message: `Add a 'site' block to your config.jsonc (e.g., "site": { "buildCommand": "npm run build" }). Inside one, buildCommand defaults to "npm run build".`
249667
+ }
249668
+ ]
249669
+ });
249670
+ }
249738
249671
  await runTask("Building site...", () => execa({
249739
249672
  cwd: root,
249740
249673
  shell: true,
@@ -250758,6 +250691,15 @@ function declaredFile({ path, size, digest }) {
250758
250691
  function declaredModule(module) {
250759
250692
  return { ...declaredFile(module), type: module.type };
250760
250693
  }
250694
+ function declaredBundle(bundle) {
250695
+ return {
250696
+ module: { size: bundle.size, digest: bundle.digest },
250697
+ functions: bundle.functions,
250698
+ runtime_secrets: bundle.runtimeSecrets,
250699
+ post_response_telemetry: bundle.postResponseTelemetry,
250700
+ static_egress_artifact: bundle.staticEgressArtifact
250701
+ };
250702
+ }
250761
250703
  function declaredServingConfig(config) {
250762
250704
  const stated = {
250763
250705
  html_handling: config?.htmlHandling ?? null,
@@ -250811,6 +250753,7 @@ async function createVersion(artifacts, options = {}) {
250811
250753
  serving_config: declaredServingConfig(artifacts.siteWorker.servingConfig)
250812
250754
  }
250813
250755
  } : {},
250756
+ backend_bundles: artifacts.backendBundles.map(declaredBundle),
250814
250757
  entities: artifacts.entities,
250815
250758
  agents: artifacts.agents,
250816
250759
  source_commit: options.sourceCommit
@@ -250819,17 +250762,22 @@ async function createVersion(artifacts, options = {}) {
250819
250762
  ...artifacts.assets,
250820
250763
  ...artifacts.siteWorker?.modules ?? []
250821
250764
  ];
250822
- options.progress?.onDeclared?.({ fileCount: declaredFiles.length });
250823
- if (declared.uploads.length !== declaredFiles.length) {
250824
- throw new InternalError(`Declared ${declaredFiles.length} files but the server signed ${declared.uploads.length} upload URLs.`);
250765
+ const slotCount = declaredFiles.length + artifacts.backendBundles.length;
250766
+ options.progress?.onDeclared?.({ fileCount: slotCount });
250767
+ if (declared.uploads.length !== slotCount) {
250768
+ throw new InternalError(`Declared ${slotCount} files but the server signed ${declared.uploads.length} upload URLs.`);
250825
250769
  }
250826
- const drifted = declared.uploads.findIndex((upload, index) => upload.path !== declaredFiles[index].path);
250770
+ const drifted = declaredFiles.findIndex((file, index) => declared.uploads[index].path !== file.path);
250827
250771
  if (drifted !== -1) {
250828
250772
  throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
250829
250773
  }
250830
250774
  let uploadedFiles = 0;
250831
250775
  await pMap(declared.uploads, async (upload, index) => {
250832
- await putPresigned(upload, declaredFiles[index].absolutePath);
250776
+ if (index < declaredFiles.length) {
250777
+ await putPresigned(upload, declaredFiles[index].absolutePath);
250778
+ } else {
250779
+ await putPresignedBody(upload, artifacts.backendBundles[index - declaredFiles.length].module);
250780
+ }
250833
250781
  uploadedFiles++;
250834
250782
  options.progress?.onUpload?.({
250835
250783
  uploadedFiles,
@@ -250845,13 +250793,109 @@ async function setEnvironmentVersion(environment, versionId, options = {}) {
250845
250793
  }, "setting the environment's version", options.idempotencyKey ? KEYED_RETRY : undefined)).json(), "environment");
250846
250794
  }
250847
250795
  // src/core/version/artifacts.ts
250848
- import { createHash as createHash2 } from "node:crypto";
250796
+ import { createHash as createHash3 } from "node:crypto";
250849
250797
  import { join as join29, resolve as resolve13 } from "node:path";
250798
+
250799
+ // src/core/version/functions.ts
250800
+ import { createHash as createHash2 } from "node:crypto";
250801
+ import { relative as relative6 } from "node:path";
250802
+ var SHARD_POLICY = {
250803
+ shardSize: 100,
250804
+ globalShardSize: 100,
250805
+ maxShards: 1,
250806
+ gzipCapBytes: 9500000
250807
+ };
250808
+ var COMPILE_MODES = { runtimeSecrets: false, postResponseTelemetry: false };
250809
+ async function loadCompiler() {
250810
+ try {
250811
+ return await import("@base44/functions-compiler");
250812
+ } catch (error) {
250813
+ throw new DependencyNotFoundError("Backend functions cannot be compiled by this installation of the CLI.", {
250814
+ hints: [{ message: "Install the CLI from npm: npm install -g base44" }],
250815
+ cause: error instanceof Error ? error : undefined
250816
+ });
250817
+ }
250818
+ }
250819
+ function projectPath(root, absolutePath) {
250820
+ return relative6(root, absolutePath).split(/[/\\]/).join("/");
250821
+ }
250822
+ async function compilerInput(compiler, root, fn) {
250823
+ const backendFiles = {};
250824
+ for (const filePath of fn.filePaths) {
250825
+ backendFiles[projectPath(root, filePath)] = await readTextFile(filePath);
250826
+ }
250827
+ const { entry, files } = await compiler.cfwBundleInput(projectPath(root, fn.entryPath), await readTextFile(fn.entryPath), backendFiles);
250828
+ return { name: fn.name, entry, files };
250829
+ }
250830
+ function describeFailure(failure) {
250831
+ const where = failure.function ? `${failure.function}: ` : "";
250832
+ const errors = (failure.errors ?? []).map((e) => e.file ? `${e.file}:${e.line ?? 0} ${e.message}` : e.message);
250833
+ return [`${where}${failure.message}`, ...errors].join(`
250834
+ `);
250835
+ }
250836
+ function sha256(bytes) {
250837
+ return `sha256:${createHash2("sha256").update(bytes).digest("hex")}`;
250838
+ }
250839
+ async function compileBackendBundles(root, functionsDir) {
250840
+ const functions = await readAllFunctions(functionsDir);
250841
+ if (functions.length === 0) {
250842
+ return [];
250843
+ }
250844
+ const compiler = await loadCompiler();
250845
+ const sorted = [...functions].sort((a, b) => a.name < b.name ? -1 : 1);
250846
+ const inputs = await pMap(sorted, (fn) => compilerInput(compiler, root, fn), {
250847
+ concurrency: 8
250848
+ });
250849
+ const entries = new Map(inputs.map((input) => [input.name, input.entry]));
250850
+ const built = await compiler.compileFunctionShards(inputs, SHARD_POLICY, COMPILE_MODES);
250851
+ if (!built.ok) {
250852
+ throw new InvalidInputError(`Backend functions failed to compile (${built.failures.length} error${built.failures.length === 1 ? "" : "s"}).`, { details: built.failures.map(describeFailure) });
250853
+ }
250854
+ return built.shards.map((shard) => {
250855
+ const module = new TextEncoder().encode(shard.module);
250856
+ return {
250857
+ module,
250858
+ size: module.byteLength,
250859
+ digest: sha256(module),
250860
+ functions: shard.functions.map((name) => ({
250861
+ name,
250862
+ entry: entries.get(name)
250863
+ })),
250864
+ ...COMPILE_MODES,
250865
+ staticEgressArtifact: compiler.STATIC_EGRESS_ARTIFACT_MARKER
250866
+ };
250867
+ });
250868
+ }
250869
+
250870
+ // src/core/version/publish.ts
250871
+ import { randomUUID as randomUUID4 } from "node:crypto";
250872
+ var DEFAULT_ENVIRONMENT = "production";
250873
+ async function tagStep2(step, run) {
250874
+ return await tagStep(step, run);
250875
+ }
250876
+ async function publishVersion(artifacts, options = {}) {
250877
+ const version = await tagStep2("create_version", () => createVersion(artifacts, {
250878
+ sourceCommit: options.sourceCommit,
250879
+ concurrency: options.concurrency,
250880
+ progress: options.progress
250881
+ }));
250882
+ const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
250883
+ idempotencyKey: randomUUID4()
250884
+ }));
250885
+ return {
250886
+ environment: environment.name,
250887
+ versionId: environment.versionId,
250888
+ manifestHash: environment.manifestHash,
250889
+ deploymentId: environment.deploymentId
250890
+ };
250891
+ }
250892
+
250893
+ // src/core/version/artifacts.ts
250850
250894
  var MAX_FILE_COUNT = 50000;
250851
250895
  var HASH_CONCURRENCY = 32;
250852
250896
  var ENTRY2 = "index.html";
250853
250897
  async function digestFile(absolutePath) {
250854
- const hash = await hashFileInto(createHash2("sha256"), absolutePath);
250898
+ const hash = await hashFileInto(createHash3("sha256"), absolutePath);
250855
250899
  return `sha256:${hash.digest("hex")}`;
250856
250900
  }
250857
250901
  async function collectBuildOutput(outputDir, options = {}) {
@@ -250921,10 +250965,11 @@ async function collectArtifacts(target) {
250921
250965
  const built = await resolveFullStackBuild(target.root);
250922
250966
  const siteWorker = built ? await describeSiteWorker(built) : null;
250923
250967
  return {
250924
- assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(target.outputDir, {
250968
+ assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(requireOutputDir(target), {
250925
250969
  entryFile: ENTRY2
250926
250970
  }),
250927
250971
  ...siteWorker ? { siteWorker } : {},
250972
+ backendBundles: await tagStep2("build", () => compileBackendBundles(target.root, join29(target.configDir, target.functionsDir))),
250928
250973
  ...await collectResources(target.configDir, target)
250929
250974
  };
250930
250975
  }
@@ -250934,28 +250979,6 @@ function versionsApiEnabled(env = process.env) {
250934
250979
  const value = env[VERSIONS_API_ENV];
250935
250980
  return value === "1" || value === "true";
250936
250981
  }
250937
- // src/core/version/publish.ts
250938
- import { randomUUID as randomUUID4 } from "node:crypto";
250939
- var DEFAULT_ENVIRONMENT = "production";
250940
- async function tagStep2(step, run) {
250941
- return await tagStep(step, run);
250942
- }
250943
- async function publishVersion(artifacts, options = {}) {
250944
- const version = await tagStep2("create_version", () => createVersion(artifacts, {
250945
- sourceCommit: options.sourceCommit,
250946
- concurrency: options.concurrency,
250947
- progress: options.progress
250948
- }));
250949
- const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
250950
- idempotencyKey: randomUUID4()
250951
- }));
250952
- return {
250953
- environment: environment.name,
250954
- versionId: environment.versionId,
250955
- manifestHash: environment.manifestHash,
250956
- deploymentId: environment.deploymentId
250957
- };
250958
- }
250959
250982
  // src/cli/commands/versions/options.ts
250960
250983
  function outputDirOption() {
250961
250984
  return new Option2("--output-dir <dir>", "Build output directory (defaults to the project's, else dist)");
@@ -251525,6 +251548,15 @@ async function deployToDeploymentsApi(ctx, project, options) {
251525
251548
  }
251526
251549
  async function deployTarball({ runTask }, project) {
251527
251550
  const outputDir = siteOutputDir(project);
251551
+ if (!outputDir) {
251552
+ throw new ConfigNotFoundError("No site configuration found.", {
251553
+ hints: [
251554
+ {
251555
+ message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
251556
+ }
251557
+ ]
251558
+ });
251559
+ }
251528
251560
  const { appUrl } = await runTask("Creating archive and deploying site...", async () => await deploySite(outputDir), {
251529
251561
  successMessage: "Site deployed successfully",
251530
251562
  errorMessage: "Deployment failed"
@@ -251532,8 +251564,8 @@ async function deployTarball({ runTask }, project) {
251532
251564
  return { outroMessage: `Visit your site at: ${appUrl}` };
251533
251565
  }
251534
251566
  function siteOutputDir(project) {
251535
- const { outputDirectory = DEFAULT_SITE.outputDirectory } = siteOrDefault(project);
251536
- return resolve15(project.root, outputDirectory);
251567
+ const outputDirectory = project.site?.outputDirectory;
251568
+ return outputDirectory ? resolve15(project.root, outputDirectory) : null;
251537
251569
  }
251538
251570
  function getSiteDeployCommand() {
251539
251571
  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)");
@@ -251731,7 +251763,10 @@ async function siteDevAction(ctx, forwarded) {
251731
251763
  throw new ConfigInvalidError("base44 site dev requires a linked local project. Run it from a project with base44/.app.jsonc.");
251732
251764
  }
251733
251765
  const project = await readProjectSettings(app.projectRoot);
251734
- const site = siteOrDefault(project);
251766
+ const site = project.site;
251767
+ if (!site) {
251768
+ throw new InvalidInputError(`This project has no 'site' block in base44/config.jsonc, so there is no frontend to serve. Add one naming its serveCommand; site dev falls back to "npm run dev".`);
251769
+ }
251735
251770
  const serveCommand = site.serveCommand ?? DEFAULT_SERVE_COMMAND;
251736
251771
  const command = [serveCommand, ...forwarded].join(" ");
251737
251772
  const runner = createServeCommandRunner({
@@ -251753,7 +251788,16 @@ async function installAction({
251753
251788
  runTask
251754
251789
  }) {
251755
251790
  const project = await readProjectSettings();
251756
- const { installCommand } = siteOrDefault(project);
251791
+ const installCommand = project.site?.installCommand;
251792
+ if (!installCommand) {
251793
+ throw new ConfigNotFoundError("No site install command found.", {
251794
+ hints: [
251795
+ {
251796
+ message: `Add a 'site' block to your config.jsonc (e.g., "site": { "installCommand": "npm ci" }). Inside one, installCommand defaults to "npm install".`
251797
+ }
251798
+ ]
251799
+ });
251800
+ }
251757
251801
  await runTask("Installing site dependencies...", () => execa({ cwd: project.root, shell: true })`${installCommand}`, {
251758
251802
  successMessage: "Dependencies installed",
251759
251803
  errorMessage: "Install failed"
@@ -254174,11 +254218,11 @@ async function createEntityRoutes(db, logger, broadcast) {
254174
254218
  // src/cli/dev/dev-server/routes/integrations.ts
254175
254219
  var import_express5 = __toESM(require_express(), 1);
254176
254220
  var import_multer = __toESM(require_multer(), 1);
254177
- import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
254221
+ import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
254178
254222
  import fs28 from "node:fs";
254179
254223
  import path18 from "node:path";
254180
254224
  function createFileToken(fileUri) {
254181
- return createHash3("sha256").update(fileUri).digest("hex");
254225
+ return createHash4("sha256").update(fileUri).digest("hex");
254182
254226
  }
254183
254227
  function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger) {
254184
254228
  const router = import_express5.Router({ mergeParams: true });
@@ -254263,7 +254307,7 @@ function createCustomIntegrationRoutes(remoteProxy, logger) {
254263
254307
 
254264
254308
  // src/cli/dev/dev-server/watcher.ts
254265
254309
  import { EventEmitter as EventEmitter4 } from "node:events";
254266
- import { relative as relative9 } from "node:path";
254310
+ import { relative as relative10 } from "node:path";
254267
254311
 
254268
254312
  // ../../node_modules/chokidar/index.js
254269
254313
  import { EventEmitter as EventEmitter3 } from "node:events";
@@ -255948,7 +255992,7 @@ class WatchBase44 extends EventEmitter4 {
255948
255992
  ignoreInitial: true
255949
255993
  });
255950
255994
  watcher.on("all", import_debounce.default(async (_event, path) => {
255951
- this.emit("change", name, relative9(targetPath, path));
255995
+ this.emit("change", name, relative10(targetPath, path));
255952
255996
  }, WATCH_DEBOUNCE_MS));
255953
255997
  watcher.on("error", (err) => {
255954
255998
  this.logger.error(`Watch handler failed for ${targetPath}`, err);
@@ -257016,7 +257060,7 @@ function isBuiltin2(candidate, className) {
257016
257060
  function isEvent(candidate) {
257017
257061
  return !isUndefined(Event) && isInstanceOf(candidate, Event);
257018
257062
  }
257019
- function isPlainObject4(candidate) {
257063
+ function isPlainObject3(candidate) {
257020
257064
  return isBuiltin2(candidate, "Object");
257021
257065
  }
257022
257066
  function isInstanceOf(candidate, base) {
@@ -260152,7 +260196,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
260152
260196
  const personProperties = {};
260153
260197
  const groupProperties = {};
260154
260198
  for (const [key, value] of Object.entries(eventProperties))
260155
- if (isPlainObject4(value) && groups && key in groups) {
260199
+ if (isPlainObject3(value) && groups && key in groups) {
260156
260200
  const groupProps = {};
260157
260201
  for (const [groupKey, groupValue] of Object.entries(value))
260158
260202
  groupProps[String(groupKey)] = String(groupValue);
@@ -260629,4 +260673,4 @@ export {
260629
260673
  runCLI
260630
260674
  };
260631
260675
 
260632
- //# debugId=545CDC42F775B10764756E2164756E21
260676
+ //# debugId=27A5BE3E7D68768264756E2164756E21