@base44-preview/cli 0.1.1-pr.555.067c6ae → 0.1.1-pr.555.5e8fb00

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
@@ -163944,7 +163944,7 @@ var require_view = __commonJS((exports, module) => {
163944
163944
  var debug = require_src4()("express:view");
163945
163945
  var path18 = __require("node:path");
163946
163946
  var fs28 = __require("node:fs");
163947
- var dirname21 = path18.dirname;
163947
+ var dirname22 = path18.dirname;
163948
163948
  var basename7 = path18.basename;
163949
163949
  var extname2 = path18.extname;
163950
163950
  var join27 = path18.join;
@@ -163983,7 +163983,7 @@ var require_view = __commonJS((exports, module) => {
163983
163983
  for (var i5 = 0;i5 < roots.length && !path19; i5++) {
163984
163984
  var root2 = roots[i5];
163985
163985
  var loc = resolve12(root2, name2);
163986
- var dir = dirname21(loc);
163986
+ var dir = dirname22(loc);
163987
163987
  var file2 = basename7(loc);
163988
163988
  path19 = this.resolve(dir, file2);
163989
163989
  }
@@ -234018,7 +234018,7 @@ function normalizeBase44Env() {
234018
234018
  loadProjectEnvFiles();
234019
234019
 
234020
234020
  // src/cli/index.ts
234021
- import { dirname as dirname25, join as join30 } from "node:path";
234021
+ import { dirname as dirname26, join as join30 } from "node:path";
234022
234022
  import { fileURLToPath as fileURLToPath6 } from "node:url";
234023
234023
 
234024
234024
  // ../../node_modules/@clack/core/dist/index.mjs
@@ -243757,6 +243757,10 @@ var RealtimeHandlerConfigSchema = exports_external.object({
243757
243757
  name: exports_external.string().min(1),
243758
243758
  entry: exports_external.string().min(1)
243759
243759
  });
243760
+ var RealtimeHandlerSchemaFileSchema = exports_external.object({
243761
+ inbound: exports_external.unknown().optional(),
243762
+ outbound: exports_external.unknown().optional()
243763
+ });
243760
243764
  var DeployRealtimeHandlerResponseSchema = exports_external.object({
243761
243765
  status: exports_external.enum(["deployed", "unchanged"]),
243762
243766
  handler_name: exports_external.string().optional()
@@ -243764,7 +243768,8 @@ var DeployRealtimeHandlerResponseSchema = exports_external.object({
243764
243768
  var RealtimeHandlerSchema = RealtimeHandlerConfigSchema.extend({
243765
243769
  entryPath: exports_external.string().min(1),
243766
243770
  filePaths: exports_external.array(exports_external.string()).min(1),
243767
- source: ResourceSourceSchema
243771
+ source: ResourceSourceSchema,
243772
+ messageSchema: exports_external.unknown().optional()
243768
243773
  });
243769
243774
 
243770
243775
  // src/core/resources/realtime-handler/api.ts
@@ -243783,7 +243788,7 @@ async function deploySingleRealtimeHandler(name2, payload) {
243783
243788
  return result.data;
243784
243789
  }
243785
243790
  // src/core/resources/realtime-handler/config.ts
243786
- import { basename as basename4, dirname as dirname8, relative as relative3 } from "node:path";
243791
+ import { basename as basename4, dirname as dirname8, join as join10, relative as relative3 } from "node:path";
243787
243792
  async function readRealtimeHandler(entryFile, realtimeDir) {
243788
243793
  const handlerDir = dirname8(entryFile);
243789
243794
  const filePaths = await globby("**/*.ts", {
@@ -243801,12 +243806,25 @@ async function readRealtimeHandler(entryFile, realtimeDir) {
243801
243806
  });
243802
243807
  }
243803
243808
  const entry = basename4(entryFile);
243809
+ const schemaPath = join10(handlerDir, "schema.jsonc");
243810
+ let messageSchema = undefined;
243811
+ if (await pathExists(schemaPath)) {
243812
+ const parsed = await readJsonFile(schemaPath);
243813
+ const result = RealtimeHandlerSchemaFileSchema.safeParse(parsed);
243814
+ if (result.success) {
243815
+ messageSchema = {
243816
+ inbound: result.data.inbound,
243817
+ outbound: result.data.outbound
243818
+ };
243819
+ }
243820
+ }
243804
243821
  return {
243805
243822
  name: name2,
243806
243823
  entry,
243807
243824
  entryPath: entryFile,
243808
243825
  filePaths,
243809
- source: { type: "project" }
243826
+ source: { type: "project" },
243827
+ messageSchema
243810
243828
  };
243811
243829
  }
243812
243830
  async function readAllRealtimeHandlers(realtimeDir) {
@@ -243925,7 +243943,14 @@ class ProjectConfigReader {
243925
243943
  }
243926
243944
  async readProjectResources(configPath, project) {
243927
243945
  const configDir = dirname10(configPath);
243928
- const [entities, functions, realtimeHandlers, agents, connectors, authConfig] = await Promise.all([
243946
+ const [
243947
+ entities,
243948
+ functions,
243949
+ realtimeHandlers,
243950
+ agents,
243951
+ connectors,
243952
+ authConfig
243953
+ ] = await Promise.all([
243929
243954
  entityResource.readAll(join11(configDir, project.entitiesDir)),
243930
243955
  functionResource.readAll(join11(configDir, project.functionsDir)),
243931
243956
  realtimeHandlerResource.readAll(join11(configDir, project.realtimeDir)),
@@ -243933,7 +243958,14 @@ class ProjectConfigReader {
243933
243958
  connectorResource.readAll(join11(configDir, project.connectorsDir)),
243934
243959
  authConfigResource.readAll(join11(configDir, project.authDir))
243935
243960
  ]);
243936
- return { entities, functions, realtimeHandlers, agents, connectors, authConfig };
243961
+ return {
243962
+ entities,
243963
+ functions,
243964
+ realtimeHandlers,
243965
+ agents,
243966
+ connectors,
243967
+ authConfig
243968
+ };
243937
243969
  }
243938
243970
  assertPluginProjectDoesNotLoadPlugins(project, configPath) {
243939
243971
  if (project.plugin && project.plugins.length > 0) {
@@ -244322,7 +244354,15 @@ async function createArchive(pathToArchive, targetArchivePath) {
244322
244354
  }
244323
244355
  // src/core/project/deploy.ts
244324
244356
  function hasResourcesToDeploy(projectData) {
244325
- const { project, entities, functions, realtimeHandlers, agents, connectors, authConfig } = projectData;
244357
+ const {
244358
+ project,
244359
+ entities,
244360
+ functions,
244361
+ realtimeHandlers,
244362
+ agents,
244363
+ connectors,
244364
+ authConfig
244365
+ } = projectData;
244326
244366
  const hasSite = Boolean(project.site?.outputDirectory);
244327
244367
  const hasEntities = entities.length > 0;
244328
244368
  const hasFunctions = functions.length > 0;
@@ -244333,7 +244373,15 @@ function hasResourcesToDeploy(projectData) {
244333
244373
  return hasEntities || hasFunctions || hasRealtimeHandlers || hasAgents || hasConnectors || hasAuthConfig || hasSite;
244334
244374
  }
244335
244375
  async function deployAll(projectData, options) {
244336
- const { project, entities, functions, realtimeHandlers, agents, connectors, authConfig } = projectData;
244376
+ const {
244377
+ project,
244378
+ entities,
244379
+ functions,
244380
+ realtimeHandlers,
244381
+ agents,
244382
+ connectors,
244383
+ authConfig
244384
+ } = projectData;
244337
244385
  await entityResource.push(entities);
244338
244386
  await deployFunctionsSequentially(functions, {
244339
244387
  onStart: options?.onFunctionStart,
@@ -253285,125 +253333,12 @@ function getFunctionsCommand() {
253285
253333
  return new Command("functions").description("Manage backend functions").addCommand(getDeployCommand()).addCommand(getDeleteCommand()).addCommand(getListCommand()).addCommand(getPullCommand());
253286
253334
  }
253287
253335
 
253288
- // src/cli/commands/realtime/deploy.ts
253289
- function parseNames3(args) {
253290
- return args.flatMap((arg) => arg.split(",")).map((n2) => n2.trim()).filter(Boolean);
253291
- }
253292
- function resolveHandlersToDeploy(names, allHandlers) {
253293
- if (names.length === 0)
253294
- return allHandlers;
253295
- const notFound = names.filter((n2) => !allHandlers.some((h2) => h2.name === n2));
253296
- if (notFound.length > 0) {
253297
- throw new InvalidInputError(`Realtime handler${notFound.length > 1 ? "s" : ""} not found in project: ${notFound.join(", ")}`);
253298
- }
253299
- return allHandlers.filter((h2) => names.includes(h2.name));
253300
- }
253301
- function formatDeployResult2(result, log) {
253302
- const label = result.name.padEnd(25);
253303
- if (result.status === "deployed") {
253304
- const timing = result.durationMs ? theme.styles.dim(` (${(result.durationMs / 1000).toFixed(1)}s)`) : "";
253305
- log.success(`${label} deployed${timing}`);
253306
- } else if (result.status === "unchanged") {
253307
- log.success(`${label} unchanged`);
253308
- } else {
253309
- log.error(`${label} error: ${result.error}`);
253310
- }
253311
- }
253312
- function buildDeploySummary2(results) {
253313
- const deployed = results.filter((r) => r.status === "deployed").length;
253314
- const unchanged = results.filter((r) => r.status === "unchanged").length;
253315
- const failed = results.filter((r) => r.status === "error").length;
253316
- const parts = [];
253317
- if (deployed > 0)
253318
- parts.push(`${deployed} deployed`);
253319
- if (unchanged > 0)
253320
- parts.push(`${unchanged} unchanged`);
253321
- if (failed > 0)
253322
- parts.push(`${failed} error${failed !== 1 ? "s" : ""}`);
253323
- return parts.join(", ") || "No realtime handlers deployed";
253324
- }
253325
- async function deployRealtimeAction({ log }, names) {
253326
- const { realtimeHandlers } = await readProjectConfig();
253327
- const toDeploy = resolveHandlersToDeploy(names, realtimeHandlers);
253328
- if (toDeploy.length === 0) {
253329
- return {
253330
- outroMessage: "No realtime handlers found. Create handlers in the 'realtime' directory."
253331
- };
253332
- }
253333
- log.info(`Found ${toDeploy.length} ${toDeploy.length === 1 ? "realtime handler" : "realtime handlers"} to deploy`);
253334
- let completed = 0;
253335
- const total = toDeploy.length;
253336
- const results = await deployRealtimeHandlersSequentially(toDeploy, {
253337
- onStart: (startNames) => {
253338
- const label = startNames.length === 1 ? startNames[0] : `${startNames.length} realtime handlers`;
253339
- log.step(theme.styles.dim(`[${completed + 1}/${total}] Deploying ${label}...`));
253340
- },
253341
- onResult: (result) => {
253342
- completed++;
253343
- formatDeployResult2(result, log);
253344
- }
253345
- });
253346
- const hasFailures = results.some((r) => r.status === "error");
253347
- if (hasFailures) {
253348
- log.message(buildDeploySummary2(results));
253349
- throw new CLIExitError(1);
253350
- }
253351
- return { outroMessage: buildDeploySummary2(results) };
253352
- }
253353
- function getDeployCommand2() {
253354
- return new Base44Command("deploy").description("Deploy realtime handlers to Base44").argument("[names...]", "Handler names to deploy (deploys all if omitted)").action(async (ctx, rawNames) => {
253355
- const names = parseNames3(rawNames);
253356
- return deployRealtimeAction(ctx, names);
253357
- });
253358
- }
253359
-
253360
- // src/cli/commands/realtime/new.ts
253361
- import { join as join22 } from "node:path";
253362
- function buildHandlerScaffold(handlerName) {
253363
- return `import { RealtimeHandler, type Conn } from "base44";
253364
-
253365
- export class ${handlerName} extends RealtimeHandler {
253366
- handleConnect(conn: Conn) {
253367
- console.log("Connected:", conn.userId);
253368
- }
253369
- handleMessage(conn: Conn, msg: unknown) {
253370
- console.log("Message:", msg);
253371
- }
253372
- handleTick() {}
253373
- handleClose(conn: Conn) {}
253374
- }
253375
- `;
253376
- }
253377
- async function newRealtimeHandlerAction(_ctx, handlerName) {
253378
- const { project: project2 } = await readProjectConfig();
253379
- const realtimeDir = join22(project2.root, project2.realtimeDir);
253380
- const handlerDir = join22(realtimeDir, handlerName);
253381
- if (await pathExists(handlerDir)) {
253382
- throw new InvalidInputError(`Realtime handler "${handlerName}" already exists at ${handlerDir}`);
253383
- }
253384
- const entryPath = join22(handlerDir, "entry.ts");
253385
- await writeFile(entryPath, buildHandlerScaffold(handlerName));
253386
- return {
253387
- outroMessage: `Created realtime handler "${handlerName}" at ${entryPath}`
253388
- };
253389
- }
253390
- function getNewCommand() {
253391
- return new Base44Command("new").description("Create a new realtime handler scaffold").argument("<HandlerName>", "Name of the realtime handler class").action(async (ctx, handlerName) => {
253392
- return newRealtimeHandlerAction(ctx, handlerName);
253393
- });
253394
- }
253395
-
253396
- // src/cli/commands/realtime/index.ts
253397
- function getRealtimeCommand() {
253398
- return new Command("realtime").description("Manage realtime handlers").addCommand(getNewCommand()).addCommand(getDeployCommand2());
253399
- }
253400
-
253401
253336
  // src/cli/commands/project/create.ts
253402
253337
  import { basename as basename5, resolve as resolve7 } from "node:path";
253403
253338
  var import_kebabCase = __toESM(require_kebabCase(), 1);
253404
253339
 
253405
253340
  // src/cli/commands/project/scaffold-shared.ts
253406
- import { join as join23 } from "node:path";
253341
+ import { join as join22 } from "node:path";
253407
253342
  var DEFAULT_TEMPLATE_ID = "backend-only";
253408
253343
  async function getTemplateById(templateId) {
253409
253344
  const templates = await listTemplates();
@@ -253462,7 +253397,7 @@ async function completeProjectSetup({
253462
253397
  updateMessage("Building project...");
253463
253398
  await execa({ cwd: resolvedPath, shell: true })`${buildCommand}`;
253464
253399
  updateMessage("Deploying site...");
253465
- return await deploySite(join23(resolvedPath, outputDirectory));
253400
+ return await deploySite(join22(resolvedPath, outputDirectory));
253466
253401
  }, {
253467
253402
  successMessage: theme.colors.base44Orange("Site deployed successfully"),
253468
253403
  errorMessage: "Failed to deploy site"
@@ -253633,7 +253568,15 @@ async function deployAction({ isNonInteractive, log }, options = {}) {
253633
253568
  outroMessage: "No resources found to deploy"
253634
253569
  };
253635
253570
  }
253636
- const { project: project2, entities, functions, realtimeHandlers, agents, connectors, authConfig } = projectData;
253571
+ const {
253572
+ project: project2,
253573
+ entities,
253574
+ functions,
253575
+ realtimeHandlers,
253576
+ agents,
253577
+ connectors,
253578
+ authConfig
253579
+ } = projectData;
253637
253580
  const summaryLines = [];
253638
253581
  if (entities.length > 0) {
253639
253582
  summaryLines.push(` - ${entities.length} ${entities.length === 1 ? "entity" : "entities"}`);
@@ -253695,7 +253638,7 @@ ${summaryLines.join(`
253695
253638
  }
253696
253639
  return { outroMessage: "App deployed successfully" };
253697
253640
  }
253698
- function getDeployCommand3() {
253641
+ function getDeployCommand2() {
253699
253642
  return new Base44Command("deploy").description("Deploy all project resources (entities, functions, agents, connectors, and site)").option("-y, --yes", "Skip confirmation prompt").action(deployAction);
253700
253643
  }
253701
253644
  async function handleOAuthConnectors(connectorResults, isNonInteractive, options, log) {
@@ -253935,6 +253878,48 @@ function formatEntry(entry) {
253935
253878
  const message = entry.message.trim();
253936
253879
  return `${time3} ${level} ${message}`;
253937
253880
  }
253881
+ function entryKey(entry) {
253882
+ return `${entry.time} ${entry.message}`;
253883
+ }
253884
+ function selectNewEntries(entries, state) {
253885
+ const fresh = entries.filter((e2) => {
253886
+ if (e2.time < state.lastTime)
253887
+ return false;
253888
+ if (e2.time === state.lastTime && state.boundaryKeys.has(entryKey(e2))) {
253889
+ return false;
253890
+ }
253891
+ return true;
253892
+ });
253893
+ if (fresh.length === 0)
253894
+ return { fresh, nextState: state };
253895
+ const newMax = fresh.reduce((max, e2) => e2.time > max ? e2.time : max, state.lastTime);
253896
+ const boundaryKeys = newMax === state.lastTime ? new Set(state.boundaryKeys) : new Set;
253897
+ for (const e2 of fresh) {
253898
+ if (e2.time === newMax)
253899
+ boundaryKeys.add(entryKey(e2));
253900
+ }
253901
+ return { fresh, nextState: { lastTime: newMax, boundaryKeys } };
253902
+ }
253903
+ function writeFollowLine(entry, jsonMode) {
253904
+ const line = jsonMode ? JSON.stringify(entry) : formatEntry(entry);
253905
+ process.stdout.write(`${line}
253906
+ `);
253907
+ }
253908
+ async function followLogs(functionNames, options, availableFunctionNames, jsonMode) {
253909
+ let state = { lastTime: "", boundaryKeys: new Set };
253910
+ let first = true;
253911
+ while (true) {
253912
+ const pollOptions = first ? options : { ...options, since: state.lastTime };
253913
+ const entries = await fetchLogsForFunctions(functionNames, pollOptions, availableFunctionNames);
253914
+ const { fresh, nextState } = selectNewEntries(entries, state);
253915
+ state = nextState;
253916
+ fresh.sort((a2, b) => a2.time.localeCompare(b.time));
253917
+ for (const entry of fresh)
253918
+ writeFollowLine(entry, jsonMode);
253919
+ first = false;
253920
+ await new Promise((resolve8) => setTimeout(resolve8, 2000));
253921
+ }
253922
+ }
253938
253923
  function formatLogs(entries, env3) {
253939
253924
  if (entries.length === 0) {
253940
253925
  if (env3 === "prod") {
@@ -254016,6 +254001,16 @@ async function logsAction(ctx, options) {
254016
254001
  outroMessage: localProjectRoot ? "No functions found in this project." : "No functions found in this app."
254017
254002
  };
254018
254003
  }
254004
+ if (options.follow) {
254005
+ if (options.until) {
254006
+ throw new InvalidInputError("--until cannot be combined with --follow (a stream has no end).");
254007
+ }
254008
+ if (options.order) {
254009
+ throw new InvalidInputError("--order cannot be combined with --follow (a live tail always streams oldest to newest).");
254010
+ }
254011
+ options.order = "asc";
254012
+ return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode);
254013
+ }
254019
254014
  let entries = await fetchLogsForFunctions(functionNames, options, availableFunctionNames);
254020
254015
  const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
254021
254016
  if (limit !== undefined && entries.length > limit) {
@@ -254031,7 +254026,7 @@ async function logsAction(ctx, options) {
254031
254026
  };
254032
254027
  }
254033
254028
  function getLogsCommand() {
254034
- return new Base44Command("logs").description("Fetch function logs for this app").option("--function <names>", "Filter by function name(s), comma-separated. If omitted, fetches logs for all project functions").option("--since <datetime>", "Show logs from this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("--until <datetime>", "Show logs until this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).addOption(new Option("--level <level>", "Filter by log level").choices([...LogLevelSchema.options]).hideHelp()).option("-n, --limit <n>", "Results per page (1-1000, default: 50)").addOption(new Option("--order <order>", "Sort order").choices(["asc", "desc"])).addOption(new Option("--env <env>", "Which deployment to read logs from: preview (current draft) or prod (published). Default: preview").choices([...LogEnvSchema.options])).action(logsAction);
254029
+ return new Base44Command("logs").description("Fetch function logs for this app").option("--function <names>", "Filter by function name(s), comma-separated. If omitted, fetches logs for all project functions").option("--since <datetime>", "Show logs from this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("--until <datetime>", "Show logs until this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).addOption(new Option("--level <level>", "Filter by log level").choices([...LogLevelSchema.options]).hideHelp()).option("-n, --limit <n>", "Results per page (1-1000, default: 50)").option("-f, --follow", "Stream new logs as they arrive").addOption(new Option("--order <order>", "Sort order").choices(["asc", "desc"])).addOption(new Option("--env <env>", "Which deployment to read logs from: preview (current draft) or prod (published). Default: preview").choices([...LogEnvSchema.options])).action(logsAction);
254035
254030
  }
254036
254031
 
254037
254032
  // src/cli/commands/project/scaffold.ts
@@ -254088,6 +254083,127 @@ Examples:
254088
254083
  $ base44 scaffold my-app --app-id app_123 Scaffolds the current dir, named "my-app"`).action(scaffoldAction);
254089
254084
  }
254090
254085
 
254086
+ // src/cli/commands/realtime/deploy.ts
254087
+ function parseNames3(args) {
254088
+ return args.flatMap((arg) => arg.split(",")).map((n2) => n2.trim()).filter(Boolean);
254089
+ }
254090
+ function resolveHandlersToDeploy(names, allHandlers) {
254091
+ if (names.length === 0)
254092
+ return allHandlers;
254093
+ const notFound = names.filter((n2) => !allHandlers.some((h2) => h2.name === n2));
254094
+ if (notFound.length > 0) {
254095
+ throw new InvalidInputError(`Realtime handler${notFound.length > 1 ? "s" : ""} not found in project: ${notFound.join(", ")}`);
254096
+ }
254097
+ return allHandlers.filter((h2) => names.includes(h2.name));
254098
+ }
254099
+ function formatDeployResult2(result, log) {
254100
+ const label = result.name.padEnd(25);
254101
+ if (result.status === "deployed") {
254102
+ const timing = result.durationMs ? theme.styles.dim(` (${(result.durationMs / 1000).toFixed(1)}s)`) : "";
254103
+ log.success(`${label} deployed${timing}`);
254104
+ } else if (result.status === "unchanged") {
254105
+ log.success(`${label} unchanged`);
254106
+ } else {
254107
+ log.error(`${label} error: ${result.error}`);
254108
+ }
254109
+ }
254110
+ function buildDeploySummary2(results) {
254111
+ const deployed = results.filter((r) => r.status === "deployed").length;
254112
+ const unchanged = results.filter((r) => r.status === "unchanged").length;
254113
+ const failed = results.filter((r) => r.status === "error").length;
254114
+ const parts = [];
254115
+ if (deployed > 0)
254116
+ parts.push(`${deployed} deployed`);
254117
+ if (unchanged > 0)
254118
+ parts.push(`${unchanged} unchanged`);
254119
+ if (failed > 0)
254120
+ parts.push(`${failed} error${failed !== 1 ? "s" : ""}`);
254121
+ return parts.join(", ") || "No realtime handlers deployed";
254122
+ }
254123
+ async function deployRealtimeAction({ log }, names) {
254124
+ const { realtimeHandlers } = await readProjectConfig();
254125
+ const toDeploy = resolveHandlersToDeploy(names, realtimeHandlers);
254126
+ if (toDeploy.length === 0) {
254127
+ return {
254128
+ outroMessage: "No realtime handlers found. Create handlers in the 'realtime' directory."
254129
+ };
254130
+ }
254131
+ log.info(`Found ${toDeploy.length} ${toDeploy.length === 1 ? "realtime handler" : "realtime handlers"} to deploy`);
254132
+ let completed = 0;
254133
+ const total = toDeploy.length;
254134
+ const results = await deployRealtimeHandlersSequentially(toDeploy, {
254135
+ onStart: (startNames) => {
254136
+ const label = startNames.length === 1 ? startNames[0] : `${startNames.length} realtime handlers`;
254137
+ log.step(theme.styles.dim(`[${completed + 1}/${total}] Deploying ${label}...`));
254138
+ },
254139
+ onResult: (result) => {
254140
+ completed++;
254141
+ formatDeployResult2(result, log);
254142
+ }
254143
+ });
254144
+ const hasFailures = results.some((r) => r.status === "error");
254145
+ if (hasFailures) {
254146
+ log.message(buildDeploySummary2(results));
254147
+ throw new CLIExitError(1);
254148
+ }
254149
+ return { outroMessage: buildDeploySummary2(results) };
254150
+ }
254151
+ function getDeployCommand3() {
254152
+ return new Base44Command("deploy").description("Deploy realtime handlers to Base44").argument("[names...]", "Handler names to deploy (deploys all if omitted)").action(async (ctx, rawNames) => {
254153
+ const names = parseNames3(rawNames);
254154
+ return deployRealtimeAction(ctx, names);
254155
+ });
254156
+ }
254157
+
254158
+ // src/cli/commands/realtime/new.ts
254159
+ import { dirname as dirname19, join as join23 } from "node:path";
254160
+ function buildHandlerScaffold(handlerName) {
254161
+ return `import { RealtimeHandler, type Conn } from "@base44/sdk";
254162
+
254163
+ interface State {
254164
+ // shared state broadcast to all clients
254165
+ }
254166
+
254167
+ interface Message {
254168
+ // messages sent from clients
254169
+ }
254170
+
254171
+ export class ${handlerName} extends RealtimeHandler<State, Message> {
254172
+ handleConnect(conn: Conn) {
254173
+ console.log("Connected:", conn.userId);
254174
+ }
254175
+ handleMessage(conn: Conn, msg: Message) {
254176
+ console.log("Message:", msg);
254177
+ }
254178
+ handleTick() {}
254179
+ handleClose(conn: Conn) {}
254180
+ }
254181
+ `;
254182
+ }
254183
+ async function newRealtimeHandlerAction(_ctx, handlerName) {
254184
+ const { project: project2 } = await readProjectConfig();
254185
+ const realtimeDir = join23(dirname19(project2.configPath), project2.realtimeDir);
254186
+ const handlerDir = join23(realtimeDir, handlerName);
254187
+ if (await pathExists(handlerDir)) {
254188
+ throw new InvalidInputError(`Realtime handler "${handlerName}" already exists at ${handlerDir}`);
254189
+ }
254190
+ const entryPath = join23(handlerDir, "entry.ts");
254191
+ await writeFile(entryPath, buildHandlerScaffold(handlerName));
254192
+ return {
254193
+ outroMessage: `Created realtime handler "${handlerName}" at ${entryPath}`
254194
+ };
254195
+ }
254196
+ function getNewCommand() {
254197
+ return new Base44Command("new").description("Create a new realtime handler scaffold").argument("<HandlerName>", "Name of the realtime handler class").action(async (ctx, handlerName) => {
254198
+ return newRealtimeHandlerAction(ctx, handlerName);
254199
+ });
254200
+ }
254201
+
254202
+ // src/cli/commands/realtime/index.ts
254203
+ function getRealtimeCommand() {
254204
+ return new Command("realtime").description("Manage realtime handlers").addCommand(getNewCommand()).addCommand(getDeployCommand3());
254205
+ }
254206
+
254091
254207
  // src/core/resources/sandbox/schema.ts
254092
254208
  var FileErrorSchema = exports_external.object({
254093
254209
  code: exports_external.string(),
@@ -254567,8 +254683,8 @@ var EMPTY_TEMPLATE = import_common_tags.stripIndent`
254567
254683
  // Auto-generated by Base44 CLI - DO NOT EDIT
254568
254684
  // Regenerate with: base44 types
254569
254685
  //
254570
- // No entities, functions, agents, or connectors found in project.
254571
- // Add resources to base44/entities/, base44/functions/, base44/agents/, or base44/connectors/
254686
+ // No entities, functions, agents, connectors, or realtime handlers found in project.
254687
+ // Add resources to base44/entities/, base44/functions/, base44/agents/, base44/connectors/, or base44/realtime/
254572
254688
  // and run \`base44 types generate\` again.
254573
254689
 
254574
254690
  declare module '@base44/sdk' {
@@ -254580,11 +254696,14 @@ async function generateTypesFile(input) {
254580
254696
  await writeFile(getTypesOutputPath(input.projectRoot), content);
254581
254697
  }
254582
254698
  async function generateContent(input) {
254583
- const { entities, functions, agents, connectors } = input;
254584
- if (!entities.length && !functions.length && !agents.length && !connectors.length) {
254699
+ const { entities, functions, agents, connectors, realtimeHandlers } = input;
254700
+ if (!entities.length && !functions.length && !agents.length && !connectors.length && !realtimeHandlers.length) {
254585
254701
  return EMPTY_TEMPLATE;
254586
254702
  }
254587
- const entityInterfaces = await Promise.all(entities.map((e8) => compileEntity(e8)));
254703
+ const [entityInterfaces, realtimeRegistryEntries] = await Promise.all([
254704
+ Promise.all(entities.map((e8) => compileEntity(e8))),
254705
+ Promise.all(realtimeHandlers.map((h5) => compileRealtimeHandler(h5)))
254706
+ ]);
254588
254707
  const registryEntries = [
254589
254708
  [
254590
254709
  "EntityTypeRegistry",
@@ -254592,7 +254711,18 @@ async function generateContent(input) {
254592
254711
  ],
254593
254712
  ["FunctionNameRegistry", functions.map((f7) => `"${f7.name}": true;`)],
254594
254713
  ["AgentNameRegistry", agents.map((a5) => `"${a5.name}": true;`)],
254595
- ["ConnectorTypeRegistry", connectors.map((c8) => `"${c8.type}": true;`)]
254714
+ ["ConnectorTypeRegistry", connectors.map((c8) => `"${c8.type}": true;`)],
254715
+ [
254716
+ "RealtimeHandlerNameRegistry",
254717
+ realtimeHandlers.map((h5) => `"${h5.name}": true;`)
254718
+ ],
254719
+ [
254720
+ "RealtimeHandlerRegistry",
254721
+ realtimeHandlers.filter((h5) => h5.messageSchema).map((h5, _10, arr) => {
254722
+ const idx = realtimeHandlers.indexOf(h5);
254723
+ return `"${h5.name}": ${realtimeRegistryEntries[idx]};`;
254724
+ })
254725
+ ]
254596
254726
  ];
254597
254727
  const registries2 = registryEntries.filter(([, entries]) => entries.length > 0).map(([name2, entries]) => registry2(name2, entries));
254598
254728
  return [
@@ -254629,6 +254759,32 @@ async function compileEntity(entity2) {
254629
254759
  throw new TypeGenerationError(`Failed to generate types for entity "${name2}"`, name2, error48);
254630
254760
  }
254631
254761
  }
254762
+ async function compileRealtimeHandler(handler) {
254763
+ const { messageSchema } = handler;
254764
+ if (!messageSchema)
254765
+ return "{ inbound: unknown; outbound: unknown }";
254766
+ const compileSchema = async (schema11, typeName) => {
254767
+ if (!schema11)
254768
+ return "unknown";
254769
+ try {
254770
+ const ts8 = await import_json_schema_to_typescript.compile(schema11, typeName, {
254771
+ bannerComment: "",
254772
+ additionalProperties: false,
254773
+ strictIndexSignatures: true
254774
+ });
254775
+ const match = ts8.match(/\{([^]*)\}/);
254776
+ return match ? `{
254777
+ ${match[1]}}` : "unknown";
254778
+ } catch {
254779
+ return "unknown";
254780
+ }
254781
+ };
254782
+ const [inbound, outbound] = await Promise.all([
254783
+ compileSchema(messageSchema.inbound, `${handler.name}Inbound`),
254784
+ compileSchema(messageSchema.outbound, `${handler.name}Outbound`)
254785
+ ]);
254786
+ return `{ inbound: ${inbound}; outbound: ${outbound} }`;
254787
+ }
254632
254788
  function registry2(name2, entries) {
254633
254789
  return import_common_tags.source`
254634
254790
  interface ${name2} {
@@ -254668,14 +254824,15 @@ var TYPES_FILE_PATH = "base44/.types/types.d.ts";
254668
254824
  async function generateTypesAction({
254669
254825
  runTask: runTask2
254670
254826
  }) {
254671
- const { entities, functions, agents, connectors, project: project2 } = await readProjectConfig();
254827
+ const { entities, functions, agents, connectors, realtimeHandlers, project: project2 } = await readProjectConfig();
254672
254828
  await runTask2("Generating types", async () => {
254673
254829
  await generateTypesFile({
254674
254830
  projectRoot: project2.root,
254675
254831
  entities,
254676
254832
  functions,
254677
254833
  agents,
254678
- connectors
254834
+ connectors,
254835
+ realtimeHandlers
254679
254836
  });
254680
254837
  });
254681
254838
  const tsconfigUpdated = await updateProjectConfig(project2.root);
@@ -254695,7 +254852,7 @@ function getTypesCommand() {
254695
254852
  // src/cli/dev/dev-server/main.ts
254696
254853
  var import_cors = __toESM(require_lib4(), 1);
254697
254854
  var import_express6 = __toESM(require_express(), 1);
254698
- import { dirname as dirname23, join as join29 } from "node:path";
254855
+ import { dirname as dirname24, join as join29 } from "node:path";
254699
254856
 
254700
254857
  // ../../node_modules/get-port/index.js
254701
254858
  import net from "node:net";
@@ -257053,9 +257210,9 @@ class NodeFsHandler {
257053
257210
  if (this.fsw.closed) {
257054
257211
  return;
257055
257212
  }
257056
- const dirname22 = sp2.dirname(file2);
257213
+ const dirname23 = sp2.dirname(file2);
257057
257214
  const basename8 = sp2.basename(file2);
257058
- const parent = this.fsw._getWatchedDir(dirname22);
257215
+ const parent = this.fsw._getWatchedDir(dirname23);
257059
257216
  let prevStats = stats;
257060
257217
  if (parent.has(basename8))
257061
257218
  return;
@@ -257082,7 +257239,7 @@ class NodeFsHandler {
257082
257239
  prevStats = newStats2;
257083
257240
  }
257084
257241
  } catch (error48) {
257085
- this.fsw._remove(dirname22, basename8);
257242
+ this.fsw._remove(dirname23, basename8);
257086
257243
  }
257087
257244
  } else if (parent.has(basename8)) {
257088
257245
  const at13 = newStats.atimeMs;
@@ -258115,8 +258272,8 @@ async function createDevServer(options8) {
258115
258272
  broadcastEntityEvent(io6, appId, entityName, event);
258116
258273
  };
258117
258274
  const base44ConfigWatcher = new WatchBase44({
258118
- functions: join29(dirname23(project2.configPath), project2.functionsDir),
258119
- entities: join29(dirname23(project2.configPath), project2.entitiesDir)
258275
+ functions: join29(dirname24(project2.configPath), project2.functionsDir),
258276
+ entities: join29(dirname24(project2.configPath), project2.entitiesDir)
258120
258277
  }, devLogger);
258121
258278
  base44ConfigWatcher.on("change", async (name2) => {
258122
258279
  try {
@@ -258458,7 +258615,7 @@ function createProgram(context) {
258458
258615
  program2.addCommand(getCreateCommand());
258459
258616
  program2.addCommand(getScaffoldCommand());
258460
258617
  program2.addCommand(getDashboardCommand());
258461
- program2.addCommand(getDeployCommand3());
258618
+ program2.addCommand(getDeployCommand2());
258462
258619
  program2.addCommand(getLinkCommand());
258463
258620
  program2.addCommand(getEjectCommand());
258464
258621
  program2.addCommand(getEntitiesPushCommand());
@@ -258482,7 +258639,7 @@ var import_detect_agent = __toESM(require_dist5(), 1);
258482
258639
  import { release, type } from "node:os";
258483
258640
 
258484
258641
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
258485
- import { dirname as dirname24, posix, sep } from "path";
258642
+ import { dirname as dirname25, posix, sep } from "path";
258486
258643
  function createModulerModifier() {
258487
258644
  const getModuleFromFileName = createGetModuleFromFilename();
258488
258645
  return async (frames) => {
@@ -258491,7 +258648,7 @@ function createModulerModifier() {
258491
258648
  return frames;
258492
258649
  };
258493
258650
  }
258494
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname24(process.argv[1]) : process.cwd(), isWindows5 = sep === "\\") {
258651
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname25(process.argv[1]) : process.cwd(), isWindows5 = sep === "\\") {
258495
258652
  const normalizedBase = isWindows5 ? normalizeWindowsPath2(basePath) : basePath;
258496
258653
  return (filename) => {
258497
258654
  if (!filename)
@@ -262680,7 +262837,7 @@ function addCommandInfoToErrorReporter(program2, errorReporter) {
262680
262837
  });
262681
262838
  }
262682
262839
  // src/cli/index.ts
262683
- var __dirname4 = dirname25(fileURLToPath6(import.meta.url));
262840
+ var __dirname4 = dirname26(fileURLToPath6(import.meta.url));
262684
262841
  async function runCLI(options8) {
262685
262842
  ensureNpmAssets(join30(__dirname4, "../assets"));
262686
262843
  const errorReporter = new ErrorReporter;
@@ -262721,4 +262878,4 @@ export {
262721
262878
  CLIExitError
262722
262879
  };
262723
262880
 
262724
- //# debugId=C07D776F1F23BE1C64756E2164756E21
262881
+ //# debugId=EDDB07DEADDF53C864756E2164756E21