@base44-preview/cli 0.0.45-pr.422.d49cf05 → 0.0.45-pr.424.8513daf

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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Deno Function Wrapper
3
+ *
4
+ * This script is executed by Deno to run user functions.
5
+ * It patches Deno.serve to inject a dynamic port before importing the user's function.
6
+ *
7
+ * Environment variables:
8
+ * - FUNCTION_PATH: Absolute path to the user's function entry file
9
+ * - FUNCTION_PORT: Port number for the function to listen on
10
+ * - FUNCTION_NAME: Name of the function (for logging)
11
+ */
12
+
13
+ // Make this file a module for top-level await support
14
+ export {};
15
+
16
+ const functionPath = Deno.env.get("FUNCTION_PATH");
17
+ const port = parseInt(Deno.env.get("FUNCTION_PORT") || "8000", 10);
18
+ const functionName = Deno.env.get("FUNCTION_NAME") || "unknown";
19
+
20
+ if (!functionPath) {
21
+ console.error("[wrapper] FUNCTION_PATH environment variable is required");
22
+ Deno.exit(1);
23
+ }
24
+
25
+ // Store the original Deno.serve
26
+ const originalServe = Deno.serve.bind(Deno);
27
+
28
+ // Patch Deno.serve to inject our port and add onListen callback
29
+ // @ts-expect-error - We're intentionally overriding Deno.serve
30
+ Deno.serve = (
31
+ optionsOrHandler:
32
+ | Deno.ServeOptions
33
+ | Deno.ServeHandler
34
+ | (Deno.ServeOptions & { handler: Deno.ServeHandler }),
35
+ maybeHandler?: Deno.ServeHandler,
36
+ ): Deno.HttpServer<Deno.NetAddr> => {
37
+ const onListen = () => {
38
+ // This message is used by FunctionManager to detect when the function is ready
39
+ console.log(`[${functionName}] Listening on http://localhost:${port}`);
40
+ };
41
+
42
+ // Handle the different Deno.serve signatures:
43
+ // 1. Deno.serve(handler)
44
+ // 2. Deno.serve(options, handler)
45
+ // 3. Deno.serve({ ...options, handler })
46
+ if (typeof optionsOrHandler === "function") {
47
+ // Signature: Deno.serve(handler)
48
+ return originalServe({ port, onListen }, optionsOrHandler);
49
+ }
50
+
51
+ if (maybeHandler) {
52
+ // Signature: Deno.serve(options, handler)
53
+ return originalServe({ ...optionsOrHandler, port, onListen }, maybeHandler);
54
+ }
55
+
56
+ // Signature: Deno.serve({ ...options, handler })
57
+ const options = optionsOrHandler as Deno.ServeOptions & {
58
+ handler: Deno.ServeHandler;
59
+ };
60
+ return originalServe({ ...options, port, onListen });
61
+ };
62
+
63
+ console.log(`[${functionName}] Starting function from ${functionPath}`);
64
+
65
+ // Dynamically import the user's function
66
+ // The function will call Deno.serve which is now patched to use our port
67
+ try {
68
+ await import(functionPath);
69
+ } catch (error) {
70
+ console.error(`[${functionName}] Failed to load function:`, error);
71
+ Deno.exit(1);
72
+ }
package/dist/cli/index.js CHANGED
@@ -141617,12 +141617,12 @@ var require_linker = __commonJS((exports) => {
141617
141617
  var require_optionValidator = __commonJS((exports) => {
141618
141618
  Object.defineProperty(exports, "__esModule", { value: true });
141619
141619
  exports.validateOptions = undefined;
141620
- function validateOptions3({ maxItems }) {
141620
+ function validateOptions2({ maxItems }) {
141621
141621
  if (maxItems !== undefined && maxItems < -1) {
141622
141622
  throw RangeError(`Expected options.maxItems to be >= -1, but was given ${maxItems}.`);
141623
141623
  }
141624
141624
  }
141625
- exports.validateOptions = validateOptions3;
141625
+ exports.validateOptions = validateOptions2;
141626
141626
  });
141627
141627
 
141628
141628
  // ../../node_modules/json-schema-to-typescript/dist/src/index.js
@@ -238351,6 +238351,61 @@ async function fetchFunctionLogs(functionName, filters = {}) {
238351
238351
  }
238352
238352
  return result.data;
238353
238353
  }
238354
+ function buildStreamQueryString(filters) {
238355
+ const params = new URLSearchParams;
238356
+ if (filters.level) {
238357
+ params.set("level", filters.level);
238358
+ }
238359
+ return params;
238360
+ }
238361
+ async function* streamFunctionLogs(functionName, filters = {}, signal) {
238362
+ const appClient = getAppClient();
238363
+ const searchParams = buildStreamQueryString(filters);
238364
+ let response;
238365
+ try {
238366
+ response = await appClient.get(`functions-mgmt/${encodeURIComponent(functionName)}/logs/stream`, {
238367
+ searchParams,
238368
+ timeout: false,
238369
+ signal
238370
+ });
238371
+ } catch (error48) {
238372
+ throw await ApiError.fromHttpError(error48, `streaming function logs: '${functionName}'`);
238373
+ }
238374
+ if (!response.body) {
238375
+ throw new ApiError("Server returned empty response for log stream");
238376
+ }
238377
+ const reader = response.body.getReader();
238378
+ const decoder = new TextDecoder;
238379
+ let buffer = "";
238380
+ try {
238381
+ while (true) {
238382
+ const { done, value } = await reader.read();
238383
+ if (done)
238384
+ break;
238385
+ buffer += decoder.decode(value, { stream: true });
238386
+ for (let newlineIndex = buffer.indexOf(`
238387
+ `);newlineIndex !== -1; newlineIndex = buffer.indexOf(`
238388
+ `)) {
238389
+ const line = buffer.slice(0, newlineIndex).trimEnd();
238390
+ buffer = buffer.slice(newlineIndex + 1);
238391
+ if (line === "" || line.startsWith(":")) {
238392
+ continue;
238393
+ }
238394
+ if (line.startsWith("data: ")) {
238395
+ const jsonStr = line.slice(6);
238396
+ try {
238397
+ const parsed = FunctionLogEntrySchema.safeParse(JSON.parse(jsonStr));
238398
+ if (parsed.success) {
238399
+ yield parsed.data;
238400
+ }
238401
+ } catch {}
238402
+ }
238403
+ }
238404
+ }
238405
+ } finally {
238406
+ reader.releaseLock();
238407
+ }
238408
+ }
238354
238409
  // src/core/resources/function/config.ts
238355
238410
  import { basename as basename2, dirname as dirname3, join as join5, relative } from "node:path";
238356
238411
  async function readFunctionConfig(configPath) {
@@ -238807,7 +238862,7 @@ function getTemplatesIndexPath() {
238807
238862
  return join8(ASSETS_DIR, "templates", "templates.json");
238808
238863
  }
238809
238864
  function getDenoWrapperPath() {
238810
- return join8(ASSETS_DIR, "deno-runtime", "main.js");
238865
+ return join8(ASSETS_DIR, "deno-runtime", "main.ts");
238811
238866
  }
238812
238867
  function ensureNpmAssets(sourceDir) {
238813
238868
  if (existsSync(ASSETS_DIR))
@@ -246812,152 +246867,6 @@ function getAgentsCommand(context) {
246812
246867
  return new Command("agents").description("Manage project agents").addCommand(getAgentsPushCommand(context)).addCommand(getAgentsPullCommand(context));
246813
246868
  }
246814
246869
 
246815
- // src/core/auth-config/schema.ts
246816
- var GoogleOAuthMode = exports_external.enum(["default", "custom"]);
246817
- var AuthConfigSchema = exports_external.object({
246818
- enable_username_password: exports_external.boolean(),
246819
- enable_google_login: exports_external.boolean(),
246820
- enable_microsoft_login: exports_external.boolean(),
246821
- enable_facebook_login: exports_external.boolean(),
246822
- enable_apple_login: exports_external.boolean(),
246823
- sso_provider_name: exports_external.string().nullable(),
246824
- enable_sso_login: exports_external.boolean(),
246825
- google_oauth_mode: GoogleOAuthMode,
246826
- google_oauth_client_id: exports_external.string().nullable(),
246827
- use_workspace_sso: exports_external.boolean()
246828
- }).transform((data) => ({
246829
- enableUsernamePassword: data.enable_username_password,
246830
- enableGoogleLogin: data.enable_google_login,
246831
- enableMicrosoftLogin: data.enable_microsoft_login,
246832
- enableFacebookLogin: data.enable_facebook_login,
246833
- enableAppleLogin: data.enable_apple_login,
246834
- ssoProviderName: data.sso_provider_name,
246835
- enableSSOLogin: data.enable_sso_login,
246836
- googleOAuthMode: data.google_oauth_mode,
246837
- googleOAuthClientId: data.google_oauth_client_id,
246838
- useWorkspaceSSO: data.use_workspace_sso
246839
- }));
246840
- var AppAuthConfigResponseSchema = exports_external.object({
246841
- auth_config: AuthConfigSchema
246842
- }).transform((data) => ({
246843
- authConfig: data.auth_config
246844
- }));
246845
- function toAuthConfigPayload(config10) {
246846
- return {
246847
- enable_username_password: config10.enableUsernamePassword,
246848
- enable_google_login: config10.enableGoogleLogin,
246849
- enable_microsoft_login: config10.enableMicrosoftLogin,
246850
- enable_facebook_login: config10.enableFacebookLogin,
246851
- enable_apple_login: config10.enableAppleLogin,
246852
- sso_provider_name: config10.ssoProviderName,
246853
- enable_sso_login: config10.enableSSOLogin,
246854
- google_oauth_mode: config10.googleOAuthMode,
246855
- google_oauth_client_id: config10.googleOAuthClientId,
246856
- use_workspace_sso: config10.useWorkspaceSSO
246857
- };
246858
- }
246859
-
246860
- // src/core/auth-config/api.ts
246861
- async function getAuthConfig() {
246862
- const { id } = getAppConfig();
246863
- let response;
246864
- try {
246865
- response = await base44Client.get(`api/apps/${id}`);
246866
- } catch (error48) {
246867
- throw await ApiError.fromHttpError(error48, "fetching auth config");
246868
- }
246869
- const result = AppAuthConfigResponseSchema.safeParse(await response.json());
246870
- if (!result.success) {
246871
- throw new SchemaValidationError("Invalid response from server", result.error);
246872
- }
246873
- return result.data.authConfig;
246874
- }
246875
- async function updateAuthConfig(updates) {
246876
- const current = await getAuthConfig();
246877
- const merged = { ...current, ...updates };
246878
- const { id } = getAppConfig();
246879
- let response;
246880
- try {
246881
- response = await base44Client.put(`api/apps/${id}`, {
246882
- json: { auth_config: toAuthConfigPayload(merged) }
246883
- });
246884
- } catch (error48) {
246885
- throw await ApiError.fromHttpError(error48, "updating auth config");
246886
- }
246887
- const result = AppAuthConfigResponseSchema.safeParse(await response.json());
246888
- if (!result.success) {
246889
- throw new SchemaValidationError("Invalid response from server", result.error);
246890
- }
246891
- return result.data.authConfig;
246892
- }
246893
- function hasAnyLoginMethod(config10) {
246894
- return config10.enableUsernamePassword || config10.enableGoogleLogin || config10.enableMicrosoftLogin || config10.enableFacebookLogin || config10.enableAppleLogin || config10.enableSSOLogin;
246895
- }
246896
- async function updatePasswordAuth(enable) {
246897
- return await updateAuthConfig({ enableUsernamePassword: enable });
246898
- }
246899
- // src/cli/commands/auth/password-login.ts
246900
- function validateOptions2(options) {
246901
- const errors5 = [];
246902
- if (!options.enable && !options.disable) {
246903
- errors5.push("Missing required flag: specify --enable or --disable");
246904
- }
246905
- if (options.enable && options.disable) {
246906
- errors5.push("Conflicting flags: --enable and --disable cannot be used together");
246907
- }
246908
- if (errors5.length > 0) {
246909
- throw new InvalidInputError(errors5.join(`
246910
- `), {
246911
- hints: [
246912
- {
246913
- message: "Enable password auth: base44 auth password-login --enable",
246914
- command: "base44 auth password-login --enable"
246915
- },
246916
- {
246917
- message: "Disable password auth: base44 auth password-login --disable",
246918
- command: "base44 auth password-login --disable"
246919
- }
246920
- ]
246921
- });
246922
- }
246923
- }
246924
- async function passwordLoginAction(options) {
246925
- validateOptions2(options);
246926
- const shouldEnable = !!options.enable;
246927
- const current = await runTask("Fetching current auth config", async () => await getAuthConfig());
246928
- if (shouldEnable === current.enableUsernamePassword) {
246929
- const status = shouldEnable ? "enabled" : "disabled";
246930
- return {
246931
- outroMessage: `Username & password authentication is already ${status}`
246932
- };
246933
- }
246934
- if (!shouldEnable) {
246935
- const configWithoutPassword = {
246936
- ...current,
246937
- enableUsernamePassword: false
246938
- };
246939
- if (!hasAnyLoginMethod(configWithoutPassword)) {
246940
- R2.warn("Disabling password auth will leave no login methods enabled. Users will be locked out.");
246941
- }
246942
- }
246943
- const action = shouldEnable ? "Enabling" : "Disabling";
246944
- await runTask(`${action} username & password authentication`, async () => await updatePasswordAuth(shouldEnable));
246945
- const newStatus = shouldEnable ? "enabled" : "disabled";
246946
- return {
246947
- outroMessage: `Username & password authentication ${newStatus}`
246948
- };
246949
- }
246950
- function getPasswordLoginCommand(context) {
246951
- return new Command("password-login").description("Enable or disable username & password authentication").option("--enable", "Enable password authentication").option("--disable", "Disable password authentication").action(async (options) => {
246952
- await runCommand(() => passwordLoginAction(options), { requireAuth: true }, context);
246953
- });
246954
- }
246955
-
246956
- // src/cli/commands/auth/index.ts
246957
- function getAuthCommand(context) {
246958
- return new Command("auth").description("Manage app authentication settings").addCommand(getPasswordLoginCommand(context));
246959
- }
246960
-
246961
246870
  // src/cli/commands/auth/login.ts
246962
246871
  function getLoginCommand(context) {
246963
246872
  return new Command("login").description("Authenticate with Base44").action(async () => {
@@ -248645,6 +248554,91 @@ function validateLimit(limit) {
248645
248554
  throw new InvalidInputError(`Invalid limit: "${limit}". Must be a number between 1 and 1000.`);
248646
248555
  }
248647
248556
  }
248557
+ function validateTailFlags(options) {
248558
+ if (!options.tail)
248559
+ return;
248560
+ const incompatible = [
248561
+ ["--since", options.since],
248562
+ ["--until", options.until],
248563
+ ["--limit", options.limit],
248564
+ ["--order", options.order]
248565
+ ];
248566
+ for (const [flag, value] of incompatible) {
248567
+ if (value !== undefined) {
248568
+ throw new InvalidInputError(`Cannot use ${flag} with --tail`);
248569
+ }
248570
+ }
248571
+ }
248572
+ function formatStreamEntry(entry, functionName, json2) {
248573
+ if (json2) {
248574
+ return JSON.stringify({
248575
+ source: functionName,
248576
+ time: entry.time,
248577
+ level: entry.level,
248578
+ message: entry.message
248579
+ });
248580
+ }
248581
+ const normalized = normalizeLogEntry(entry, functionName);
248582
+ return formatEntry(normalized);
248583
+ }
248584
+ async function consumeStream(functionName, filters, signal, json2) {
248585
+ try {
248586
+ for await (const entry of streamFunctionLogs(functionName, filters, signal)) {
248587
+ process.stdout.write(`${formatStreamEntry(entry, functionName, json2)}
248588
+ `);
248589
+ }
248590
+ return "ended";
248591
+ } catch (error48) {
248592
+ if (signal.aborted)
248593
+ return "aborted";
248594
+ throw error48;
248595
+ }
248596
+ }
248597
+ async function tailAction(options) {
248598
+ validateTailFlags(options);
248599
+ const specifiedFunctions = parseFunctionNames(options.function);
248600
+ const allProjectFunctions = await getAllFunctionNames();
248601
+ const functionNames = specifiedFunctions.length > 0 ? specifiedFunctions : allProjectFunctions;
248602
+ if (functionNames.length === 0) {
248603
+ return { outroMessage: "No functions found in this project." };
248604
+ }
248605
+ const filters = {};
248606
+ if (options.level) {
248607
+ filters.level = options.level;
248608
+ }
248609
+ const json2 = options.json ?? false;
248610
+ const functionList = functionNames.join(", ");
248611
+ R2.info(`Tailing logs for ${functionList}... (Ctrl+C to stop)`);
248612
+ const controller = new AbortController;
248613
+ const onSigint = () => controller.abort();
248614
+ process.on("SIGINT", onSigint);
248615
+ let userAborted = false;
248616
+ try {
248617
+ if (functionNames.length === 1) {
248618
+ const result = await consumeStream(functionNames[0], filters, controller.signal, json2);
248619
+ userAborted = result === "aborted";
248620
+ } else {
248621
+ const results = await Promise.allSettled(functionNames.map((fn) => consumeStream(fn, filters, controller.signal, json2)));
248622
+ const allFailed = results.every((r) => r.status === "rejected");
248623
+ if (allFailed && !controller.signal.aborted) {
248624
+ const firstError = results.find((r) => r.status === "rejected");
248625
+ throw firstError.reason;
248626
+ }
248627
+ for (let i2 = 0;i2 < results.length; i2++) {
248628
+ const result = results[i2];
248629
+ if (result.status === "rejected" && !controller.signal.aborted) {
248630
+ R2.warn(`Connection lost for function '${functionNames[i2]}'`);
248631
+ }
248632
+ }
248633
+ userAborted = controller.signal.aborted;
248634
+ }
248635
+ } finally {
248636
+ process.removeListener("SIGINT", onSigint);
248637
+ }
248638
+ return {
248639
+ outroMessage: userAborted ? "Stream closed" : "Stream ended"
248640
+ };
248641
+ }
248648
248642
  async function logsAction(options) {
248649
248643
  validateLimit(options.limit);
248650
248644
  const specifiedFunctions = parseFunctionNames(options.function);
@@ -248663,8 +248657,9 @@ async function logsAction(options) {
248663
248657
  return { outroMessage: "Fetched logs", stdout: logsOutput };
248664
248658
  }
248665
248659
  function getLogsCommand(context) {
248666
- return new Command("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 format)", normalizeDatetime).option("--until <datetime>", "Show logs until this time (ISO format)", 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"])).action(async (options) => {
248667
- await runCommand(() => logsAction(options), { requireAuth: true }, context);
248660
+ return new Command("logs").description("Fetch function logs for this app (use --tail to stream in real-time)").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 format)", normalizeDatetime).option("--until <datetime>", "Show logs until this time (ISO format)", 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"])).option("--json", "Output raw JSON").option("-f, --tail", "Stream logs in real-time").action(async (options) => {
248661
+ const action = options.tail ? () => tailAction(options) : () => logsAction(options);
248662
+ await runCommand(action, { requireAuth: true }, context);
248668
248663
  });
248669
248664
  }
248670
248665
 
@@ -251861,7 +251856,6 @@ function createProgram(context) {
251861
251856
  program2.addCommand(getConnectorsCommand(context));
251862
251857
  program2.addCommand(getFunctionsCommand(context));
251863
251858
  program2.addCommand(getSecretsCommand(context));
251864
- program2.addCommand(getAuthCommand(context));
251865
251859
  program2.addCommand(getSiteCommand(context));
251866
251860
  program2.addCommand(getTypesCommand(context));
251867
251861
  program2.addCommand(getDevCommand(context), { hidden: true });
@@ -256107,4 +256101,4 @@ export {
256107
256101
  CLIExitError
256108
256102
  };
256109
256103
 
256110
- //# debugId=FD70C1725704242064756E2164756E21
256104
+ //# debugId=FFECB82AD6C33D2764756E2164756E21