@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 +505 -154
- package/dist/cli/index.js.map +16 -13
- package/package.json +1 -1
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
|
|
235045
|
-
const result = AuthDataSchema.safeParse(
|
|
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
|
|
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/
|
|
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
|
-
|
|
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 } =
|
|
253523
|
-
const
|
|
253524
|
-
if (!
|
|
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,
|
|
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 =
|
|
253628
|
-
const parseBody =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
253674
|
-
|
|
253675
|
-
|
|
253676
|
-
|
|
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
|
-
|
|
253695
|
-
|
|
253696
|
-
|
|
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
|
-
|
|
253701
|
-
|
|
253702
|
-
cursor3 = cursor3.projection(projection);
|
|
253983
|
+
if (schema10) {
|
|
253984
|
+
results = results.map((doc2) => applyFLS(doc2, schema10, currentUser, "read"));
|
|
253703
253985
|
}
|
|
253704
|
-
|
|
253705
|
-
res.json(stripInternalFields(docs));
|
|
253986
|
+
res.json(results);
|
|
253706
253987
|
} catch (error48) {
|
|
253707
|
-
|
|
253708
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
253804
|
-
|
|
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
|
|
253817
|
-
|
|
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
|
|
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 =
|
|
253837
|
-
const parseBody =
|
|
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 =
|
|
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 =
|
|
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",
|
|
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
|
-
|
|
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=
|
|
260606
|
+
//# debugId=FF5639434B8FD38C64756E2164756E21
|