@base44-preview/cli 0.0.50-pr.484.f8f85fa → 0.0.50-pr.487.fc1c45a

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
@@ -219982,7 +219982,8 @@ var theme = {
219982
219982
  bold: source_default.bold,
219983
219983
  dim: source_default.dim,
219984
219984
  error: source_default.red,
219985
- warn: source_default.yellow
219985
+ warn: source_default.yellow,
219986
+ info: source_default.cyan
219986
219987
  },
219987
219988
  format: {
219988
219989
  errorContext(ctx) {
@@ -242001,88 +242002,121 @@ async function pushCustomOAuthSecret(provider, clientSecret) {
242001
242002
  [providerInfo.customOAuth.secretKey]: clientSecret
242002
242003
  });
242003
242004
  }
242004
- // src/core/resources/auth-config/sso.ts
242005
- var KNOWN_SSO_PROVIDERS = [
242006
- "google",
242007
- "microsoft",
242008
- "github",
242009
- "okta",
242010
- "custom"
242011
- ];
242012
- var BASE_SSO_SCOPE = "openid email profile";
242013
- var SSO_PROVIDER_SCHEMAS = {
242014
- google: {
242015
- requiredKeys: [],
242016
- defaults: {
242017
- sso_scope: BASE_SSO_SCOPE,
242018
- sso_discovery_url: "https://accounts.google.com/.well-known/openid-configuration"
242019
- }
242020
- },
242021
- microsoft: {
242022
- requiredKeys: ["sso_tenant_id"],
242023
- defaults: {
242024
- sso_scope: BASE_SSO_SCOPE
242025
- },
242026
- deriveDefaults: (options) => {
242027
- const tenantId = options.sso_tenant_id;
242028
- if (tenantId) {
242029
- return {
242030
- sso_discovery_url: `https://login.microsoftonline.com/${tenantId}/v2.0/.well-known/openid-configuration`
242031
- };
242032
- }
242033
- return {};
242034
- }
242005
+ // src/core/resources/auth-config/sso/secret-keys.ts
242006
+ var SSOSecretKey;
242007
+ ((SSOSecretKey2) => {
242008
+ SSOSecretKey2["Name"] = "sso_name";
242009
+ SSOSecretKey2["ClientId"] = "sso_client_id";
242010
+ SSOSecretKey2["ClientSecret"] = "sso_client_secret";
242011
+ SSOSecretKey2["Scope"] = "sso_scope";
242012
+ SSOSecretKey2["DiscoveryUrl"] = "sso_discovery_url";
242013
+ SSOSecretKey2["TenantId"] = "sso_tenant_id";
242014
+ SSOSecretKey2["AuthEndpoint"] = "sso_auth_endpoint";
242015
+ SSOSecretKey2["TokenEndpoint"] = "sso_token_endpoint";
242016
+ SSOSecretKey2["UserinfoEndpoint"] = "sso_userinfo_endpoint";
242017
+ SSOSecretKey2["OktaDomain"] = "sso_okta_domain";
242018
+ SSOSecretKey2["JwksUri"] = "sso_jwks_uri";
242019
+ })(SSOSecretKey ||= {});
242020
+ var ALL_SSO_SECRET_KEYS = Object.values(SSOSecretKey);
242021
+ var DEFAULT_OIDC_SCOPE = "openid email profile";
242022
+ var DEFAULT_GITHUB_SCOPE = "user:email";
242023
+
242024
+ // src/core/resources/auth-config/sso/providers/custom.ts
242025
+ var customProvider = {
242026
+ requiredKeys: [
242027
+ "sso_auth_endpoint" /* AuthEndpoint */,
242028
+ "sso_token_endpoint" /* TokenEndpoint */,
242029
+ "sso_userinfo_endpoint" /* UserinfoEndpoint */,
242030
+ "sso_jwks_uri" /* JwksUri */
242031
+ ],
242032
+ defaults: {
242033
+ ["sso_scope" /* Scope */]: DEFAULT_OIDC_SCOPE
242034
+ }
242035
+ };
242036
+
242037
+ // src/core/resources/auth-config/sso/providers/github.ts
242038
+ var githubProvider = {
242039
+ requiredKeys: [],
242040
+ defaults: {
242041
+ ["sso_scope" /* Scope */]: DEFAULT_GITHUB_SCOPE,
242042
+ ["sso_auth_endpoint" /* AuthEndpoint */]: "https://github.com/login/oauth/authorize",
242043
+ ["sso_token_endpoint" /* TokenEndpoint */]: "https://github.com/login/oauth/access_token",
242044
+ ["sso_userinfo_endpoint" /* UserinfoEndpoint */]: "https://api.github.com/user"
242045
+ }
242046
+ };
242047
+
242048
+ // src/core/resources/auth-config/sso/providers/google.ts
242049
+ var googleProvider = {
242050
+ requiredKeys: [],
242051
+ defaults: {
242052
+ ["sso_scope" /* Scope */]: DEFAULT_OIDC_SCOPE,
242053
+ ["sso_discovery_url" /* DiscoveryUrl */]: "https://accounts.google.com/.well-known/openid-configuration"
242054
+ }
242055
+ };
242056
+
242057
+ // src/core/resources/auth-config/sso/providers/microsoft.ts
242058
+ var microsoftProvider = {
242059
+ requiredKeys: ["sso_tenant_id" /* TenantId */],
242060
+ defaults: {
242061
+ ["sso_scope" /* Scope */]: DEFAULT_OIDC_SCOPE
242035
242062
  },
242036
- github: {
242037
- requiredKeys: [],
242038
- defaults: {
242039
- sso_scope: "user:email",
242040
- sso_auth_endpoint: "https://github.com/login/oauth/authorize",
242041
- sso_token_endpoint: "https://github.com/login/oauth/access_token",
242042
- sso_userinfo_endpoint: "https://api.github.com/user"
242063
+ deriveDefaults: (secrets) => {
242064
+ const tenantId = secrets["sso_tenant_id" /* TenantId */];
242065
+ if (tenantId) {
242066
+ return {
242067
+ ["sso_discovery_url" /* DiscoveryUrl */]: `https://login.microsoftonline.com/${tenantId}/v2.0/.well-known/openid-configuration`
242068
+ };
242043
242069
  }
242070
+ return {};
242071
+ }
242072
+ };
242073
+
242074
+ // src/core/resources/auth-config/sso/providers/okta.ts
242075
+ var oktaProvider = {
242076
+ requiredKeys: ["sso_okta_domain" /* OktaDomain */],
242077
+ defaults: {
242078
+ ["sso_scope" /* Scope */]: DEFAULT_OIDC_SCOPE
242044
242079
  },
242045
- okta: {
242046
- requiredKeys: ["sso_okta_domain"],
242047
- defaults: {
242048
- sso_scope: BASE_SSO_SCOPE
242049
- },
242050
- deriveDefaults: (options) => {
242051
- const domain2 = options.sso_okta_domain;
242052
- if (domain2) {
242053
- return {
242054
- sso_discovery_url: `https://${domain2}/.well-known/openid-configuration`
242055
- };
242056
- }
242057
- return {};
242080
+ deriveDefaults: (secrets) => {
242081
+ const domain2 = secrets["sso_okta_domain" /* OktaDomain */];
242082
+ if (domain2) {
242083
+ return {
242084
+ ["sso_discovery_url" /* DiscoveryUrl */]: `https://${domain2}/.well-known/openid-configuration`
242085
+ };
242058
242086
  }
242059
- },
242060
- custom: {
242061
- requiredKeys: [
242062
- "sso_auth_endpoint",
242063
- "sso_token_endpoint",
242064
- "sso_userinfo_endpoint",
242065
- "sso_jwks_uri"
242066
- ],
242067
- optionalKeys: ["sso_discovery_url"],
242068
- defaults: {
242069
- sso_scope: BASE_SSO_SCOPE
242070
- }
242071
- }
242072
- };
242073
- var ALL_SSO_SECRET_KEYS = [
242074
- "sso_name",
242075
- "sso_client_id",
242076
- "sso_client_secret",
242077
- "sso_scope",
242078
- "sso_discovery_url",
242079
- "sso_tenant_id",
242080
- "sso_auth_endpoint",
242081
- "sso_token_endpoint",
242082
- "sso_userinfo_endpoint",
242083
- "sso_okta_domain",
242084
- "sso_jwks_uri"
242085
- ];
242087
+ return {};
242088
+ }
242089
+ };
242090
+
242091
+ // src/core/resources/auth-config/sso/providers/index.ts
242092
+ var SSO_PROVIDER_SCHEMAS = {
242093
+ google: googleProvider,
242094
+ microsoft: microsoftProvider,
242095
+ github: githubProvider,
242096
+ okta: oktaProvider,
242097
+ custom: customProvider
242098
+ };
242099
+
242100
+ // src/core/resources/auth-config/sso/types.ts
242101
+ var KNOWN_SSO_PROVIDERS = {
242102
+ google: "google",
242103
+ microsoft: "microsoft",
242104
+ github: "github",
242105
+ okta: "okta",
242106
+ custom: "custom"
242107
+ };
242108
+
242109
+ // src/core/resources/auth-config/sso/operations.ts
242110
+ var OPTION_TO_SECRET_KEY = {
242111
+ scope: "sso_scope" /* Scope */,
242112
+ discoveryUrl: "sso_discovery_url" /* DiscoveryUrl */,
242113
+ tenantId: "sso_tenant_id" /* TenantId */,
242114
+ oktaDomain: "sso_okta_domain" /* OktaDomain */,
242115
+ authEndpoint: "sso_auth_endpoint" /* AuthEndpoint */,
242116
+ tokenEndpoint: "sso_token_endpoint" /* TokenEndpoint */,
242117
+ userinfoEndpoint: "sso_userinfo_endpoint" /* UserinfoEndpoint */,
242118
+ jwksUri: "sso_jwks_uri" /* JwksUri */
242119
+ };
242086
242120
  async function updateSSOConfig(authDir, provider, enable) {
242087
242121
  const current = await readAuthConfig(authDir) ?? DEFAULT_AUTH_CONFIG;
242088
242122
  const merged = {
@@ -242099,22 +242133,12 @@ async function updateSSOConfig(authDir, provider, enable) {
242099
242133
  await writeAuthConfig(authDir, merged);
242100
242134
  return merged;
242101
242135
  }
242102
- var OPTION_TO_SECRET_KEY = {
242103
- scope: "sso_scope",
242104
- discoveryUrl: "sso_discovery_url",
242105
- tenantId: "sso_tenant_id",
242106
- oktaDomain: "sso_okta_domain",
242107
- authEndpoint: "sso_auth_endpoint",
242108
- tokenEndpoint: "sso_token_endpoint",
242109
- userinfoEndpoint: "sso_userinfo_endpoint",
242110
- jwksUri: "sso_jwks_uri"
242111
- };
242112
242136
  function buildSSOSecrets(provider, options) {
242113
242137
  const schema3 = SSO_PROVIDER_SCHEMAS[provider];
242114
242138
  const secrets = {};
242115
- secrets.sso_name = options.ssoName ?? provider;
242116
- secrets.sso_client_id = options.clientId;
242117
- secrets.sso_client_secret = options.clientSecret;
242139
+ secrets["sso_name" /* Name */] = options.ssoName ?? provider;
242140
+ secrets["sso_client_id" /* ClientId */] = options.clientId;
242141
+ secrets["sso_client_secret" /* ClientSecret */] = options.clientSecret;
242118
242142
  for (const [optionKey, secretKey] of Object.entries(OPTION_TO_SECRET_KEY)) {
242119
242143
  const value = options[optionKey];
242120
242144
  if (typeof value === "string" && value.length > 0) {
@@ -242140,8 +242164,8 @@ function buildSSOSecrets(provider, options) {
242140
242164
  missing.push(key);
242141
242165
  }
242142
242166
  }
242143
- if (provider === "custom" && !options.ssoName) {
242144
- missing.push("sso_name");
242167
+ if (provider === KNOWN_SSO_PROVIDERS.custom && !options.ssoName) {
242168
+ missing.push("sso_name" /* Name */);
242145
242169
  }
242146
242170
  if (missing.length > 0) {
242147
242171
  throw new InvalidInputError(`Missing required fields for ${provider}: ${missing.join(", ")}`);
@@ -243564,6 +243588,7 @@ var package_default = {
243564
243588
  "@types/ejs": "^3.1.5",
243565
243589
  "@types/express": "^5.0.6",
243566
243590
  "@types/json-schema": "^7.0.15",
243591
+ "@types/jsonwebtoken": "^9.0.10",
243567
243592
  "@types/lodash": "^4.17.24",
243568
243593
  "@types/multer": "^2.0.0",
243569
243594
  "@types/node": "^22.10.5",
@@ -243582,6 +243607,7 @@ var package_default = {
243582
243607
  globby: "^16.1.0",
243583
243608
  "http-proxy-middleware": "^3.0.5",
243584
243609
  "json-schema-to-typescript": "^15.0.4",
243610
+ jsonwebtoken: "^9.0.3",
243585
243611
  json5: "^2.2.3",
243586
243612
  ky: "^1.14.2",
243587
243613
  lodash: "^4.17.23",
@@ -243597,6 +243623,7 @@ var package_default = {
243597
243623
  typescript: "^5.7.2",
243598
243624
  vitest: "^4.0.16",
243599
243625
  yaml: "^2.8.2",
243626
+ qs: "^6.12.3",
243600
243627
  zod: "^4.3.5"
243601
243628
  },
243602
243629
  engines: {
@@ -251234,23 +251261,34 @@ function mergeFileWithFlags(fileConfig, options) {
251234
251261
  ssoName: options.ssoName ?? fileConfig.ssoName
251235
251262
  };
251236
251263
  }
251264
+ var providerNames = Object.keys(KNOWN_SSO_PROVIDERS);
251265
+ function secretKeyToFlag(key) {
251266
+ return `--${key.replace(/^sso_/, "").replace(/_/g, "-")}`;
251267
+ }
251268
+ function exampleCommand(provider) {
251269
+ let cmd = `base44 auth sso enable --provider ${provider} --client-id <id> --client-secret <secret>`;
251270
+ if (provider === KNOWN_SSO_PROVIDERS.microsoft)
251271
+ cmd += " --tenant-id <id>";
251272
+ if (provider === KNOWN_SSO_PROVIDERS.okta)
251273
+ cmd += " --okta-domain <domain>";
251274
+ if (provider === KNOWN_SSO_PROVIDERS.custom)
251275
+ cmd += " --sso-name <name> --auth-endpoint <url> --token-endpoint <url> --userinfo-endpoint <url> --jwks-uri <url>";
251276
+ return cmd;
251277
+ }
251237
251278
  function validateProvider(provider) {
251238
251279
  if (!provider) {
251239
251280
  throw new InvalidInputError("Missing --provider.", {
251240
251281
  hints: [
251241
251282
  {
251242
- message: `Valid providers: ${KNOWN_SSO_PROVIDERS.join(", ")}`,
251283
+ message: `Valid providers: ${providerNames.join(", ")}`,
251243
251284
  command: "base44 auth sso enable --provider <provider> --client-id <id> --client-secret <secret>"
251244
251285
  }
251245
251286
  ]
251246
251287
  });
251247
251288
  }
251248
- if (!KNOWN_SSO_PROVIDERS.includes(provider)) {
251249
- throw new InvalidInputError(`Unknown provider "${provider}". Valid providers: ${KNOWN_SSO_PROVIDERS.join(", ")}`);
251250
- }
251251
251289
  return provider;
251252
251290
  }
251253
- async function ssoEnableAction({ isNonInteractive, log, runTask: runTask2 }, options) {
251291
+ async function ssoEnableAction({ isNonInteractive, runTask: runTask2 }, options) {
251254
251292
  let merged = options;
251255
251293
  if (options.file) {
251256
251294
  const fileConfig = await loadSSOConfigFile(options.file);
@@ -251310,7 +251348,23 @@ async function ssoEnableAction({ isNonInteractive, log, runTask: runTask2 }, opt
251310
251348
  jwksUri: merged.jwksUri,
251311
251349
  ssoName: merged.ssoName
251312
251350
  };
251313
- const secrets = buildSSOSecrets(provider, secretOptions);
251351
+ let secrets;
251352
+ try {
251353
+ secrets = buildSSOSecrets(provider, secretOptions);
251354
+ } catch (error48) {
251355
+ if (error48 instanceof InvalidInputError) {
251356
+ const flagMessage = error48.message.replace(/sso_[a-z_]+/g, (key) => secretKeyToFlag(key));
251357
+ throw new InvalidInputError(flagMessage, {
251358
+ hints: [
251359
+ {
251360
+ message: `Example: ${exampleCommand(provider)}`,
251361
+ command: exampleCommand(provider)
251362
+ }
251363
+ ]
251364
+ });
251365
+ }
251366
+ throw error48;
251367
+ }
251314
251368
  const { project: project2 } = await readProjectConfig();
251315
251369
  const configDir = dirname11(project2.configPath);
251316
251370
  const authDir = join16(configDir, project2.authDir);
@@ -251321,7 +251375,6 @@ async function ssoEnableAction({ isNonInteractive, log, runTask: runTask2 }, opt
251321
251375
  };
251322
251376
  }
251323
251377
  async function ssoDisableAction({
251324
- log,
251325
251378
  runTask: runTask2
251326
251379
  }) {
251327
251380
  const { project: project2 } = await readProjectConfig();
@@ -251343,7 +251396,7 @@ function getSSOCommand() {
251343
251396
  return new Base44Command("sso").description("Configure SSO identity provider (google, microsoft, github, okta, custom)").addArgument(new Argument("<action>", "enable or disable SSO").choices([
251344
251397
  "enable",
251345
251398
  "disable"
251346
- ])).option("--provider <provider>", "SSO provider: google, microsoft, github, okta, custom").option("--client-id <id>", "OAuth client ID").option("--client-secret <secret>", "OAuth client secret").option("--client-secret-stdin", "Read client secret from stdin").option("--env-file <path>", "Read client secret from a .env file (key: sso_client_secret)").option("--file <path>", "JSON config file with all SSO settings").option("--scope <scope>", "OAuth scope (defaults per provider)").option("--discovery-url <url>", "OIDC discovery URL").option("--tenant-id <id>", "Microsoft tenant ID (required for microsoft)").option("--okta-domain <domain>", "Okta domain (required for okta)").option("--auth-endpoint <url>", "Authorization endpoint (required for custom)").option("--token-endpoint <url>", "Token endpoint (required for custom)").option("--userinfo-endpoint <url>", "Userinfo endpoint (required for custom)").option("--jwks-uri <url>", "JWKS URI (required for custom)").option("--sso-name <name>", "Provider display name (required for custom)").action(ssoAction);
251399
+ ])).addOption(new Option("--provider <provider>", "SSO provider").choices(Object.values(KNOWN_SSO_PROVIDERS))).option("--client-id <id>", "OAuth client ID").option("--client-secret <secret>", "OAuth client secret").option("--client-secret-stdin", "Read client secret from stdin").option("--env-file <path>", "Read client secret from a .env file (key: sso_client_secret)").option("--file <path>", "JSON config file with all SSO settings").option("--scope <scope>", "OAuth scope (defaults per provider)").option("--discovery-url <url>", "OIDC discovery URL").option("--tenant-id <id>", "Microsoft tenant ID (required for microsoft)").option("--okta-domain <domain>", "Okta domain (required for okta)").option("--auth-endpoint <url>", "Authorization endpoint (required for custom)").option("--token-endpoint <url>", "Token endpoint (required for custom)").option("--userinfo-endpoint <url>", "Userinfo endpoint (required for custom)").option("--jwks-uri <url>", "JWKS URI (required for custom)").option("--sso-name <name>", "Provider display name (required for custom)").action(ssoAction);
251347
251400
  }
251348
251401
 
251349
251402
  // src/cli/commands/auth/index.ts
@@ -253367,9 +253420,12 @@ function getTypesCommand() {
253367
253420
  return new Command("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
253368
253421
  }
253369
253422
 
253423
+ // src/cli/commands/dev.ts
253424
+ import process21 from "node:process";
253425
+
253370
253426
  // src/cli/dev/dev-server/main.ts
253371
253427
  var import_cors = __toESM(require_lib4(), 1);
253372
- var import_express5 = __toESM(require_express(), 1);
253428
+ var import_express6 = __toESM(require_express(), 1);
253373
253429
  import { dirname as dirname18, join as join25 } from "node:path";
253374
253430
 
253375
253431
  // ../../node_modules/get-port/index.js
@@ -253933,7 +253989,9 @@ class Validator {
253933
253989
  }
253934
253990
 
253935
253991
  // src/cli/dev/dev-server/db/database.ts
253992
+ var PRIVATE_COLLECTION_PREFIX = "$";
253936
253993
  var USER_COLLECTION = "user";
253994
+ var PRIVATE_USER_COLLECTION = PRIVATE_COLLECTION_PREFIX + USER_COLLECTION;
253937
253995
 
253938
253996
  class Database {
253939
253997
  collections = new Map;
@@ -253955,6 +254013,7 @@ class Database {
253955
254013
  this.schemas.set(USER_COLLECTION, this.buildUserSchema(userEntity));
253956
254014
  const collection = new import_nedb.default;
253957
254015
  this.collections.set(USER_COLLECTION, collection);
254016
+ this.collections.set(PRIVATE_USER_COLLECTION, new import_nedb.default);
253958
254017
  const userInfo = await readAuth();
253959
254018
  const now = getNowISOTimestamp();
253960
254019
  await collection.insertAsync({
@@ -253996,7 +254055,9 @@ class Database {
253996
254055
  return this.collections.get(this.normalizeName(name2));
253997
254056
  }
253998
254057
  getCollectionNames() {
253999
- return Array.from(this.collections.keys());
254058
+ return Array.from(this.collections.keys()).filter((name2) => {
254059
+ return !name2.startsWith(PRIVATE_COLLECTION_PREFIX);
254060
+ });
254000
254061
  }
254001
254062
  dropAll() {
254002
254063
  for (const collection of this.collections.values()) {
@@ -254060,15 +254121,229 @@ function broadcastEntityEvent(io6, appId, entityName, event) {
254060
254121
  });
254061
254122
  }
254062
254123
 
254063
- // src/cli/dev/dev-server/routes/entities/entities-router.ts
254064
- var import_express3 = __toESM(require_express(), 1);
254065
-
254066
- // src/cli/dev/dev-server/routes/entities/entities-user-router.ts
254124
+ // src/cli/dev/dev-server/routes/auth-router.ts
254067
254125
  var import_express2 = __toESM(require_express(), 1);
254068
254126
  var import_jsonwebtoken = __toESM(require_jsonwebtoken(), 1);
254069
- function createUserRouter(db2, logger2) {
254127
+ import { randomInt } from "node:crypto";
254128
+ var LOCAL_DEV_SECRET = "LOCAL_DEV_SECRET";
254129
+ var TEN_MINUTES = 10 * 60 * 1000;
254130
+ var generateCode = () => {
254131
+ return randomInt(1e5, 1e6).toString();
254132
+ };
254133
+ var createJwtToken = (email3) => {
254134
+ return import_jsonwebtoken.default.sign({ sub: email3 }, LOCAL_DEV_SECRET, {
254135
+ expiresIn: "360d"
254136
+ });
254137
+ };
254138
+ var LoginBody = object({ email: email2(), password: string2() });
254139
+ var VerifyOtpBody = object({ email: email2(), otp_code: string2() });
254140
+ function createAuthRouter(db2, logger2) {
254070
254141
  const router = import_express2.Router({ mergeParams: true });
254071
254142
  const parseBody = import_express2.json();
254143
+ router.post("/login", parseBody, async (req, res) => {
254144
+ const { email: email3, password } = LoginBody.parse(req.body);
254145
+ const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: email3 });
254146
+ if (result) {
254147
+ const privateUserData = await db2.getCollection(PRIVATE_USER_COLLECTION)?.findOneAsync({ email: email3 });
254148
+ if (result.role === "admin" || privateUserData?.password === password) {
254149
+ res.json({
254150
+ access_token: createJwtToken(email3),
254151
+ success: true,
254152
+ user: {}
254153
+ });
254154
+ } else {
254155
+ res.status(400).json({
254156
+ detail: "Invalid email or password",
254157
+ error_type: "HTTPException",
254158
+ message: "Invalid email or password",
254159
+ request_id: null,
254160
+ traceback: ""
254161
+ });
254162
+ }
254163
+ return;
254164
+ }
254165
+ res.status(401).json({ error: "Unauthorized" });
254166
+ });
254167
+ router.post("/register", parseBody, async (req, res) => {
254168
+ const { email: email3, password } = LoginBody.parse(req.body);
254169
+ if ((password || "").length < 8) {
254170
+ res.status(400).json({
254171
+ detail: "Password must be at least 8 characters long",
254172
+ error_type: "HTTPException",
254173
+ message: "Password must be at least 8 characters long",
254174
+ request_id: null,
254175
+ traceback: ""
254176
+ });
254177
+ return;
254178
+ }
254179
+ const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: email3 });
254180
+ if (result) {
254181
+ res.status(400).json({
254182
+ detail: "A user with this email already exists",
254183
+ error_type: "HTTPException",
254184
+ message: "A user with this email already exists",
254185
+ request_id: null,
254186
+ traceback: ""
254187
+ });
254188
+ return;
254189
+ }
254190
+ const privateUserCollection = db2.getCollection(PRIVATE_USER_COLLECTION);
254191
+ const privateUserData = await privateUserCollection?.findOneAsync({
254192
+ email: email3
254193
+ });
254194
+ const otpCode = generateCode();
254195
+ const id2 = privateUserData ? privateUserData.id : nanoid3();
254196
+ if (!privateUserData) {
254197
+ await privateUserCollection?.insertAsync({
254198
+ id: id2,
254199
+ email: email3,
254200
+ otpCode,
254201
+ password,
254202
+ createdAt: Date.now()
254203
+ });
254204
+ } else {
254205
+ await privateUserCollection?.updateAsync({
254206
+ email: email3
254207
+ }, {
254208
+ $set: {
254209
+ otpCode,
254210
+ createdAt: Date.now()
254211
+ }
254212
+ });
254213
+ }
254214
+ logger2.log(theme.styles.info(`
254215
+ In order to complete registration use this verification code: ${otpCode}
254216
+ `));
254217
+ res.json({
254218
+ id: id2,
254219
+ message: "Registration successful. Please check your email for the verification code.",
254220
+ otp_expires_in_minutes: 10
254221
+ });
254222
+ });
254223
+ router.post("/verify-otp", parseBody, async (req, res) => {
254224
+ const { email: email3, otp_code } = VerifyOtpBody.parse(req.body);
254225
+ const privateUserCollection = db2.getCollection(PRIVATE_USER_COLLECTION);
254226
+ const privateUserData = await privateUserCollection?.findOneAsync({
254227
+ email: email3
254228
+ });
254229
+ if (!privateUserData || privateUserData.otpCode !== otp_code) {
254230
+ const appId = req.params.appId;
254231
+ res.status(500).json({
254232
+ detail: `{'email': '${email3}', 'app_id': '${appId}}'} -> Object not found`,
254233
+ error_type: "ObjectNotFoundError",
254234
+ message: `{'email': '${email3}', 'app_id': '${appId}}'} -> Object not found`,
254235
+ request_id: null,
254236
+ traceback: ""
254237
+ });
254238
+ return;
254239
+ }
254240
+ if (+Date.now() - privateUserData.createdAt > TEN_MINUTES) {
254241
+ res.status(400).json({
254242
+ detail: "Verification code has expired",
254243
+ error_type: "HTTPException",
254244
+ message: "Verification code has expired",
254245
+ request_id: null,
254246
+ traceback: ""
254247
+ });
254248
+ } else {
254249
+ await privateUserCollection?.updateAsync({
254250
+ email: email3
254251
+ }, {
254252
+ $unset: { otpCode: true }
254253
+ });
254254
+ const collection = db2.getCollection(USER_COLLECTION);
254255
+ const now = getNowISOTimestamp();
254256
+ const nameFromEmailMatch = /^([^@]+)/.exec(email3);
254257
+ const fullName = nameFromEmailMatch ? nameFromEmailMatch[1] : email3;
254258
+ await collection?.insertAsync({
254259
+ id: privateUserData.id,
254260
+ email: email3,
254261
+ full_name: fullName,
254262
+ is_service: false,
254263
+ is_verified: true,
254264
+ disabled: null,
254265
+ role: "user",
254266
+ collaborator_role: "editor",
254267
+ created_date: now,
254268
+ updated_date: now
254269
+ });
254270
+ res.json({
254271
+ id: privateUserData.id,
254272
+ access_token: createJwtToken(email3),
254273
+ message: "Email verified successfully. You are now logged in.",
254274
+ success: true
254275
+ });
254276
+ }
254277
+ });
254278
+ return router;
254279
+ }
254280
+
254281
+ // src/cli/dev/dev-server/routes/entities/entities-router.ts
254282
+ var import_express4 = __toESM(require_express(), 1);
254283
+
254284
+ // src/cli/dev/dev-server/db/entity-queries.ts
254285
+ function parseSort(sort) {
254286
+ if (!sort) {
254287
+ return;
254288
+ }
254289
+ if (sort.startsWith("-")) {
254290
+ return { [sort.slice(1)]: -1 };
254291
+ }
254292
+ return { [sort]: 1 };
254293
+ }
254294
+ function parseFields(fields) {
254295
+ if (!fields) {
254296
+ return;
254297
+ }
254298
+ const projection = {};
254299
+ for (const field of fields.split(",")) {
254300
+ const trimmed = field.trim();
254301
+ if (trimmed) {
254302
+ projection[trimmed] = 1;
254303
+ }
254304
+ }
254305
+ return Object.keys(projection).length > 0 ? projection : undefined;
254306
+ }
254307
+ var queryEntity = async (collection, reqQuery) => {
254308
+ const { sort, limit, skip: skip2, fields, q: q13 } = reqQuery;
254309
+ let query = {};
254310
+ if (q13 && typeof q13 === "string") {
254311
+ try {
254312
+ query = JSON.parse(q13);
254313
+ } catch {
254314
+ throw new InvalidInputError("Invalid query parameter 'q'");
254315
+ }
254316
+ }
254317
+ let cursor3 = collection.findAsync(query);
254318
+ const sortObj = parseSort(sort);
254319
+ if (sortObj) {
254320
+ cursor3 = cursor3.sort(sortObj);
254321
+ }
254322
+ if (skip2) {
254323
+ const skipNum = Number.parseInt(skip2, 10);
254324
+ if (!Number.isNaN(skipNum)) {
254325
+ cursor3 = cursor3.skip(skipNum);
254326
+ }
254327
+ }
254328
+ if (limit) {
254329
+ const limitNum = Number.parseInt(limit, 10);
254330
+ if (!Number.isNaN(limitNum)) {
254331
+ cursor3 = cursor3.limit(limitNum);
254332
+ }
254333
+ }
254334
+ const projection = parseFields(fields);
254335
+ if (projection) {
254336
+ cursor3 = cursor3.projection(projection);
254337
+ }
254338
+ return cursor3;
254339
+ };
254340
+
254341
+ // src/cli/dev/dev-server/routes/entities/entities-user-router.ts
254342
+ var import_express3 = __toESM(require_express(), 1);
254343
+ var import_jsonwebtoken2 = __toESM(require_jsonwebtoken(), 1);
254344
+ function createUserRouter(db2, logger2) {
254345
+ const router = import_express3.Router({ mergeParams: true });
254346
+ const parseBody = import_express3.json();
254072
254347
  function withAuth(handler) {
254073
254348
  return async (req, res) => {
254074
254349
  const auth2 = req.headers.authorization;
@@ -254077,7 +254352,7 @@ function createUserRouter(db2, logger2) {
254077
254352
  return;
254078
254353
  }
254079
254354
  try {
254080
- const { payload } = import_jsonwebtoken.default.decode(auth2.replace("Bearer ", ""), { complete: true }) ?? {};
254355
+ const { payload } = import_jsonwebtoken2.default.decode(auth2.replace("Bearer ", ""), { complete: true }) ?? {};
254081
254356
  const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: payload?.sub });
254082
254357
  if (!result) {
254083
254358
  res.status(404).json({ error: "Unable to read data for the current user" });
@@ -254110,6 +254385,28 @@ function createUserRouter(db2, logger2) {
254110
254385
  ...req.body
254111
254386
  });
254112
254387
  }));
254388
+ router.get("/", withAuth(async (req, res, currentUser) => {
254389
+ const collection = db2.getCollection(USER_COLLECTION);
254390
+ if (!collection) {
254391
+ res.status(404).json({ error: `Entity "${USER_COLLECTION}" not found` });
254392
+ return;
254393
+ }
254394
+ try {
254395
+ if (currentUser.role === "admin") {
254396
+ const result = await queryEntity(collection, req.query);
254397
+ res.json(stripInternalFields(result));
254398
+ } else {
254399
+ res.json([stripInternalFields(currentUser)]);
254400
+ }
254401
+ } catch (error48) {
254402
+ if (error48 instanceof InvalidInputError) {
254403
+ res.status(400).json({ error: error48.message });
254404
+ } else {
254405
+ logger2.error(`Error in GET /${USER_COLLECTION}:`, error48);
254406
+ res.status(500).json({ error: "Internal server error" });
254407
+ }
254408
+ }
254409
+ }));
254113
254410
  router.post("/bulk", async (_req, res) => {
254114
254411
  res.json({});
254115
254412
  });
@@ -254159,31 +254456,9 @@ function createUserRouter(db2, logger2) {
254159
254456
  }
254160
254457
 
254161
254458
  // src/cli/dev/dev-server/routes/entities/entities-router.ts
254162
- function parseSort(sort) {
254163
- if (!sort) {
254164
- return;
254165
- }
254166
- if (sort.startsWith("-")) {
254167
- return { [sort.slice(1)]: -1 };
254168
- }
254169
- return { [sort]: 1 };
254170
- }
254171
- function parseFields(fields) {
254172
- if (!fields) {
254173
- return;
254174
- }
254175
- const projection = {};
254176
- for (const field of fields.split(",")) {
254177
- const trimmed = field.trim();
254178
- if (trimmed) {
254179
- projection[trimmed] = 1;
254180
- }
254181
- }
254182
- return Object.keys(projection).length > 0 ? projection : undefined;
254183
- }
254184
254459
  async function createEntityRoutes(db2, logger2, broadcast) {
254185
- const router = import_express3.Router({ mergeParams: true });
254186
- const parseBody = import_express3.json();
254460
+ const router = import_express4.Router({ mergeParams: true });
254461
+ const parseBody = import_express4.json();
254187
254462
  function withCollection(handler) {
254188
254463
  return async (req, res) => {
254189
254464
  const collection = db2.getCollection(req.params.entityName);
@@ -254228,42 +254503,14 @@ async function createEntityRoutes(db2, logger2, broadcast) {
254228
254503
  router.get("/:entityName", withCollection(async (req, res, collection) => {
254229
254504
  const { entityName } = req.params;
254230
254505
  try {
254231
- const { sort, limit, skip: skip2, fields, q: q13 } = req.query;
254232
- let query = {};
254233
- if (q13 && typeof q13 === "string") {
254234
- try {
254235
- query = JSON.parse(q13);
254236
- } catch {
254237
- res.status(400).json({ error: "Invalid query parameter 'q'" });
254238
- return;
254239
- }
254240
- }
254241
- let cursor3 = collection.findAsync(query);
254242
- const sortObj = parseSort(sort);
254243
- if (sortObj) {
254244
- cursor3 = cursor3.sort(sortObj);
254245
- }
254246
- if (skip2) {
254247
- const skipNum = Number.parseInt(skip2, 10);
254248
- if (!Number.isNaN(skipNum)) {
254249
- cursor3 = cursor3.skip(skipNum);
254250
- }
254251
- }
254252
- if (limit) {
254253
- const limitNum = Number.parseInt(limit, 10);
254254
- if (!Number.isNaN(limitNum)) {
254255
- cursor3 = cursor3.limit(limitNum);
254256
- }
254257
- }
254258
- const projection = parseFields(fields);
254259
- if (projection) {
254260
- cursor3 = cursor3.projection(projection);
254261
- }
254262
- const docs = await cursor3;
254263
- res.json(stripInternalFields(docs));
254506
+ res.json(stripInternalFields(await queryEntity(collection, req.query)));
254264
254507
  } catch (error48) {
254265
- logger2.error(`Error in GET /${entityName}:`, error48);
254266
- res.status(500).json({ error: "Internal server error" });
254508
+ if (error48 instanceof InvalidInputError) {
254509
+ res.status(400).json({ error: error48.message });
254510
+ } else {
254511
+ logger2.error(`Error in GET /${entityName}:`, error48);
254512
+ res.status(500).json({ error: "Internal server error" });
254513
+ }
254267
254514
  }
254268
254515
  }));
254269
254516
  router.post("/:entityName", parseBody, withCollection(async (req, res, collection) => {
@@ -254382,7 +254629,7 @@ async function createEntityRoutes(db2, logger2, broadcast) {
254382
254629
  }
254383
254630
 
254384
254631
  // src/cli/dev/dev-server/routes/integrations.ts
254385
- var import_express4 = __toESM(require_express(), 1);
254632
+ var import_express5 = __toESM(require_express(), 1);
254386
254633
  var import_multer = __toESM(require_multer(), 1);
254387
254634
  import { createHash, randomUUID as randomUUID4 } from "node:crypto";
254388
254635
  import fs28 from "node:fs";
@@ -254391,8 +254638,8 @@ function createFileToken(fileUri) {
254391
254638
  return createHash("sha256").update(fileUri).digest("hex");
254392
254639
  }
254393
254640
  function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger2) {
254394
- const router = import_express4.Router({ mergeParams: true });
254395
- const parseBody = import_express4.json();
254641
+ const router = import_express5.Router({ mergeParams: true });
254642
+ const parseBody = import_express5.json();
254396
254643
  const privateFilesDir = path18.join(mediaFilesDir, "private");
254397
254644
  fs28.mkdirSync(mediaFilesDir, { recursive: true });
254398
254645
  fs28.mkdirSync(privateFilesDir, { recursive: true });
@@ -254462,7 +254709,7 @@ function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger2) {
254462
254709
  return router;
254463
254710
  }
254464
254711
  function createCustomIntegrationRoutes(remoteProxy, logger2) {
254465
- const router = import_express4.Router({ mergeParams: true });
254712
+ const router = import_express5.Router({ mergeParams: true });
254466
254713
  router.post("/:slug/:operationId", (req, res, next) => {
254467
254714
  logger2.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
254468
254715
  req.url = req.originalUrl;
@@ -256175,7 +256422,7 @@ async function createDevServer(options8) {
256175
256422
  const port = userPort ?? await getPorts({ port: DEFAULT_PORT });
256176
256423
  const baseUrl = `http://localhost:${port}`;
256177
256424
  const { functions, entities, project: project2 } = await options8.loadResources();
256178
- const app = import_express5.default();
256425
+ const app = import_express6.default();
256179
256426
  const remoteProxy = import_http_proxy_middleware2.createProxyMiddleware({
256180
256427
  target: BASE44_APP_URL,
256181
256428
  changeOrigin: true
@@ -256207,6 +256454,8 @@ async function createDevServer(options8) {
256207
256454
  let emitEntityEvent = () => {};
256208
256455
  const entityRoutes = await createEntityRoutes(db2, devLogger, (...args) => emitEntityEvent(...args));
256209
256456
  app.use("/api/apps/:appId/entities", entityRoutes);
256457
+ const authRouter = createAuthRouter(db2, devLogger);
256458
+ app.use("/api/apps/:appId/auth", authRouter);
256210
256459
  const { path: mediaFilesDir } = await $dir();
256211
256460
  app.use("/media/private/:fileUri", (req, res, next) => {
256212
256461
  const { fileUri } = req.params;
@@ -256226,13 +256475,15 @@ async function createDevServer(options8) {
256226
256475
  }
256227
256476
  next();
256228
256477
  });
256229
- app.use("/media", import_express5.default.static(mediaFilesDir));
256478
+ app.use("/media", import_express6.default.static(mediaFilesDir));
256230
256479
  const integrationRoutes = createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, devLogger);
256231
256480
  app.use("/api/apps/:appId/integration-endpoints", integrationRoutes);
256232
256481
  const customIntegrationRoutes = createCustomIntegrationRoutes(remoteProxy, devLogger);
256233
256482
  app.use("/api/apps/:appId/integrations/custom", customIntegrationRoutes);
256234
256483
  app.use((req, res, next) => {
256235
- devLogger.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
256484
+ if (!req.originalUrl.endsWith("analytics/track/batch")) {
256485
+ devLogger.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
256486
+ }
256236
256487
  remoteProxy(req, res, next);
256237
256488
  });
256238
256489
  const server = await new Promise((resolve10, reject) => {
@@ -256303,6 +256554,7 @@ async function devAction({ log }, options8) {
256303
256554
  const { port: resolvedPort } = await createDevServer({
256304
256555
  log,
256305
256556
  port,
256557
+ cwd: process21.cwd(),
256306
256558
  denoWrapperPath: getDenoWrapperPath(),
256307
256559
  loadResources: async () => {
256308
256560
  const { functions, entities, project: project2 } = await readProjectConfig();
@@ -260779,4 +261031,4 @@ export {
260779
261031
  CLIExitError
260780
261032
  };
260781
261033
 
260782
- //# debugId=C23C26DBDA6AA44264756E2164756E21
261034
+ //# debugId=CDE136D996499A7364756E2164756E21