@base44-preview/cli 0.1.8-pr.589.9d22ef2 → 0.1.8-pr.600.002d9ac

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
@@ -247201,24 +247201,33 @@ var ResourceSourceSchema = exports_external.discriminatedUnion("type", [
247201
247201
  ]);
247202
247202
 
247203
247203
  // src/core/resources/entity/schema.ts
247204
- var FieldConditionSchema = exports_external.union([
247205
- exports_external.string(),
247206
- exports_external.number(),
247207
- exports_external.boolean(),
247208
- exports_external.null(),
247209
- exports_external.looseObject({
247210
- $in: exports_external.unknown().optional(),
247211
- $nin: exports_external.unknown().optional(),
247212
- $ne: exports_external.unknown().optional(),
247213
- $all: exports_external.unknown().optional()
247214
- })
247204
+ var fieldConditionOperators = new Set([
247205
+ "$eq",
247206
+ "$ne",
247207
+ "$in",
247208
+ "$nin",
247209
+ "$gt",
247210
+ "$gte",
247211
+ "$lt",
247212
+ "$lte",
247213
+ "$exists",
247214
+ "$all",
247215
+ "$size",
247216
+ "$elemMatch"
247215
247217
  ]);
247216
- var userConditionAllowedKeys = new Set(["role", "email", "id"]);
247217
- var UserConditionSchema = exports_external.looseObject({
247218
- role: exports_external.string().optional(),
247219
- email: exports_external.string().optional(),
247220
- id: exports_external.string().optional()
247221
- }).refine((val) => Object.keys(val).every((key) => userConditionAllowedKeys.has(key) || key.startsWith("data.")), "Keys must be role, email, id, or match data.* pattern");
247218
+ var isScalar = (value) => value === null || ["string", "number", "boolean"].includes(typeof value);
247219
+ var isValidFieldCondition = (value) => {
247220
+ if (isScalar(value)) {
247221
+ return true;
247222
+ }
247223
+ if (typeof value === "object" && !Array.isArray(value)) {
247224
+ return Object.keys(value).every((k2) => fieldConditionOperators.has(k2));
247225
+ }
247226
+ return false;
247227
+ };
247228
+ var supportedOperators = [...fieldConditionOperators].sort().join(", ");
247229
+ var FieldConditionSchema = exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean(), exports_external.null(), exports_external.looseObject({})]).refine(isValidFieldCondition, `Field condition values must be a primitive or an operator object (${supportedOperators})`);
247230
+ var UserConditionSchema = exports_external.looseObject({}).refine((val) => Object.keys(val).length > 0 && Object.entries(val).every(([key, value]) => !key.startsWith("$") && isScalar(value)), "user_condition compares user attributes by exact equality: a non-empty object of attribute: scalar pairs, no operators");
247222
247231
  var rlsConditionAllowedKeys = new Set([
247223
247232
  "user_condition",
247224
247233
  "created_by",
@@ -247250,18 +247259,13 @@ var RLSConditionSchema = exports_external.looseObject({
247250
247259
  return exports_external.array(RefineRLSConditionSchema).optional();
247251
247260
  }
247252
247261
  });
247253
- var fieldConditionOperators = new Set(["$in", "$nin", "$ne", "$all"]);
247254
- var isValidFieldCondition = (value) => {
247255
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
247256
- return true;
247257
- }
247258
- if (typeof value === "object") {
247259
- return Object.keys(value).every((k2) => fieldConditionOperators.has(k2));
247260
- }
247261
- return false;
247262
- };
247263
- var RefineRLSConditionSchema = RLSConditionSchema.refine((val) => Object.entries(val).every(([key, value]) => rlsConditionAllowedKeys.has(key) || isValidFieldCondition(value)), "Field condition values must be a primitive or an operator object ($in, $nin, $ne, $all)");
247264
- var RLSRuleSchema = exports_external.union([exports_external.boolean(), RefineRLSConditionSchema]);
247262
+ var RefineRLSConditionSchema = RLSConditionSchema.refine((val) => Object.entries(val).every(([key, value]) => rlsConditionAllowedKeys.has(key) || isValidFieldCondition(value)), `Field condition values must be a primitive or an operator object (${supportedOperators})`);
247263
+ var RLSRuleSchema = exports_external.union([
247264
+ exports_external.boolean(),
247265
+ exports_external.null(),
247266
+ exports_external.literal(""),
247267
+ RefineRLSConditionSchema
247268
+ ]);
247265
247269
  var EntityRLSSchema = exports_external.looseObject({
247266
247270
  create: RLSRuleSchema.optional(),
247267
247271
  read: RLSRuleSchema.optional(),
@@ -247277,7 +247281,7 @@ var FieldRLSSchema = exports_external.looseObject({
247277
247281
  delete: RLSRuleSchema.optional()
247278
247282
  });
247279
247283
  var PropertyDefinitionSchema = exports_external.looseObject({
247280
- type: exports_external.string(),
247284
+ type: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]),
247281
247285
  title: exports_external.string().optional(),
247282
247286
  description: exports_external.string().optional(),
247283
247287
  minLength: exports_external.number().int().min(0).optional(),
@@ -247301,7 +247305,7 @@ var PropertyDefinitionSchema = exports_external.looseObject({
247301
247305
  });
247302
247306
  var EntitySchema = exports_external.looseObject({
247303
247307
  type: exports_external.literal("object").default("object"),
247304
- name: exports_external.string().min(1).regex(/^[a-zA-Z0-9]+$/, "Entity name must be alphanumeric only"),
247308
+ name: exports_external.string().min(1).regex(/^\w+$/, "Entity name must contain only letters, numbers, and underscores"),
247305
247309
  title: exports_external.string().optional(),
247306
247310
  description: exports_external.string().optional(),
247307
247311
  properties: exports_external.record(exports_external.string(), PropertyDefinitionSchema).default({}),
@@ -247871,10 +247875,15 @@ var functionResource = {
247871
247875
  // src/core/project/config.ts
247872
247876
  class ProjectConfigReader {
247873
247877
  pluginSourceByNamespace = new Map;
247874
- async readProjectConfig(projectRoot) {
247878
+ async readProjectSettings(projectRoot) {
247875
247879
  const { root, configPath } = await this.findConfigOrThrow(projectRoot);
247876
247880
  const project = await this.readConfigFile(configPath);
247877
247881
  this.assertPluginProjectDoesNotLoadPlugins(project, configPath);
247882
+ return { ...project, root, configPath };
247883
+ }
247884
+ async readProjectConfig(projectRoot) {
247885
+ const project = await this.readProjectSettings(projectRoot);
247886
+ const { configPath } = project;
247878
247887
  const localResources = await this.readProjectResources(configPath, project);
247879
247888
  const pluginResources = await this.readPlugins(project.plugins, configPath);
247880
247889
  const entities = mergeProjectAndPluginEntities(localResources.entities, pluginResources.entities, configPath);
@@ -247884,7 +247893,7 @@ class ProjectConfigReader {
247884
247893
  ];
247885
247894
  this.validateFunctionNames(functions, configPath);
247886
247895
  return {
247887
- project: { ...project, root, configPath },
247896
+ project,
247888
247897
  entities,
247889
247898
  functions,
247890
247899
  agents: localResources.agents,
@@ -248022,6 +248031,10 @@ async function readProjectConfig(projectRoot) {
248022
248031
  const reader = new ProjectConfigReader;
248023
248032
  return await reader.readProjectConfig(projectRoot);
248024
248033
  }
248034
+ async function readProjectSettings(projectRoot) {
248035
+ const reader = new ProjectConfigReader;
248036
+ return await reader.readProjectSettings(projectRoot);
248037
+ }
248025
248038
  // src/core/project/template.ts
248026
248039
  var import_ejs = __toESM(require_ejs(), 1);
248027
248040
  var import_front_matter2 = __toESM(require_front_matter(), 1);
@@ -248335,7 +248348,9 @@ async function deploySite(siteOutputDir) {
248335
248348
  if (!await pathExists(siteOutputDir)) {
248336
248349
  throw new InvalidInputError(`Output directory does not exist: ${siteOutputDir}. Make sure to build your project first.`, {
248337
248350
  hints: [
248338
- { message: "Run your build command (e.g., 'npm run build') first" }
248351
+ {
248352
+ message: "Run 'base44 build' first (it injects your app id; a bare 'npm run build' does not)"
248353
+ }
248339
248354
  ]
248340
248355
  });
248341
248356
  }
@@ -248343,7 +248358,9 @@ async function deploySite(siteOutputDir) {
248343
248358
  if (filePaths.length === 0) {
248344
248359
  throw new ConfigInvalidError(`No files found in output directory: ${siteOutputDir}. Make sure to build your project first.`, siteOutputDir, {
248345
248360
  hints: [
248346
- { message: "Run your build command (e.g., 'npm run build') first" }
248361
+ {
248362
+ message: "Run 'base44 build' first (it injects your app id; a bare 'npm run build' does not)"
248363
+ }
248347
248364
  ]
248348
248365
  });
248349
248366
  }
@@ -255586,6 +255603,14 @@ function writeJsonError(error48) {
255586
255603
  envelope.hints = error48.hints;
255587
255604
  }
255588
255605
  }
255606
+ if (error48 instanceof ApiError) {
255607
+ if (error48.statusCode !== undefined) {
255608
+ envelope.statusCode = error48.statusCode;
255609
+ }
255610
+ if (error48.requestId !== undefined) {
255611
+ envelope.requestId = error48.requestId;
255612
+ }
255613
+ }
255589
255614
  process.stdout.write(`${JSON.stringify(envelope)}
255590
255615
  `);
255591
255616
  }
@@ -255682,6 +255707,18 @@ async function confirmPush({
255682
255707
  });
255683
255708
  return !Ct(proceed) && proceed;
255684
255709
  }
255710
+ // src/cli/utils/datetime.ts
255711
+ var import_ms2 = __toESM(require_ms(), 1);
255712
+ var HAS_TIMEZONE_SUFFIX = /Z$|[+-]\d{2}:\d{2}$/;
255713
+ function normalizeDatetime(value) {
255714
+ const duration3 = import_ms2.default(value);
255715
+ if (duration3 !== undefined) {
255716
+ return new Date(Date.now() - duration3).toISOString();
255717
+ }
255718
+ if (HAS_TIMEZONE_SUFFIX.test(value))
255719
+ return value;
255720
+ return `${value}Z`;
255721
+ }
255685
255722
  // src/cli/utils/json.ts
255686
255723
  function toJsonStdout(result) {
255687
255724
  return `${JSON.stringify(result, null, 2)}
@@ -257539,8 +257576,8 @@ function getDeleteCommand() {
257539
257576
  }
257540
257577
 
257541
257578
  // src/cli/commands/functions/formatDeployResult.ts
257542
- function formatDuration(ms) {
257543
- return `${(ms / 1000).toFixed(1)}s`;
257579
+ function formatDuration(ms2) {
257580
+ return `${(ms2 / 1000).toFixed(1)}s`;
257544
257581
  }
257545
257582
  function formatDeployResult(result, log) {
257546
257583
  const label = result.name.padEnd(25);
@@ -257873,7 +257910,11 @@ async function completeProjectSetup({
257873
257910
  const { appUrl } = await runTask2("Installing dependencies...", async (updateMessage) => {
257874
257911
  await execa({ cwd: resolvedPath, shell: true })`${installCommand}`;
257875
257912
  updateMessage("Building project...");
257876
- await execa({ cwd: resolvedPath, shell: true })`${buildCommand}`;
257913
+ await execa({
257914
+ cwd: resolvedPath,
257915
+ shell: true,
257916
+ env: { VITE_BASE44_APP_ID: projectId }
257917
+ })`${buildCommand}`;
257877
257918
  updateMessage("Deploying site...");
257878
257919
  return await deploySite(join25(resolvedPath, outputDirectory));
257879
257920
  }, {
@@ -258353,7 +258394,6 @@ function getLinkCommand() {
258353
258394
  }
258354
258395
 
258355
258396
  // src/cli/commands/project/logs.ts
258356
- var import_ms2 = __toESM(require_ms(), 1);
258357
258397
  function parseFunctionFilters(options) {
258358
258398
  const filters = {};
258359
258399
  if (options.since) {
@@ -258381,15 +258421,6 @@ function parseFunctionNames(option) {
258381
258421
  return [];
258382
258422
  return option.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
258383
258423
  }
258384
- function normalizeDatetime(value) {
258385
- const duration3 = import_ms2.default(value);
258386
- if (duration3 !== undefined) {
258387
- return new Date(Date.now() - duration3).toISOString();
258388
- }
258389
- if (/Z$|[+-]\d{2}:\d{2}$/.test(value))
258390
- return value;
258391
- return `${value}Z`;
258392
- }
258393
258424
  function formatEntry(entry) {
258394
258425
  const time3 = entry.time.substring(0, 19).replace("T", " ");
258395
258426
  const level = entry.level.toUpperCase().padEnd(5);
@@ -259030,7 +259061,7 @@ async function deployAction2(ctx, options) {
259030
259061
  if (isNonInteractive && !options.yes) {
259031
259062
  throw new InvalidInputError("--yes is required in non-interactive mode");
259032
259063
  }
259033
- const { project: project2 } = await readProjectConfig();
259064
+ const project2 = await readProjectSettings();
259034
259065
  const outputDirectory = project2.site?.outputDirectory;
259035
259066
  if (!outputDirectory) {
259036
259067
  throw new ConfigNotFoundError("No site configuration found.", {
@@ -259267,6 +259298,235 @@ function getTypesCommand() {
259267
259298
  return new Command("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
259268
259299
  }
259269
259300
 
259301
+ // src/core/resources/workflow/schema.ts
259302
+ var WorkflowRunStatusSchema = exports_external.enum([
259303
+ "running",
259304
+ "completed",
259305
+ "failed",
259306
+ "cancelled"
259307
+ ]);
259308
+ var WorkflowListItemSchema = exports_external.object({
259309
+ id: exports_external.string(),
259310
+ name: exports_external.string(),
259311
+ description: exports_external.string().nullable().optional(),
259312
+ status: exports_external.string(),
259313
+ status_reason: exports_external.string().nullable().optional(),
259314
+ total_runs: exports_external.number().default(0),
259315
+ consecutive_failures: exports_external.number().default(0),
259316
+ last_run_at: exports_external.string().nullable().optional(),
259317
+ last_run_status: exports_external.string().nullable().optional()
259318
+ }).transform((data) => ({
259319
+ id: data.id,
259320
+ name: data.name,
259321
+ description: data.description ?? null,
259322
+ status: data.status,
259323
+ statusReason: data.status_reason ?? null,
259324
+ totalRuns: data.total_runs,
259325
+ consecutiveFailures: data.consecutive_failures,
259326
+ lastRunAt: data.last_run_at ?? null,
259327
+ lastRunStatus: data.last_run_status ?? null
259328
+ }));
259329
+ var ListWorkflowsResponseSchema = exports_external.array(WorkflowListItemSchema);
259330
+ var WorkflowRunSchema = exports_external.object({
259331
+ run_id: exports_external.string(),
259332
+ workflow_id: exports_external.string(),
259333
+ workflow_name: exports_external.string().default(""),
259334
+ trigger_type: exports_external.string().default(""),
259335
+ status: exports_external.string(),
259336
+ started_at: exports_external.string().nullable().optional(),
259337
+ completed_at: exports_external.string().nullable().optional(),
259338
+ duration_ms: exports_external.number().default(0),
259339
+ steps_count: exports_external.number().default(0),
259340
+ error_message: exports_external.string().nullable().optional(),
259341
+ is_test_run: exports_external.boolean().default(false),
259342
+ status_reason: exports_external.string().default("")
259343
+ }).transform((data) => ({
259344
+ runId: data.run_id,
259345
+ workflowId: data.workflow_id,
259346
+ workflowName: data.workflow_name,
259347
+ triggerType: data.trigger_type,
259348
+ status: data.status,
259349
+ startedAt: data.started_at ?? null,
259350
+ completedAt: data.completed_at ?? null,
259351
+ durationMs: data.duration_ms,
259352
+ stepsCount: data.steps_count,
259353
+ errorMessage: data.error_message ?? null,
259354
+ isTestRun: data.is_test_run,
259355
+ statusReason: data.status_reason
259356
+ }));
259357
+ var ListWorkflowRunsResponseSchema = exports_external.array(WorkflowRunSchema);
259358
+
259359
+ // src/core/resources/workflow/api.ts
259360
+ async function listWorkflows(limit) {
259361
+ const appClient = getAppClient();
259362
+ const searchParams = new URLSearchParams;
259363
+ if (limit !== undefined) {
259364
+ searchParams.set("limit", String(limit));
259365
+ }
259366
+ let response;
259367
+ try {
259368
+ response = await appClient.get("workflows", { searchParams });
259369
+ } catch (error48) {
259370
+ throw await ApiError.fromHttpError(error48, "listing workflows");
259371
+ }
259372
+ const result = ListWorkflowsResponseSchema.safeParse(await response.json());
259373
+ if (!result.success) {
259374
+ throw new SchemaValidationError("Invalid workflows response from server", result.error);
259375
+ }
259376
+ return result.data;
259377
+ }
259378
+ function buildRunsQueryString(filters) {
259379
+ const params = new URLSearchParams;
259380
+ if (filters.status) {
259381
+ params.set("status", filters.status);
259382
+ }
259383
+ if (filters.since) {
259384
+ params.set("since", filters.since);
259385
+ }
259386
+ if (filters.limit !== undefined) {
259387
+ params.set("limit", String(filters.limit));
259388
+ }
259389
+ return params;
259390
+ }
259391
+ async function listWorkflowRuns(filters = {}) {
259392
+ const appClient = getAppClient();
259393
+ let response;
259394
+ try {
259395
+ response = await appClient.get("workflows/runs", {
259396
+ searchParams: buildRunsQueryString(filters)
259397
+ });
259398
+ } catch (error48) {
259399
+ throw await ApiError.fromHttpError(error48, "listing workflow runs");
259400
+ }
259401
+ const result = ListWorkflowRunsResponseSchema.safeParse(await response.json());
259402
+ if (!result.success) {
259403
+ throw new SchemaValidationError("Invalid workflow runs response from server", result.error);
259404
+ }
259405
+ return result.data;
259406
+ }
259407
+ // src/cli/commands/workflows/legacy-app.ts
259408
+ var isWorkflowsNotEnabled = (error48) => error48 instanceof ApiError && error48.statusCode === 403;
259409
+ function rethrowLegacyAppAsExplanation(error48) {
259410
+ if (isWorkflowsNotEnabled(error48)) {
259411
+ throw new InvalidInputError("Workflows are not enabled for this app — it predates the Workflows system, so its automation runs are not readable via this command.");
259412
+ }
259413
+ throw error48;
259414
+ }
259415
+
259416
+ // src/cli/commands/workflows/limit.ts
259417
+ var MAX_LIMIT = 200;
259418
+ function parseLimit(limit) {
259419
+ if (limit === undefined)
259420
+ return;
259421
+ const parsed = Number.parseInt(limit, 10);
259422
+ if (Number.isNaN(parsed) || parsed < 1 || parsed > MAX_LIMIT) {
259423
+ throw new InvalidInputError(`Invalid limit: "${limit}". Must be a number between 1 and ${MAX_LIMIT}.`);
259424
+ }
259425
+ return parsed;
259426
+ }
259427
+
259428
+ // src/cli/commands/workflows/list.ts
259429
+ function formatWorkflowLine(workflow) {
259430
+ const lastRun = workflow.lastRunAt ? `last run ${workflow.lastRunStatus ?? "unknown"} at ${workflow.lastRunAt}` : "never ran";
259431
+ const failures = workflow.consecutiveFailures > 0 ? ` (${workflow.consecutiveFailures} consecutive failures)` : "";
259432
+ return `${workflow.name} [${workflow.status}] runs: ${workflow.totalRuns}, ${lastRun}${failures}`;
259433
+ }
259434
+ async function listAction({ log, runTask: runTask2, jsonMode }, options8) {
259435
+ const limit = parseLimit(options8.limit);
259436
+ const workflows = await runTask2("Fetching workflows from Base44", async () => listWorkflows(limit).catch(rethrowLegacyAppAsExplanation), {
259437
+ successMessage: "Workflows fetched successfully",
259438
+ errorMessage: "Failed to fetch workflows"
259439
+ });
259440
+ if (jsonMode) {
259441
+ return {
259442
+ outroMessage: `Found ${workflows.length} workflows.`,
259443
+ stdout: `${JSON.stringify({ workflows }, null, 2)}
259444
+ `
259445
+ };
259446
+ }
259447
+ if (workflows.length === 0) {
259448
+ return { outroMessage: "This app has no workflows." };
259449
+ }
259450
+ for (const workflow of workflows) {
259451
+ log.info(formatWorkflowLine(workflow));
259452
+ }
259453
+ return { outroMessage: `Found ${workflows.length} workflows.` };
259454
+ }
259455
+ function getWorkflowsListCommand() {
259456
+ return new Base44Command("list").description("List this app's workflows").option("-n, --limit <n>", `Number of workflows to return (1-${MAX_LIMIT}, default: 30)`).action(listAction);
259457
+ }
259458
+
259459
+ // src/cli/commands/workflows/runs.ts
259460
+ function formatDuration2(durationMs) {
259461
+ if (durationMs === 0)
259462
+ return "";
259463
+ return ` ${(durationMs / 1000).toFixed(1)}s`;
259464
+ }
259465
+ function formatRunTags(run) {
259466
+ const tags = [run.triggerType, run.isTestRun ? "test" : null].filter(Boolean);
259467
+ return tags.length > 0 ? ` (${tags.join(", ")})` : "";
259468
+ }
259469
+ function formatFailureDetail(run) {
259470
+ const reason = run.statusReason ? ` [${run.statusReason}]` : "";
259471
+ const message = run.errorMessage ? `
259472
+ ${run.errorMessage}` : "";
259473
+ return `${reason}${message}`;
259474
+ }
259475
+ function formatRunLine(run) {
259476
+ const time3 = (run.startedAt ?? "").substring(0, 19).replace("T", " ");
259477
+ const status = run.status.toUpperCase().padEnd(9);
259478
+ const base = `${time3} ${status} ${run.workflowName}${formatRunTags(run)}${formatDuration2(run.durationMs)}`;
259479
+ const failureDetail = run.status === "failed" || run.status === "cancelled" ? formatFailureDetail(run) : "";
259480
+ return `${base}${failureDetail}`;
259481
+ }
259482
+ async function describeEmptyResult(hasFilters) {
259483
+ const workflows = await listWorkflows().catch(() => null);
259484
+ if (workflows === null) {
259485
+ return "No runs found.";
259486
+ }
259487
+ if (workflows.length === 0) {
259488
+ return "This app has no workflows, so there are no runs.";
259489
+ }
259490
+ const names = workflows.map((workflow) => workflow.name).join(", ");
259491
+ return hasFilters ? `No runs match your filters. Workflows in this app: ${names}.` : `No runs yet. Workflows in this app: ${names}.`;
259492
+ }
259493
+ async function runsAction(ctx, options8) {
259494
+ const limit = parseLimit(options8.limit);
259495
+ const runs = await ctx.runTask("Fetching workflow runs from Base44", async () => listWorkflowRuns({
259496
+ status: options8.status,
259497
+ since: options8.since,
259498
+ limit
259499
+ }).catch(rethrowLegacyAppAsExplanation), {
259500
+ successMessage: "Workflow runs fetched successfully",
259501
+ errorMessage: "Failed to fetch workflow runs"
259502
+ });
259503
+ if (ctx.jsonMode) {
259504
+ return {
259505
+ outroMessage: `Found ${runs.length} runs.`,
259506
+ stdout: `${JSON.stringify({ runs }, null, 2)}
259507
+ `
259508
+ };
259509
+ }
259510
+ if (runs.length === 0) {
259511
+ const hasFilters = Boolean(options8.status || options8.since);
259512
+ return { outroMessage: await describeEmptyResult(hasFilters) };
259513
+ }
259514
+ for (const run of runs) {
259515
+ ctx.log.info(formatRunLine(run));
259516
+ }
259517
+ return { outroMessage: `Found ${runs.length} runs.` };
259518
+ }
259519
+ function getWorkflowsRunsCommand() {
259520
+ return new Base44Command("runs").description("List workflow runs for this app, newest first (includes scheduled, manual, and test runs)").addOption(new Option("--status <status>", "Filter by run status").choices([
259521
+ ...WorkflowRunStatusSchema.options
259522
+ ])).option("--since <datetime>", "Show runs started after this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("-n, --limit <n>", `Number of runs to return (1-${MAX_LIMIT}, default: 30)`).action(runsAction);
259523
+ }
259524
+
259525
+ // src/cli/commands/workflows/index.ts
259526
+ function getWorkflowsCommand() {
259527
+ return new Command("workflows").description("Inspect this app's workflows and their runs").addCommand(getWorkflowsListCommand()).addCommand(getWorkflowsRunsCommand());
259528
+ }
259529
+
259270
259530
  // src/cli/commands/workspace/shared.ts
259271
259531
  function workspaceTag(workspace2) {
259272
259532
  const role = workspace2.userRole ?? "member";
@@ -260261,7 +260521,8 @@ var fieldTypes = [
260261
260521
  "number",
260262
260522
  "boolean",
260263
260523
  "array",
260264
- "object"
260524
+ "object",
260525
+ "null"
260265
260526
  ];
260266
260527
 
260267
260528
  class Validator {
@@ -260321,6 +260582,14 @@ class Validator {
260321
260582
  if (!property) {
260322
260583
  return { hasError: false };
260323
260584
  }
260585
+ if (Array.isArray(property.type)) {
260586
+ const types = property.type;
260587
+ const matched = types.some((type) => !this.validateValue(value, { ...property, type }, fieldPath).hasError);
260588
+ return matched ? { hasError: false } : {
260589
+ hasError: true,
260590
+ error: this.createValidationError(`Error in field ${fieldPath}: Input should be a valid ${types.join(" or ")}`)
260591
+ };
260592
+ }
260324
260593
  const propertyType = property.type;
260325
260594
  if (!fieldTypes.includes(propertyType)) {
260326
260595
  return {
@@ -260361,6 +260630,14 @@ class Validator {
260361
260630
  }
260362
260631
  }
260363
260632
  break;
260633
+ case "null":
260634
+ if (value !== null) {
260635
+ return {
260636
+ hasError: true,
260637
+ error: this.createValidationError(`Error in field ${fieldPath}: Input should be null`)
260638
+ };
260639
+ }
260640
+ break;
260364
260641
  case "integer":
260365
260642
  if (!Number.isInteger(value)) {
260366
260643
  return {
@@ -260780,7 +261057,9 @@ function evaluateCondition(condition, record2, user) {
260780
261057
  function checkRLS(rule, record2, user) {
260781
261058
  if (user?.is_service === true)
260782
261059
  return true;
260783
- if (rule === undefined)
261060
+ if (rule === undefined || rule === null || rule === "")
261061
+ return true;
261062
+ if (typeof rule === "object" && Object.keys(rule).length === 0)
260784
261063
  return true;
260785
261064
  if (typeof rule === "boolean")
260786
261065
  return rule;
@@ -263331,6 +263610,10 @@ function validateDevOptions(command2) {
263331
263610
  if (appId !== undefined) {
263332
263611
  command2.error(`base44 dev cannot be used with --app-id or ${BASE44_APP_ID_ENV_VAR}.`);
263333
263612
  }
263613
+ const { port, remote } = command2.opts();
263614
+ if (remote && port !== undefined) {
263615
+ command2.error("--port applies to the local backend, which --remote does not start.");
263616
+ }
263334
263617
  }
263335
263618
  function requireLinkedProject({ app }) {
263336
263619
  if (!app?.projectRoot) {
@@ -263338,31 +263621,44 @@ function requireLinkedProject({ app }) {
263338
263621
  }
263339
263622
  return { id: app.id, projectRoot: app.projectRoot };
263340
263623
  }
263341
- async function createConfiguredServeRunner(app, backendUrl) {
263624
+ async function resolveConfiguredSite(app) {
263342
263625
  const { project: project2 } = await readProjectConfig(app.projectRoot);
263343
263626
  const serveCommand = project2.site?.serveCommand;
263344
- if (!serveCommand) {
263345
- return;
263346
- }
263347
- return createServeCommandRunner({
263348
- serveCommand,
263349
- projectRoot: project2.root,
263350
- appId: app.id,
263351
- appBaseUrl: backendUrl
263352
- });
263627
+ return serveCommand ? { serveCommand, projectRoot: project2.root } : undefined;
263353
263628
  }
263354
- function startServeCommand(runner, backend) {
263629
+ function stopRunnerOnProcessSignals(runner) {
263355
263630
  const stop2 = () => void runner.stop();
263356
263631
  process.on("SIGINT", stop2);
263357
263632
  process.on("SIGTERM", stop2);
263633
+ }
263634
+ function startServeCommand(runner, backend) {
263635
+ stopRunnerOnProcessSignals(runner);
263358
263636
  runner.onExit(() => {
263359
263637
  backend.shutdown().finally(() => process.exit(1));
263360
263638
  });
263361
263639
  createDevLogger("backend", theme.styles.info).log(`Backend running on ${backend.url}`);
263362
263640
  runner.start();
263363
263641
  }
263364
- async function devAction(ctx, options8) {
263365
- const app = requireLinkedProject(ctx);
263642
+ async function remoteDevAction(app) {
263643
+ const site2 = await resolveConfiguredSite(app);
263644
+ if (!site2) {
263645
+ throw new ConfigInvalidError("base44 dev --remote serves the frontend against the production backend, but this project has no site.serveCommand in base44/config.jsonc.");
263646
+ }
263647
+ const appBaseUrl = await getSiteUrl();
263648
+ const runner = createServeCommandRunner({
263649
+ ...site2,
263650
+ appId: app.id,
263651
+ appBaseUrl
263652
+ });
263653
+ stopRunnerOnProcessSignals(runner);
263654
+ runner.onExit((code2) => process.exit(code2 ?? 1));
263655
+ runner.start();
263656
+ return {
263657
+ outroMessage: `Frontend dev server targets ${theme.styles.bold(appBaseUrl)} — every write hits your live app`
263658
+ };
263659
+ }
263660
+ async function localDevAction(ctx, app, options8) {
263661
+ const site2 = await resolveConfiguredSite(app);
263366
263662
  const siteUrlPromise = getSiteUrl().catch(() => {
263367
263663
  return;
263368
263664
  });
@@ -263377,15 +263673,23 @@ async function devAction(ctx, options8) {
263377
263673
  }
263378
263674
  });
263379
263675
  const backendUrl = localServerUrl(backend.port);
263380
- const runner = await createConfiguredServeRunner(app, backendUrl);
263381
- if (runner) {
263676
+ if (site2) {
263677
+ const runner = createServeCommandRunner({
263678
+ ...site2,
263679
+ appId: app.id,
263680
+ appBaseUrl: backendUrl
263681
+ });
263382
263682
  startServeCommand(runner, { url: backendUrl, shutdown: backend.shutdown });
263383
263683
  }
263384
- const outroMessage = runner ? "Open your app using the frontend dev server URL" : `Dev server is available at ${theme.colors.links(backendUrl)}`;
263684
+ const outroMessage = site2 ? "Open your app using the frontend dev server URL" : `Dev server is available at ${theme.colors.links(backendUrl)}`;
263385
263685
  return { outroMessage };
263386
263686
  }
263687
+ async function devAction(ctx, options8) {
263688
+ const app = requireLinkedProject(ctx);
263689
+ return options8.remote ? remoteDevAction(app) : localDevAction(ctx, app, options8);
263690
+ }
263387
263691
  function getDevCommand() {
263388
- return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").hook("preAction", validateDevOptions).action(devAction);
263692
+ return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").option("--remote", "Serve the frontend against the production backend instead of a local one").hook("preAction", validateDevOptions).action(devAction);
263389
263693
  }
263390
263694
 
263391
263695
  // src/core/exec/run-script.ts
@@ -263648,6 +263952,7 @@ function createProgram(context) {
263648
263952
  program2.addCommand(getAgentSkillsCommand());
263649
263953
  program2.addCommand(getConnectorsCommand());
263650
263954
  program2.addCommand(getFunctionsCommand());
263955
+ program2.addCommand(getWorkflowsCommand());
263651
263956
  program2.addCommand(getSecretsCommand());
263652
263957
  program2.addCommand(getSandboxCommand());
263653
263958
  program2.addCommand(getAuthCommand());
@@ -267903,4 +268208,4 @@ export {
267903
268208
  CLIExitError
267904
268209
  };
267905
268210
 
267906
- //# debugId=D124AF9A61B7AEE264756E2164756E21
268211
+ //# debugId=BD8B328810C7720964756E2164756E21