@base44-preview/cli 0.0.50-pr.480.b87871d → 0.0.50-pr.481.773d5d4

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
@@ -219926,7 +219926,8 @@ var theme = {
219926
219926
  bold: source_default.bold,
219927
219927
  dim: source_default.dim,
219928
219928
  error: source_default.red,
219929
- warn: source_default.yellow
219929
+ warn: source_default.yellow,
219930
+ info: source_default.cyan
219930
219931
  },
219931
219932
  format: {
219932
219933
  errorContext(ctx) {
@@ -235041,8 +235042,8 @@ var TOKEN_REFRESH_BUFFER_MS = 60 * 1000;
235041
235042
  var refreshPromise = null;
235042
235043
  async function readAuth() {
235043
235044
  try {
235044
- const parsed = await readJsonFile(getAuthFilePath());
235045
- const result = AuthDataSchema.safeParse(parsed);
235045
+ const authData = await readJsonFile(getAuthFilePath());
235046
+ const result = AuthDataSchema.safeParse(authData);
235046
235047
  if (!result.success) {
235047
235048
  throw new SchemaValidationError("Invalid authentication data", result.error, getAuthFilePath());
235048
235049
  }
@@ -241538,27 +241539,12 @@ var ToolConfigSchema = exports_external.union([
241538
241539
  EntityToolConfigSchema,
241539
241540
  BackendFunctionToolConfigSchema
241540
241541
  ]);
241541
- var EntityAccessRuleSchema = exports_external.union([
241542
- exports_external.boolean(),
241543
- exports_external.record(exports_external.string(), exports_external.unknown())
241544
- ]);
241545
- var AgentAccessConfigSchema = exports_external.object({
241546
- entities: exports_external.record(exports_external.string(), exports_external.record(exports_external.string(), EntityAccessRuleSchema)).optional().default({}),
241547
- functions: exports_external.array(exports_external.string()).optional().default([])
241548
- });
241549
- var CodeModeConfigSchema = exports_external.object({
241550
- access: AgentAccessConfigSchema.optional().default({
241551
- entities: {},
241552
- functions: []
241553
- })
241554
- });
241555
241542
  var AgentConfigSchema = exports_external.looseObject({
241556
241543
  name: exports_external.string().trim().min(1).max(100),
241557
241544
  description: exports_external.string().trim().min(1, "Description is required"),
241558
241545
  instructions: exports_external.string().trim().min(1, "Instructions are required"),
241559
241546
  tool_configs: exports_external.array(ToolConfigSchema).optional().default([]),
241560
- whatsapp_greeting: exports_external.string().nullable().optional(),
241561
- code_mode: CodeModeConfigSchema.optional()
241547
+ whatsapp_greeting: exports_external.string().nullable().optional()
241562
241548
  });
241563
241549
  var SyncAgentsResponseSchema = exports_external.object({
241564
241550
  created: exports_external.array(exports_external.string()),
@@ -242609,51 +242595,11 @@ var EntityAutomationSchema = AutomationBaseSchema.extend({
242609
242595
  entity_name: exports_external.string().min(1, "Entity name cannot be empty"),
242610
242596
  event_types: exports_external.array(exports_external.enum(["create", "update", "delete"])).min(1, "At least one event type is required")
242611
242597
  });
242612
- var KnownConditionOperators = [
242613
- "equals",
242614
- "not_equals",
242615
- "gt",
242616
- "gte",
242617
- "lt",
242618
- "lte",
242619
- "contains",
242620
- "not_contains",
242621
- "starts_with",
242622
- "ends_with",
242623
- "in_list",
242624
- "not_in_list",
242625
- "exists",
242626
- "not_exists",
242627
- "is_empty",
242628
- "is_not_empty"
242629
- ];
242630
- var ConditionOperatorSchema = exports_external.union([
242631
- exports_external.enum(KnownConditionOperators),
242632
- exports_external.string().min(1)
242633
- ]);
242634
- var TriggerConditionSchema = exports_external.object({
242635
- field: exports_external.string().min(1),
242636
- operator: ConditionOperatorSchema,
242637
- value: exports_external.unknown().nullable().optional()
242638
- });
242639
- var TriggerLogicSchema = exports_external.enum(["and", "or"]);
242640
- var TriggerConditionGroupSchema = exports_external.lazy(() => exports_external.object({
242641
- logic: TriggerLogicSchema.optional(),
242642
- conditions: exports_external.array(exports_external.union([TriggerConditionSchema, TriggerConditionGroupSchema])).min(1)
242643
- }));
242644
- var ConnectorAutomationSchema = AutomationBaseSchema.extend({
242645
- type: exports_external.literal("connector"),
242646
- integration_type: IntegrationTypeSchema,
242647
- events: exports_external.array(exports_external.string()),
242648
- resource_id: exports_external.string().nullable().optional(),
242649
- trigger_conditions: TriggerConditionGroupSchema.nullable().optional()
242650
- });
242651
242598
  var AutomationSchema = exports_external.union([
242652
242599
  ScheduledOneTimeSchema,
242653
242600
  ScheduledCronSchema,
242654
242601
  ScheduledSimpleSchema,
242655
- EntityAutomationSchema,
242656
- ConnectorAutomationSchema
242602
+ EntityAutomationSchema
242657
242603
  ]);
242658
242604
  var FunctionConfigSchema = exports_external.object({
242659
242605
  name: FunctionNameSchema,
@@ -243265,10 +243211,12 @@ var package_default = {
243265
243211
  "@types/ejs": "^3.1.5",
243266
243212
  "@types/express": "^5.0.6",
243267
243213
  "@types/json-schema": "^7.0.15",
243214
+ "@types/jsonwebtoken": "^9.0.10",
243268
243215
  "@types/lodash": "^4.17.24",
243269
243216
  "@types/multer": "^2.0.0",
243270
243217
  "@types/node": "^22.10.5",
243271
243218
  "@vercel/detect-agent": "^1.1.0",
243219
+ outdent: "^0.8.0",
243272
243220
  chalk: "^5.6.2",
243273
243221
  chokidar: "^5.0.0",
243274
243222
  commander: "^12.1.0",
@@ -243283,6 +243231,7 @@ var package_default = {
243283
243231
  globby: "^16.1.0",
243284
243232
  "http-proxy-middleware": "^3.0.5",
243285
243233
  "json-schema-to-typescript": "^15.0.4",
243234
+ jsonwebtoken: "^9.0.3",
243286
243235
  json5: "^2.2.3",
243287
243236
  ky: "^1.14.2",
243288
243237
  lodash: "^4.17.23",
@@ -243298,6 +243247,7 @@ var package_default = {
243298
243247
  typescript: "^5.7.2",
243299
243248
  vitest: "^4.0.16",
243300
243249
  yaml: "^2.8.2",
243250
+ qs: "^6.12.3",
243301
243251
  zod: "^4.3.5"
243302
243252
  },
243303
243253
  engines: {
@@ -252810,9 +252760,12 @@ function getTypesCommand() {
252810
252760
  return new Command("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
252811
252761
  }
252812
252762
 
252763
+ // src/cli/commands/dev.ts
252764
+ import process21 from "node:process";
252765
+
252813
252766
  // src/cli/dev/dev-server/main.ts
252814
252767
  var import_cors = __toESM(require_lib4(), 1);
252815
- var import_express5 = __toESM(require_express(), 1);
252768
+ var import_express6 = __toESM(require_express(), 1);
252816
252769
  import { dirname as dirname16, join as join23 } from "node:path";
252817
252770
 
252818
252771
  // ../../node_modules/get-port/index.js
@@ -252986,6 +252939,7 @@ function createDevLogger() {
252986
252939
 
252987
252940
  // src/cli/dev/dev-server/function-manager.ts
252988
252941
  import { spawn as spawn2 } from "node:child_process";
252942
+ import { pathToFileURL } from "node:url";
252989
252943
  var READY_TIMEOUT = 30000;
252990
252944
 
252991
252945
  class FunctionManager {
@@ -253065,7 +253019,7 @@ class FunctionManager {
253065
253019
  const process21 = spawn2("deno", ["run", "--allow-all", this.wrapperPath], {
253066
253020
  env: {
253067
253021
  ...globalThis.process.env,
253068
- FUNCTION_PATH: func.entryPath,
253022
+ FUNCTION_PATH: pathToFileURL(func.entryPath).href,
253069
253023
  FUNCTION_PORT: String(port),
253070
253024
  FUNCTION_NAME: func.name
253071
253025
  },
@@ -253375,7 +253329,9 @@ class Validator {
253375
253329
  }
253376
253330
 
253377
253331
  // src/cli/dev/dev-server/db/database.ts
253332
+ var PRIVATE_COLLECTION_PREFIX = "$";
253378
253333
  var USER_COLLECTION = "user";
253334
+ var PRIVATE_USER_COLLECTION = PRIVATE_COLLECTION_PREFIX + USER_COLLECTION;
253379
253335
 
253380
253336
  class Database {
253381
253337
  collections = new Map;
@@ -253397,6 +253353,7 @@ class Database {
253397
253353
  this.schemas.set(USER_COLLECTION, this.buildUserSchema(userEntity));
253398
253354
  const collection = new import_nedb.default;
253399
253355
  this.collections.set(USER_COLLECTION, collection);
253356
+ this.collections.set(PRIVATE_USER_COLLECTION, new import_nedb.default);
253400
253357
  const userInfo = await readAuth();
253401
253358
  const now = getNowISOTimestamp();
253402
253359
  await collection.insertAsync({
@@ -253437,8 +253394,13 @@ class Database {
253437
253394
  getCollection(name2) {
253438
253395
  return this.collections.get(this.normalizeName(name2));
253439
253396
  }
253397
+ getSchema(entityName) {
253398
+ return this.schemas.get(this.normalizeName(entityName));
253399
+ }
253440
253400
  getCollectionNames() {
253441
- return Array.from(this.collections.keys());
253401
+ return Array.from(this.collections.keys()).filter((name2) => {
253402
+ return !name2.startsWith(PRIVATE_COLLECTION_PREFIX);
253403
+ });
253442
253404
  }
253443
253405
  dropAll() {
253444
253406
  for (const collection of this.collections.values()) {
@@ -253502,15 +253464,339 @@ function broadcastEntityEvent(io6, appId, entityName, event) {
253502
253464
  });
253503
253465
  }
253504
253466
 
253505
- // src/cli/dev/dev-server/routes/entities/entities-router.ts
253506
- var import_express3 = __toESM(require_express(), 1);
253507
-
253508
- // src/cli/dev/dev-server/routes/entities/entities-user-router.ts
253467
+ // src/cli/dev/dev-server/routes/auth-router.ts
253509
253468
  var import_express2 = __toESM(require_express(), 1);
253510
253469
  var import_jsonwebtoken = __toESM(require_jsonwebtoken(), 1);
253511
- function createUserRouter(db2, logger2) {
253470
+ import { randomInt } from "node:crypto";
253471
+ var LOCAL_DEV_SECRET = "LOCAL_DEV_SECRET";
253472
+ var generateCode = () => {
253473
+ return randomInt(1e5, 1e6).toString();
253474
+ };
253475
+ var createJwtToken = (email3) => {
253476
+ return import_jsonwebtoken.default.sign({ sub: email3 }, LOCAL_DEV_SECRET, {
253477
+ expiresIn: "360d"
253478
+ });
253479
+ };
253480
+ var LoginBody = object({ email: email2(), password: string2() });
253481
+ var VerifyOtpBody = object({ email: email2(), otp_code: string2() });
253482
+ function createAuthRouter(db2, logger2) {
253512
253483
  const router = import_express2.Router({ mergeParams: true });
253513
253484
  const parseBody = import_express2.json();
253485
+ router.post("/login", parseBody, async (req, res) => {
253486
+ const { email: email3, password } = LoginBody.parse(req.body);
253487
+ const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: email3 });
253488
+ if (result) {
253489
+ const privateUserData = await db2.getCollection(PRIVATE_USER_COLLECTION)?.findOneAsync({ email: email3 });
253490
+ if (result.role === "admin" || privateUserData?.password === password) {
253491
+ res.json({
253492
+ access_token: createJwtToken(email3),
253493
+ success: true,
253494
+ user: {}
253495
+ });
253496
+ } else {
253497
+ res.status(400).json({
253498
+ detail: "Invalid email or password",
253499
+ error_type: "HTTPException",
253500
+ message: "Invalid email or password",
253501
+ request_id: null,
253502
+ traceback: ""
253503
+ });
253504
+ }
253505
+ return;
253506
+ }
253507
+ res.status(401).json({ error: "Unauthorized" });
253508
+ });
253509
+ router.post("/register", parseBody, async (req, res) => {
253510
+ const { email: email3, password } = LoginBody.parse(req.body);
253511
+ if ((password || "").length < 8) {
253512
+ res.status(400).json({
253513
+ detail: "Password must be at least 8 characters long",
253514
+ error_type: "HTTPException",
253515
+ message: "Password must be at least 8 characters long",
253516
+ request_id: null,
253517
+ traceback: ""
253518
+ });
253519
+ return;
253520
+ }
253521
+ const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: email3 });
253522
+ if (result) {
253523
+ res.status(400).json({
253524
+ detail: "A user with this email already exists",
253525
+ error_type: "HTTPException",
253526
+ message: "A user with this email already exists",
253527
+ request_id: null,
253528
+ traceback: ""
253529
+ });
253530
+ return;
253531
+ }
253532
+ const privateUserCollection = db2.getCollection(PRIVATE_USER_COLLECTION);
253533
+ const privateUserData = await privateUserCollection?.findOneAsync({
253534
+ email: email3
253535
+ });
253536
+ const otpCode = generateCode();
253537
+ const id2 = privateUserData ? privateUserData.id : nanoid3();
253538
+ if (!privateUserData) {
253539
+ await privateUserCollection?.insertAsync({
253540
+ id: id2,
253541
+ email: email3,
253542
+ otpCode,
253543
+ password,
253544
+ createdAt: Date.now()
253545
+ });
253546
+ } else {
253547
+ await privateUserCollection?.updateAsync({
253548
+ email: email3
253549
+ }, {
253550
+ $set: {
253551
+ otpCode,
253552
+ createdAt: Date.now()
253553
+ }
253554
+ });
253555
+ }
253556
+ logger2.log(theme.styles.info(`
253557
+ In order to complete registration use this verification code: ${otpCode}
253558
+ `));
253559
+ res.json({
253560
+ id: id2,
253561
+ message: "Registration successful. Please check your email for the verification code.",
253562
+ otp_expires_in_minutes: 10
253563
+ });
253564
+ });
253565
+ router.post("/verify-otp", parseBody, async (req, res) => {
253566
+ const { email: email3, otp_code } = VerifyOtpBody.parse(req.body);
253567
+ const privateUserCollection = db2.getCollection(PRIVATE_USER_COLLECTION);
253568
+ const privateUserData = await privateUserCollection?.findOneAsync({
253569
+ email: email3
253570
+ });
253571
+ if (privateUserData && privateUserData.otpCode === otp_code) {
253572
+ if (+Date.now() - privateUserData.createdAt < 10 * 60 * 1000) {
253573
+ await privateUserCollection?.updateAsync({
253574
+ email: email3
253575
+ }, {
253576
+ $unset: { otpCode: true }
253577
+ });
253578
+ const collection = db2.getCollection(USER_COLLECTION);
253579
+ const now = getNowISOTimestamp();
253580
+ const nameFromEmailMatch = /^([^@]+)/.exec(email3);
253581
+ const fullName = nameFromEmailMatch ? nameFromEmailMatch[1] : email3;
253582
+ await collection?.insertAsync({
253583
+ id: privateUserData.id,
253584
+ email: email3,
253585
+ full_name: fullName,
253586
+ is_service: false,
253587
+ is_verified: true,
253588
+ disabled: null,
253589
+ role: "user",
253590
+ collaborator_role: "editor",
253591
+ created_date: now,
253592
+ updated_date: now
253593
+ });
253594
+ res.json({
253595
+ id: privateUserData.id,
253596
+ access_token: createJwtToken(email3),
253597
+ message: "Email verified successfully. You are now logged in.",
253598
+ success: true
253599
+ });
253600
+ } else {
253601
+ res.status(400).json({
253602
+ detail: "Verification code has expired",
253603
+ error_type: "HTTPException",
253604
+ message: "Verification code has expired",
253605
+ request_id: null,
253606
+ traceback: ""
253607
+ });
253608
+ }
253609
+ } else {
253610
+ const appId = req.params.appId;
253611
+ res.status(500).json({
253612
+ detail: `{'email': '${email3}', 'app_id': '${appId}}'} -> Object not found`,
253613
+ error_type: "ObjectNotFoundError",
253614
+ message: `{'email': '${email3}', 'app_id': '${appId}}'} -> Object not found`,
253615
+ request_id: null,
253616
+ traceback: ""
253617
+ });
253618
+ }
253619
+ });
253620
+ return router;
253621
+ }
253622
+
253623
+ // src/cli/dev/dev-server/routes/entities/entities-router.ts
253624
+ var import_express4 = __toESM(require_express(), 1);
253625
+ var import_jsonwebtoken3 = __toESM(require_jsonwebtoken(), 1);
253626
+
253627
+ // src/cli/dev/dev-server/db/rls.ts
253628
+ function resolveTemplate(value, user) {
253629
+ return value.replace(/\{\{user\.([\w.]+)\}\}/g, (_match, path18) => {
253630
+ if (path18.startsWith("data.")) {
253631
+ return String(user[path18.slice(5)] ?? "");
253632
+ }
253633
+ return String(user[path18] ?? "");
253634
+ });
253635
+ }
253636
+ function getRecordField(key2, record2) {
253637
+ if (key2.startsWith("data.")) {
253638
+ return record2[key2.slice(5)];
253639
+ }
253640
+ return record2[key2];
253641
+ }
253642
+ function evaluateOperator(recordValue, operator) {
253643
+ for (const [op2, opValue] of Object.entries(operator)) {
253644
+ switch (op2) {
253645
+ case "$in":
253646
+ if (!Array.isArray(opValue) || !opValue.includes(recordValue))
253647
+ return false;
253648
+ break;
253649
+ case "$nin":
253650
+ if (Array.isArray(opValue) && opValue.includes(recordValue))
253651
+ return false;
253652
+ break;
253653
+ case "$ne":
253654
+ if (recordValue === opValue)
253655
+ return false;
253656
+ break;
253657
+ case "$all":
253658
+ if (!Array.isArray(recordValue) || !Array.isArray(opValue))
253659
+ return false;
253660
+ if (!opValue.every((v10) => recordValue.includes(v10)))
253661
+ return false;
253662
+ break;
253663
+ }
253664
+ }
253665
+ return true;
253666
+ }
253667
+ function evaluateUserCondition(condition, user) {
253668
+ for (const [key2, expected] of Object.entries(condition)) {
253669
+ const userValue = key2.startsWith("data.") ? user[key2.slice(5)] : user[key2];
253670
+ if (typeof expected === "object" && expected !== null) {
253671
+ if (!evaluateOperator(userValue, expected))
253672
+ return false;
253673
+ } else {
253674
+ if (userValue !== expected)
253675
+ return false;
253676
+ }
253677
+ }
253678
+ return true;
253679
+ }
253680
+ function evaluateCondition(condition, record2, user) {
253681
+ for (const [key2, value] of Object.entries(condition)) {
253682
+ if (key2 === "user_condition") {
253683
+ if (!evaluateUserCondition(value, user))
253684
+ return false;
253685
+ continue;
253686
+ }
253687
+ if (key2 === "$or") {
253688
+ const conditions = value;
253689
+ if (!conditions.some((c8) => evaluateCondition(c8, record2, user)))
253690
+ return false;
253691
+ continue;
253692
+ }
253693
+ if (key2 === "$and") {
253694
+ const conditions = value;
253695
+ if (!conditions.every((c8) => evaluateCondition(c8, record2, user)))
253696
+ return false;
253697
+ continue;
253698
+ }
253699
+ if (key2 === "$nor") {
253700
+ const conditions = value;
253701
+ if (conditions.some((c8) => evaluateCondition(c8, record2, user)))
253702
+ return false;
253703
+ continue;
253704
+ }
253705
+ const recordValue = getRecordField(key2, record2);
253706
+ const resolvedValue = typeof value === "string" ? resolveTemplate(value, user) : value;
253707
+ if (typeof resolvedValue === "object" && resolvedValue !== null) {
253708
+ if (!evaluateOperator(recordValue, resolvedValue))
253709
+ return false;
253710
+ } else {
253711
+ if (recordValue !== resolvedValue)
253712
+ return false;
253713
+ }
253714
+ }
253715
+ return true;
253716
+ }
253717
+ function checkRLS(rule, record2, user) {
253718
+ if (rule === undefined)
253719
+ return true;
253720
+ if (typeof rule === "boolean")
253721
+ return rule;
253722
+ if (!user)
253723
+ return false;
253724
+ return evaluateCondition(rule, record2, user);
253725
+ }
253726
+ function applyFLS(record2, schema10, user, operation) {
253727
+ const result = {};
253728
+ for (const [key2, value] of Object.entries(record2)) {
253729
+ const rule = schema10.properties[key2]?.rls?.[operation];
253730
+ if (!rule || checkRLS(rule, record2, user)) {
253731
+ result[key2] = value;
253732
+ }
253733
+ }
253734
+ return result;
253735
+ }
253736
+
253737
+ // src/cli/dev/dev-server/db/entity-queries.ts
253738
+ function parseSort(sort) {
253739
+ if (!sort) {
253740
+ return;
253741
+ }
253742
+ if (sort.startsWith("-")) {
253743
+ return { [sort.slice(1)]: -1 };
253744
+ }
253745
+ return { [sort]: 1 };
253746
+ }
253747
+ function parseFields(fields) {
253748
+ if (!fields) {
253749
+ return;
253750
+ }
253751
+ const projection = {};
253752
+ for (const field of fields.split(",")) {
253753
+ const trimmed = field.trim();
253754
+ if (trimmed) {
253755
+ projection[trimmed] = 1;
253756
+ }
253757
+ }
253758
+ return Object.keys(projection).length > 0 ? projection : undefined;
253759
+ }
253760
+ var queryEntity = async (collection, reqQuery) => {
253761
+ const { sort, limit, skip: skip2, fields, q: q13 } = reqQuery;
253762
+ let query = {};
253763
+ if (q13 && typeof q13 === "string") {
253764
+ try {
253765
+ query = JSON.parse(q13);
253766
+ } catch {
253767
+ throw new InvalidInputError("Invalid query parameter 'q'");
253768
+ }
253769
+ }
253770
+ let cursor3 = collection.findAsync(query);
253771
+ const sortObj = parseSort(sort);
253772
+ if (sortObj) {
253773
+ cursor3 = cursor3.sort(sortObj);
253774
+ }
253775
+ if (skip2) {
253776
+ const skipNum = Number.parseInt(skip2, 10);
253777
+ if (!Number.isNaN(skipNum)) {
253778
+ cursor3 = cursor3.skip(skipNum);
253779
+ }
253780
+ }
253781
+ if (limit) {
253782
+ const limitNum = Number.parseInt(limit, 10);
253783
+ if (!Number.isNaN(limitNum)) {
253784
+ cursor3 = cursor3.limit(limitNum);
253785
+ }
253786
+ }
253787
+ const projection = parseFields(fields);
253788
+ if (projection) {
253789
+ cursor3 = cursor3.projection(projection);
253790
+ }
253791
+ return cursor3;
253792
+ };
253793
+
253794
+ // src/cli/dev/dev-server/routes/entities/entities-user-router.ts
253795
+ var import_express3 = __toESM(require_express(), 1);
253796
+ var import_jsonwebtoken2 = __toESM(require_jsonwebtoken(), 1);
253797
+ function createUserRouter(db2, logger2) {
253798
+ const router = import_express3.Router({ mergeParams: true });
253799
+ const parseBody = import_express3.json();
253514
253800
  function withAuth(handler) {
253515
253801
  return async (req, res) => {
253516
253802
  const auth2 = req.headers.authorization;
@@ -253519,13 +253805,13 @@ function createUserRouter(db2, logger2) {
253519
253805
  return;
253520
253806
  }
253521
253807
  try {
253522
- const { payload } = import_jsonwebtoken.default.decode(auth2.replace("Bearer ", ""), { complete: true }) ?? {};
253523
- const result = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: payload?.sub });
253524
- if (!result) {
253808
+ const { payload } = import_jsonwebtoken2.default.decode(auth2.replace("Bearer ", ""), { complete: true }) ?? {};
253809
+ const currentUser = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: payload?.sub });
253810
+ if (!currentUser) {
253525
253811
  res.status(404).json({ error: "Unable to read data for the current user" });
253526
253812
  return;
253527
253813
  }
253528
- await handler(req, res, result);
253814
+ await handler(req, res, currentUser);
253529
253815
  } catch {
253530
253816
  res.status(401).json({ error: "Unauthorized" });
253531
253817
  }
@@ -253552,6 +253838,28 @@ function createUserRouter(db2, logger2) {
253552
253838
  ...req.body
253553
253839
  });
253554
253840
  }));
253841
+ router.get("/", withAuth(async (req, res, currentUser) => {
253842
+ const collection = db2.getCollection(USER_COLLECTION);
253843
+ if (!collection) {
253844
+ res.status(404).json({ error: `Entity "${USER_COLLECTION}" not found` });
253845
+ return;
253846
+ }
253847
+ try {
253848
+ if (currentUser.role === "admin") {
253849
+ const result = await queryEntity(collection, req.query);
253850
+ res.json(stripInternalFields(result));
253851
+ } else {
253852
+ res.json([stripInternalFields(currentUser)]);
253853
+ }
253854
+ } catch (error48) {
253855
+ if (error48 instanceof InvalidInputError) {
253856
+ res.status(400).json({ error: error48.message });
253857
+ } else {
253858
+ logger2.error(`Error in GET /${USER_COLLECTION}:`, error48);
253859
+ res.status(500).json({ error: "Internal server error" });
253860
+ }
253861
+ }
253862
+ }));
253555
253863
  router.post("/bulk", async (_req, res) => {
253556
253864
  res.json({});
253557
253865
  });
@@ -253601,31 +253909,9 @@ function createUserRouter(db2, logger2) {
253601
253909
  }
253602
253910
 
253603
253911
  // src/cli/dev/dev-server/routes/entities/entities-router.ts
253604
- function parseSort(sort) {
253605
- if (!sort) {
253606
- return;
253607
- }
253608
- if (sort.startsWith("-")) {
253609
- return { [sort.slice(1)]: -1 };
253610
- }
253611
- return { [sort]: 1 };
253612
- }
253613
- function parseFields(fields) {
253614
- if (!fields) {
253615
- return;
253616
- }
253617
- const projection = {};
253618
- for (const field of fields.split(",")) {
253619
- const trimmed = field.trim();
253620
- if (trimmed) {
253621
- projection[trimmed] = 1;
253622
- }
253623
- }
253624
- return Object.keys(projection).length > 0 ? projection : undefined;
253625
- }
253626
253912
  async function createEntityRoutes(db2, logger2, broadcast) {
253627
- const router = import_express3.Router({ mergeParams: true });
253628
- const parseBody = import_express3.json();
253913
+ const router = import_express4.Router({ mergeParams: true });
253914
+ const parseBody = import_express4.json();
253629
253915
  function withCollection(handler) {
253630
253916
  return async (req, res) => {
253631
253917
  const collection = db2.getCollection(req.params.entityName);
@@ -253633,7 +253919,13 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253633
253919
  res.status(404).json({ error: `Entity "${req.params.entityName}" not found` });
253634
253920
  return;
253635
253921
  }
253636
- await handler(req, res, collection);
253922
+ let currentUser;
253923
+ try {
253924
+ const auth2 = req.headers.authorization || "";
253925
+ const { payload } = import_jsonwebtoken3.default.decode(auth2.replace("Bearer ", ""), { complete: true }) ?? {};
253926
+ currentUser = await db2.getCollection(USER_COLLECTION)?.findOneAsync({ email: payload?.sub });
253927
+ } catch {}
253928
+ await handler(req, res, collection, currentUser);
253637
253929
  };
253638
253930
  }
253639
253931
  function emit(appId, entityName, type, data) {
@@ -253653,7 +253945,7 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253653
253945
  }
253654
253946
  const userRouter = createUserRouter(db2, logger2);
253655
253947
  router.use("/User", userRouter);
253656
- router.get("/:entityName/:id", withCollection(async (req, res, collection) => {
253948
+ router.get("/:entityName/:id", withCollection(async (req, res, collection, currentUser) => {
253657
253949
  const { entityName, id: id2 } = req.params;
253658
253950
  try {
253659
253951
  const doc2 = await collection.findOneAsync({ id: id2 });
@@ -253661,63 +253953,70 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253661
253953
  res.status(404).json({ error: `Record with id "${id2}" not found` });
253662
253954
  return;
253663
253955
  }
253664
- res.json(stripInternalFields(doc2));
253956
+ const schema10 = db2.getSchema(entityName);
253957
+ if (!checkRLS(schema10?.rls?.read, doc2, currentUser)) {
253958
+ res.status(403).json({ error: "Permission denied" });
253959
+ return;
253960
+ }
253961
+ let result = stripInternalFields(doc2);
253962
+ if (schema10) {
253963
+ result = applyFLS(result, schema10, currentUser, "read");
253964
+ }
253965
+ res.json(result);
253665
253966
  } catch (error48) {
253666
253967
  logger2.error(`Error in GET /${entityName}/${id2}:`, error48);
253667
253968
  res.status(500).json({ error: "Internal server error" });
253668
253969
  }
253669
253970
  }));
253670
- router.get("/:entityName", withCollection(async (req, res, collection) => {
253971
+ router.get("/:entityName", withCollection(async (req, res, collection, currentUser) => {
253671
253972
  const { entityName } = req.params;
253672
253973
  try {
253673
- const { sort, limit, skip: skip2, fields, q: q13 } = req.query;
253674
- let query = {};
253675
- if (q13 && typeof q13 === "string") {
253676
- try {
253677
- query = JSON.parse(q13);
253678
- } catch {
253679
- res.status(400).json({ error: "Invalid query parameter 'q'" });
253680
- return;
253681
- }
253682
- }
253683
- let cursor3 = collection.findAsync(query);
253684
- const sortObj = parseSort(sort);
253685
- if (sortObj) {
253686
- cursor3 = cursor3.sort(sortObj);
253687
- }
253688
- if (skip2) {
253689
- const skipNum = Number.parseInt(skip2, 10);
253690
- if (!Number.isNaN(skipNum)) {
253691
- cursor3 = cursor3.skip(skipNum);
253692
- }
253974
+ const schema10 = db2.getSchema(entityName);
253975
+ if (schema10?.rls?.read === false) {
253976
+ res.json([]);
253977
+ return;
253693
253978
  }
253694
- if (limit) {
253695
- const limitNum = Number.parseInt(limit, 10);
253696
- if (!Number.isNaN(limitNum)) {
253697
- cursor3 = cursor3.limit(limitNum);
253698
- }
253979
+ let results = stripInternalFields(await queryEntity(collection, req.query));
253980
+ if (schema10?.rls?.read && schema10.rls.read !== true) {
253981
+ results = results.filter((doc2) => checkRLS(schema10.rls.read, doc2, currentUser));
253699
253982
  }
253700
- const projection = parseFields(fields);
253701
- if (projection) {
253702
- cursor3 = cursor3.projection(projection);
253983
+ if (schema10) {
253984
+ results = results.map((doc2) => applyFLS(doc2, schema10, currentUser, "read"));
253703
253985
  }
253704
- const docs = await cursor3;
253705
- res.json(stripInternalFields(docs));
253986
+ res.json(results);
253706
253987
  } catch (error48) {
253707
- logger2.error(`Error in GET /${entityName}:`, error48);
253708
- res.status(500).json({ error: "Internal server error" });
253988
+ if (error48 instanceof InvalidInputError) {
253989
+ res.status(400).json({ error: error48.message });
253990
+ } else {
253991
+ logger2.error(`Error in GET /${entityName}:`, error48);
253992
+ res.status(500).json({ error: "Internal server error" });
253993
+ }
253709
253994
  }
253710
253995
  }));
253711
- router.post("/:entityName", parseBody, withCollection(async (req, res, collection) => {
253996
+ router.post("/:entityName", parseBody, withCollection(async (req, res, collection, currentUser) => {
253712
253997
  const { appId, entityName } = req.params;
253713
253998
  try {
253714
253999
  const now = new Date().toISOString();
253715
254000
  const { _id, ...body } = req.body;
253716
- const filteredBody = db2.prepareRecord(entityName, body);
254001
+ const schema10 = db2.getSchema(entityName);
254002
+ if (!checkRLS(schema10?.rls?.create, {
254003
+ ...body,
254004
+ created_by: currentUser?.email,
254005
+ created_by_id: currentUser?.id
254006
+ }, currentUser)) {
254007
+ res.status(403).json({ error: "Permission denied" });
254008
+ return;
254009
+ }
254010
+ let filteredBody = db2.prepareRecord(entityName, body);
254011
+ if (schema10) {
254012
+ filteredBody = applyFLS(filteredBody, schema10, currentUser, "write");
254013
+ }
253717
254014
  db2.validate(entityName, filteredBody);
253718
254015
  const record2 = {
253719
254016
  ...filteredBody,
253720
254017
  id: nanoid3(),
254018
+ created_by: currentUser?.email,
254019
+ created_by_id: currentUser?.id,
253721
254020
  created_date: now,
253722
254021
  updated_date: now
253723
254022
  };
@@ -253733,7 +254032,7 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253733
254032
  res.status(500).json({ error: "Internal server error" });
253734
254033
  }
253735
254034
  }));
253736
- router.post("/:entityName/bulk", parseBody, withCollection(async (req, res, collection) => {
254035
+ router.post("/:entityName/bulk", parseBody, withCollection(async (req, res, collection, currentUser) => {
253737
254036
  const { appId, entityName } = req.params;
253738
254037
  if (!Array.isArray(req.body)) {
253739
254038
  res.status(400).json({ error: "Request body must be an array" });
@@ -253741,13 +254040,27 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253741
254040
  }
253742
254041
  try {
253743
254042
  const now = new Date().toISOString();
254043
+ const schema10 = db2.getSchema(entityName);
253744
254044
  const records = [];
253745
254045
  for (const record2 of req.body) {
253746
- const filteredRecord = db2.prepareRecord(entityName, record2);
254046
+ if (!checkRLS(schema10?.rls?.create, {
254047
+ ...record2,
254048
+ created_by: currentUser?.email,
254049
+ created_by_id: currentUser?.id
254050
+ }, currentUser)) {
254051
+ res.status(403).json({ error: "Permission denied" });
254052
+ return;
254053
+ }
254054
+ let filteredRecord = db2.prepareRecord(entityName, record2);
254055
+ if (schema10) {
254056
+ filteredRecord = applyFLS(filteredRecord, schema10, currentUser, "write");
254057
+ }
253747
254058
  db2.validate(entityName, filteredRecord);
253748
254059
  records.push({
253749
254060
  ...filteredRecord,
253750
254061
  id: nanoid3(),
254062
+ created_by: currentUser?.email,
254063
+ created_by_id: currentUser?.id,
253751
254064
  created_date: now,
253752
254065
  updated_date: now
253753
254066
  });
@@ -253764,11 +254077,26 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253764
254077
  res.status(500).json({ error: "Internal server error" });
253765
254078
  }
253766
254079
  }));
253767
- router.put("/:entityName/:id", parseBody, withCollection(async (req, res, collection) => {
254080
+ router.put("/:entityName/:id", parseBody, withCollection(async (req, res, collection, currentUser) => {
253768
254081
  const { appId, entityName, id: id2 } = req.params;
253769
254082
  const { id: _id, created_date: _created_date, ...body } = req.body;
253770
254083
  try {
253771
- const filteredBody = db2.prepareRecord(entityName, body, true);
254084
+ const schema10 = db2.getSchema(entityName);
254085
+ if (schema10?.rls?.update !== undefined) {
254086
+ const existing = await collection.findOneAsync({ id: id2 });
254087
+ if (!existing) {
254088
+ res.status(404).json({ error: `Record with id "${id2}" not found` });
254089
+ return;
254090
+ }
254091
+ if (!checkRLS(schema10.rls.update, existing, currentUser)) {
254092
+ res.status(403).json({ error: "Permission denied" });
254093
+ return;
254094
+ }
254095
+ }
254096
+ let filteredBody = db2.prepareRecord(entityName, body, true);
254097
+ if (schema10) {
254098
+ filteredBody = applyFLS(filteredBody, schema10, currentUser, "write");
254099
+ }
253772
254100
  db2.validate(entityName, filteredBody, true);
253773
254101
  const updateData = {
253774
254102
  ...filteredBody,
@@ -253791,30 +254119,48 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253791
254119
  res.status(500).json({ error: "Internal server error" });
253792
254120
  }
253793
254121
  }));
253794
- router.delete("/:entityName/:id", withCollection(async (req, res, collection) => {
254122
+ router.delete("/:entityName/:id", withCollection(async (req, res, collection, currentUser) => {
253795
254123
  const { appId, entityName, id: id2 } = req.params;
253796
254124
  try {
253797
254125
  const doc2 = await collection.findOneAsync({ id: id2 });
253798
- const numRemoved = await collection.removeAsync({ id: id2 }, { multi: false });
253799
- if (numRemoved === 0) {
254126
+ if (!doc2) {
253800
254127
  res.status(404).json({ error: `Record with id "${id2}" not found` });
253801
254128
  return;
253802
254129
  }
253803
- if (doc2) {
253804
- emit(appId, entityName, "delete", stripInternalFields(doc2));
254130
+ const schema10 = db2.getSchema(entityName);
254131
+ if (!checkRLS(schema10?.rls?.delete, doc2, currentUser)) {
254132
+ res.status(403).json({ error: "Permission denied" });
254133
+ return;
253805
254134
  }
254135
+ await collection.removeAsync({ id: id2 }, { multi: false });
254136
+ emit(appId, entityName, "delete", stripInternalFields(doc2));
253806
254137
  res.json({ success: true });
253807
254138
  } catch (error48) {
253808
254139
  logger2.error(`Error in DELETE /${entityName}/${id2}:`, error48);
253809
254140
  res.status(500).json({ error: "Internal server error" });
253810
254141
  }
253811
254142
  }));
253812
- router.delete("/:entityName", parseBody, withCollection(async (req, res, collection) => {
254143
+ router.delete("/:entityName", parseBody, withCollection(async (req, res, collection, currentUser) => {
253813
254144
  const { entityName } = req.params;
253814
254145
  try {
253815
254146
  const query = req.body || {};
253816
- const numRemoved = await collection.removeAsync(query, { multi: true });
253817
- res.json({ success: true, deleted: numRemoved });
254147
+ const schema10 = db2.getSchema(entityName);
254148
+ const rlsDelete = schema10?.rls?.delete;
254149
+ if (rlsDelete !== undefined && rlsDelete !== true) {
254150
+ if (rlsDelete === false) {
254151
+ res.status(403).json({ error: "Permission denied" });
254152
+ return;
254153
+ }
254154
+ const docs = await collection.findAsync(query);
254155
+ const allowedIds = docs.filter((doc2) => checkRLS(rlsDelete, doc2, currentUser)).map((doc2) => doc2.id);
254156
+ const numRemoved = await collection.removeAsync({ id: { $in: allowedIds } }, { multi: true });
254157
+ res.json({ success: true, deleted: numRemoved });
254158
+ } else {
254159
+ const numRemoved = await collection.removeAsync(query, {
254160
+ multi: true
254161
+ });
254162
+ res.json({ success: true, deleted: numRemoved });
254163
+ }
253818
254164
  } catch (error48) {
253819
254165
  logger2.error(`Error in DELETE /${entityName}:`, error48);
253820
254166
  res.status(500).json({ error: "Internal server error" });
@@ -253824,7 +254170,7 @@ async function createEntityRoutes(db2, logger2, broadcast) {
253824
254170
  }
253825
254171
 
253826
254172
  // src/cli/dev/dev-server/routes/integrations.ts
253827
- var import_express4 = __toESM(require_express(), 1);
254173
+ var import_express5 = __toESM(require_express(), 1);
253828
254174
  var import_multer = __toESM(require_multer(), 1);
253829
254175
  import { createHash, randomUUID as randomUUID4 } from "node:crypto";
253830
254176
  import fs28 from "node:fs";
@@ -253833,8 +254179,8 @@ function createFileToken(fileUri) {
253833
254179
  return createHash("sha256").update(fileUri).digest("hex");
253834
254180
  }
253835
254181
  function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger2) {
253836
- const router = import_express4.Router({ mergeParams: true });
253837
- const parseBody = import_express4.json();
254182
+ const router = import_express5.Router({ mergeParams: true });
254183
+ const parseBody = import_express5.json();
253838
254184
  const privateFilesDir = path18.join(mediaFilesDir, "private");
253839
254185
  fs28.mkdirSync(mediaFilesDir, { recursive: true });
253840
254186
  fs28.mkdirSync(privateFilesDir, { recursive: true });
@@ -253904,7 +254250,7 @@ function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger2) {
253904
254250
  return router;
253905
254251
  }
253906
254252
  function createCustomIntegrationRoutes(remoteProxy, logger2) {
253907
- const router = import_express4.Router({ mergeParams: true });
254253
+ const router = import_express5.Router({ mergeParams: true });
253908
254254
  router.post("/:slug/:operationId", (req, res, next) => {
253909
254255
  logger2.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
253910
254256
  req.url = req.originalUrl;
@@ -255617,7 +255963,7 @@ async function createDevServer(options8) {
255617
255963
  const port = userPort ?? await getPorts({ port: DEFAULT_PORT });
255618
255964
  const baseUrl = `http://localhost:${port}`;
255619
255965
  const { functions, entities, project: project2 } = await options8.loadResources();
255620
- const app = import_express5.default();
255966
+ const app = import_express6.default();
255621
255967
  const remoteProxy = import_http_proxy_middleware2.createProxyMiddleware({
255622
255968
  target: BASE44_APP_URL,
255623
255969
  changeOrigin: true
@@ -255649,6 +255995,8 @@ async function createDevServer(options8) {
255649
255995
  let emitEntityEvent = () => {};
255650
255996
  const entityRoutes = await createEntityRoutes(db2, devLogger, (...args) => emitEntityEvent(...args));
255651
255997
  app.use("/api/apps/:appId/entities", entityRoutes);
255998
+ const authRouter = createAuthRouter(db2, devLogger);
255999
+ app.use("/api/apps/:appId/auth", authRouter);
255652
256000
  const { path: mediaFilesDir } = await $dir();
255653
256001
  app.use("/media/private/:fileUri", (req, res, next) => {
255654
256002
  const { fileUri } = req.params;
@@ -255668,13 +256016,15 @@ async function createDevServer(options8) {
255668
256016
  }
255669
256017
  next();
255670
256018
  });
255671
- app.use("/media", import_express5.default.static(mediaFilesDir));
256019
+ app.use("/media", import_express6.default.static(mediaFilesDir));
255672
256020
  const integrationRoutes = createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, devLogger);
255673
256021
  app.use("/api/apps/:appId/integration-endpoints", integrationRoutes);
255674
256022
  const customIntegrationRoutes = createCustomIntegrationRoutes(remoteProxy, devLogger);
255675
256023
  app.use("/api/apps/:appId/integrations/custom", customIntegrationRoutes);
255676
256024
  app.use((req, res, next) => {
255677
- devLogger.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
256025
+ if (!req.originalUrl.endsWith("analytics/track/batch")) {
256026
+ devLogger.warn(`"${req.originalUrl}" is not supported in local development, passing call to production`);
256027
+ }
255678
256028
  remoteProxy(req, res, next);
255679
256029
  });
255680
256030
  const server = await new Promise((resolve8, reject) => {
@@ -255745,6 +256095,7 @@ async function devAction({ log }, options8) {
255745
256095
  const { port: resolvedPort } = await createDevServer({
255746
256096
  log,
255747
256097
  port,
256098
+ cwd: process21.cwd(),
255748
256099
  denoWrapperPath: getDenoWrapperPath(),
255749
256100
  loadResources: async () => {
255750
256101
  const { functions, entities, project: project2 } = await readProjectConfig();
@@ -260252,4 +260603,4 @@ export {
260252
260603
  CLIExitError
260253
260604
  };
260254
260605
 
260255
- //# debugId=C6E0C5B984DF777364756E2164756E21
260606
+ //# debugId=FF5639434B8FD38C64756E2164756E21