@gzl10/nexus-backend 0.17.0 → 0.19.0
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/app-error-CKbYJQ9V.d.ts +136 -0
- package/dist/cli.js +2769 -9275
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +116 -142
- package/dist/index.js +1126 -359
- package/dist/index.js.map +1 -1
- package/dist/main.js +1136 -359
- package/dist/main.js.map +1 -1
- package/dist/migration-helpers/index.d.ts +63 -0
- package/dist/migration-helpers/index.js +12116 -0
- package/dist/migration-helpers/index.js.map +1 -0
- package/dist/testing/index.d.ts +81 -0
- package/dist/testing/index.js +1675 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +26 -23
package/dist/main.js
CHANGED
|
@@ -106,7 +106,7 @@ var init_package = __esm({
|
|
|
106
106
|
"package.json"() {
|
|
107
107
|
package_default = {
|
|
108
108
|
name: "@gzl10/nexus-backend",
|
|
109
|
-
version: "0.
|
|
109
|
+
version: "0.19.0",
|
|
110
110
|
description: "Backend as a Service (BaaS) with Express 5, Knex and CASL",
|
|
111
111
|
type: "module",
|
|
112
112
|
main: "./dist/index.js",
|
|
@@ -118,6 +118,14 @@ var init_package = __esm({
|
|
|
118
118
|
".": {
|
|
119
119
|
import: "./dist/index.js",
|
|
120
120
|
types: "./dist/index.d.ts"
|
|
121
|
+
},
|
|
122
|
+
"./testing": {
|
|
123
|
+
import: "./dist/testing/index.js",
|
|
124
|
+
types: "./dist/testing/index.d.ts"
|
|
125
|
+
},
|
|
126
|
+
"./migrations": {
|
|
127
|
+
import: "./dist/migration-helpers/index.js",
|
|
128
|
+
types: "./dist/migration-helpers/index.d.ts"
|
|
121
129
|
}
|
|
122
130
|
},
|
|
123
131
|
files: [
|
|
@@ -162,7 +170,7 @@ var init_package = __esm({
|
|
|
162
170
|
"jwt"
|
|
163
171
|
],
|
|
164
172
|
scripts: {
|
|
165
|
-
dev: "
|
|
173
|
+
dev: "node --watch-path=./src --import tsx/esm src/main.ts",
|
|
166
174
|
build: "tsup",
|
|
167
175
|
start: "node dist/main.js",
|
|
168
176
|
nexus: "tsx src/cli.ts",
|
|
@@ -218,39 +226,34 @@ var init_package = __esm({
|
|
|
218
226
|
zod: "^3.24.0"
|
|
219
227
|
},
|
|
220
228
|
devDependencies: {
|
|
221
|
-
"@gzl10/nexus-plugin-ai": "workspace:^",
|
|
222
|
-
"@gzl10/nexus-plugin-auth-providers": "workspace:^",
|
|
223
|
-
"@gzl10/nexus-plugin-charts": "workspace:^",
|
|
224
|
-
"@gzl10/nexus-plugin-cms": "workspace:^",
|
|
225
|
-
"@gzl10/nexus-plugin-compliance": "workspace:^",
|
|
226
|
-
"@gzl10/nexus-plugin-docker": "workspace:^",
|
|
227
|
-
"@gzl10/nexus-plugin-feeds": "workspace:^",
|
|
228
|
-
"@gzl10/nexus-plugin-importer": "workspace:^",
|
|
229
|
-
"@gzl10/nexus-plugin-links": "workspace:*",
|
|
230
|
-
"@gzl10/nexus-plugin-notifications": "workspace:*",
|
|
231
|
-
"@gzl10/nexus-plugin-oidc-server": "workspace:^",
|
|
232
|
-
"@gzl10/nexus-plugin-plane": "workspace:^",
|
|
233
|
-
"@gzl10/nexus-plugin-prisma": "workspace:^",
|
|
234
|
-
"@gzl10/nexus-plugin-remote": "workspace:*",
|
|
235
|
-
"@gzl10/nexus-plugin-schedules": "workspace:*",
|
|
236
|
-
"@gzl10/nexus-plugin-scim": "workspace:^",
|
|
237
|
-
"@gzl10/nexus-plugin-scraper": "workspace:^",
|
|
238
|
-
"@gzl10/nexus-plugin-secrets": "workspace:^",
|
|
239
|
-
"@gzl10/nexus-plugin-tags": "workspace:*",
|
|
240
|
-
"@gzl10/nexus-plugin-webhooks": "workspace:*",
|
|
241
229
|
"@types/bcryptjs": "^2.4.0",
|
|
242
230
|
"@types/compression": "^1.8.1",
|
|
243
231
|
"@types/cookie-parser": "^1.4.10",
|
|
244
232
|
"@types/cors": "^2.8.19",
|
|
245
233
|
"@types/express": "^5.0.6",
|
|
234
|
+
"@types/express-serve-static-core": "^5.1.1",
|
|
246
235
|
"@types/jsonwebtoken": "^9.0.10",
|
|
247
236
|
"@types/multer": "^2.1.0",
|
|
248
237
|
"@types/nodemailer": "^7.0.11",
|
|
238
|
+
"@types/qs": "^6.15.0",
|
|
249
239
|
"@types/supertest": "^6.0.3",
|
|
250
240
|
"pino-pretty": "^13.1.3",
|
|
251
241
|
"socket.io-client": "^4.8.3",
|
|
252
242
|
supertest: "^7.2.2",
|
|
253
|
-
tsx: "^4.21.0"
|
|
243
|
+
tsx: "^4.21.0",
|
|
244
|
+
vite: "^8.0.3"
|
|
245
|
+
},
|
|
246
|
+
peerDependencies: {
|
|
247
|
+
vite: ">=6.0.0",
|
|
248
|
+
vitest: ">=3.0.0"
|
|
249
|
+
},
|
|
250
|
+
peerDependenciesMeta: {
|
|
251
|
+
vite: {
|
|
252
|
+
optional: true
|
|
253
|
+
},
|
|
254
|
+
vitest: {
|
|
255
|
+
optional: true
|
|
256
|
+
}
|
|
254
257
|
},
|
|
255
258
|
publishConfig: {
|
|
256
259
|
access: "public",
|
|
@@ -1151,6 +1154,14 @@ async function isWorkspacePackage(name) {
|
|
|
1151
1154
|
}
|
|
1152
1155
|
}
|
|
1153
1156
|
async function installPlugin(name, opts) {
|
|
1157
|
+
const projectPath2 = opts?.projectPath ?? process.cwd();
|
|
1158
|
+
const pkgPath = join2(projectPath2, "package.json");
|
|
1159
|
+
if (existsSync2(pkgPath)) {
|
|
1160
|
+
const pkg3 = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1161
|
+
if (pkg3.name === "@gzl10/nexus-backend") {
|
|
1162
|
+
throw new Error("Cannot install plugins inside @gzl10/nexus-backend. Run this command from a Nexus project directory.");
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1154
1165
|
const isWorkspace = await isWorkspacePackage(name);
|
|
1155
1166
|
let pkg2;
|
|
1156
1167
|
if (opts?.version) {
|
|
@@ -1167,11 +1178,28 @@ async function installPlugin(name, opts) {
|
|
|
1167
1178
|
plugins[name] = { enabled: true };
|
|
1168
1179
|
writePluginsFile(plugins, filePath);
|
|
1169
1180
|
}
|
|
1181
|
+
function isPackageInstalled(name, projectPath2) {
|
|
1182
|
+
const base = projectPath2 || process.cwd();
|
|
1183
|
+
const pkgPath = join2(base, "package.json");
|
|
1184
|
+
try {
|
|
1185
|
+
const pkg2 = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1186
|
+
return !!(pkg2.dependencies?.[name] || pkg2.devDependencies?.[name]);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1170
1191
|
async function uninstallPlugin(name, projectPath2) {
|
|
1171
|
-
await execAsync(`pnpm remove ${name}`);
|
|
1172
1192
|
const filePath = getPluginsFilePath(projectPath2);
|
|
1173
1193
|
const plugins = readPluginsFile(filePath);
|
|
1174
|
-
|
|
1194
|
+
const isRegistered = name in plugins;
|
|
1195
|
+
const isInstalled = isPackageInstalled(name, projectPath2);
|
|
1196
|
+
if (!isRegistered && !isInstalled) {
|
|
1197
|
+
throw new Error(`Plugin ${shortPluginName(name)} is not installed`);
|
|
1198
|
+
}
|
|
1199
|
+
if (isInstalled) {
|
|
1200
|
+
await execAsync(`pnpm remove ${name}`);
|
|
1201
|
+
}
|
|
1202
|
+
if (isRegistered) {
|
|
1175
1203
|
delete plugins[name];
|
|
1176
1204
|
writePluginsFile(plugins, filePath);
|
|
1177
1205
|
}
|
|
@@ -1252,7 +1280,7 @@ var init_table_prefix = __esm({
|
|
|
1252
1280
|
}
|
|
1253
1281
|
});
|
|
1254
1282
|
|
|
1255
|
-
// src/engine/store.ts
|
|
1283
|
+
// src/engine/module-store.ts
|
|
1256
1284
|
function resetStore() {
|
|
1257
1285
|
moduleStore.modules.length = 0;
|
|
1258
1286
|
moduleStore.plugins.clear();
|
|
@@ -1263,8 +1291,8 @@ function resetStore() {
|
|
|
1263
1291
|
moduleStore.tableToSubject.clear();
|
|
1264
1292
|
}
|
|
1265
1293
|
var moduleStore;
|
|
1266
|
-
var
|
|
1267
|
-
"src/engine/store.ts"() {
|
|
1294
|
+
var init_module_store = __esm({
|
|
1295
|
+
"src/engine/module-store.ts"() {
|
|
1268
1296
|
"use strict";
|
|
1269
1297
|
moduleStore = {
|
|
1270
1298
|
/** Registered modules with source metadata */
|
|
@@ -1317,7 +1345,7 @@ var init_id = __esm({
|
|
|
1317
1345
|
}
|
|
1318
1346
|
});
|
|
1319
1347
|
|
|
1320
|
-
// src/engine/extractors.ts
|
|
1348
|
+
// src/engine/definition-extractors.ts
|
|
1321
1349
|
function getTableAndSubject(def) {
|
|
1322
1350
|
const caslSubject = def.casl?.subject;
|
|
1323
1351
|
if (!TYPES_WITH_TABLE.has(def.type)) {
|
|
@@ -1385,8 +1413,8 @@ function validateModuleDependencies(modules) {
|
|
|
1385
1413
|
}
|
|
1386
1414
|
}
|
|
1387
1415
|
var TYPES_WITH_TABLE;
|
|
1388
|
-
var
|
|
1389
|
-
"src/engine/extractors.ts"() {
|
|
1416
|
+
var init_definition_extractors = __esm({
|
|
1417
|
+
"src/engine/definition-extractors.ts"() {
|
|
1390
1418
|
"use strict";
|
|
1391
1419
|
TYPES_WITH_TABLE = /* @__PURE__ */ new Set(["collection", "reference", "event", "config", "temp", "view", void 0]);
|
|
1392
1420
|
}
|
|
@@ -1506,9 +1534,9 @@ var init_registry = __esm({
|
|
|
1506
1534
|
"use strict";
|
|
1507
1535
|
init_plugin_ops();
|
|
1508
1536
|
init_table_prefix();
|
|
1509
|
-
|
|
1537
|
+
init_module_store();
|
|
1510
1538
|
init_id();
|
|
1511
|
-
|
|
1539
|
+
init_definition_extractors();
|
|
1512
1540
|
}
|
|
1513
1541
|
});
|
|
1514
1542
|
|
|
@@ -1560,7 +1588,28 @@ var init_paths = __esm({
|
|
|
1560
1588
|
}
|
|
1561
1589
|
});
|
|
1562
1590
|
|
|
1563
|
-
// src/engine/queries.ts
|
|
1591
|
+
// src/engine/module-queries.ts
|
|
1592
|
+
var module_queries_exports = {};
|
|
1593
|
+
__export(module_queries_exports, {
|
|
1594
|
+
getCoreManifest: () => getCoreManifest,
|
|
1595
|
+
getCoreModules: () => getCoreModules,
|
|
1596
|
+
getModule: () => getModule,
|
|
1597
|
+
getModules: () => getModules,
|
|
1598
|
+
getOrderedModules: () => getOrderedModules,
|
|
1599
|
+
getOrderedModulesInternal: () => getOrderedModulesInternal,
|
|
1600
|
+
getPlugin: () => getPlugin,
|
|
1601
|
+
getPluginByCode: () => getPluginByCode,
|
|
1602
|
+
getPlugins: () => getPlugins,
|
|
1603
|
+
getRegisteredSubjects: () => getRegisteredSubjects,
|
|
1604
|
+
getSubjectForTable: () => getSubjectForTable,
|
|
1605
|
+
getUserManifest: () => getUserManifest,
|
|
1606
|
+
getUserModules: () => getUserModules,
|
|
1607
|
+
hasModule: () => hasModule,
|
|
1608
|
+
hasPlugin: () => hasPlugin,
|
|
1609
|
+
hasPluginByCode: () => hasPluginByCode,
|
|
1610
|
+
hasUserApp: () => hasUserApp,
|
|
1611
|
+
isValidSubject: () => isValidSubject
|
|
1612
|
+
});
|
|
1564
1613
|
import { join as join4 } from "path";
|
|
1565
1614
|
import { readFileSync as readFileSync3 } from "fs";
|
|
1566
1615
|
function readPackageJson(dir) {
|
|
@@ -1594,12 +1643,22 @@ function getOrderedModulesInternal() {
|
|
|
1594
1643
|
moduleStore.modules.forEach(visit);
|
|
1595
1644
|
return sorted;
|
|
1596
1645
|
}
|
|
1646
|
+
function getModule(name) {
|
|
1647
|
+
const mod = moduleStore.modules.find((m) => m.name === name);
|
|
1648
|
+
return mod ? toModuleManifest(mod) : void 0;
|
|
1649
|
+
}
|
|
1650
|
+
function getPlugin(name) {
|
|
1651
|
+
return moduleStore.plugins.get(name);
|
|
1652
|
+
}
|
|
1597
1653
|
function getPlugins() {
|
|
1598
1654
|
return [...moduleStore.plugins.values()];
|
|
1599
1655
|
}
|
|
1600
1656
|
function getRegisteredSubjects() {
|
|
1601
1657
|
return [...moduleStore.subjects];
|
|
1602
1658
|
}
|
|
1659
|
+
function isValidSubject(subject2) {
|
|
1660
|
+
return moduleStore.subjects.has(subject2);
|
|
1661
|
+
}
|
|
1603
1662
|
function getSubjectForTable(table) {
|
|
1604
1663
|
return moduleStore.tableToSubject.get(table);
|
|
1605
1664
|
}
|
|
@@ -1646,10 +1705,10 @@ function getPluginByCode(code) {
|
|
|
1646
1705
|
function hasPluginByCode(code) {
|
|
1647
1706
|
return moduleStore.pluginsByCode.has(code);
|
|
1648
1707
|
}
|
|
1649
|
-
var
|
|
1650
|
-
"src/engine/queries.ts"() {
|
|
1708
|
+
var init_module_queries = __esm({
|
|
1709
|
+
"src/engine/module-queries.ts"() {
|
|
1651
1710
|
"use strict";
|
|
1652
|
-
|
|
1711
|
+
init_module_store();
|
|
1653
1712
|
init_paths();
|
|
1654
1713
|
}
|
|
1655
1714
|
});
|
|
@@ -2128,17 +2187,22 @@ var init_definitions = __esm({
|
|
|
2128
2187
|
};
|
|
2129
2188
|
mastersEntity = {
|
|
2130
2189
|
table: "masters",
|
|
2190
|
+
seedable: true,
|
|
2131
2191
|
routePrefix: "/",
|
|
2132
2192
|
label: { en: "Master", es: "Maestro" },
|
|
2133
2193
|
labelPlural: { en: "Masters", es: "Maestros" },
|
|
2134
2194
|
labelField: "label",
|
|
2135
2195
|
timestamps: true,
|
|
2196
|
+
availableDisplayModes: ["board"],
|
|
2197
|
+
groupBy: "type",
|
|
2198
|
+
groupableFields: ["type"],
|
|
2199
|
+
//columnDragFields: ['is_active'],
|
|
2136
2200
|
fields: {
|
|
2137
2201
|
id: useTextField2({
|
|
2138
2202
|
label: { en: "ID", es: "ID" },
|
|
2139
2203
|
required: true,
|
|
2140
2204
|
size: 100,
|
|
2141
|
-
|
|
2205
|
+
hidden: true,
|
|
2142
2206
|
meta: { sortable: true }
|
|
2143
2207
|
}),
|
|
2144
2208
|
type: useTextField2({
|
|
@@ -2155,13 +2219,31 @@ var init_definitions = __esm({
|
|
|
2155
2219
|
meta: { sortable: true, searchable: true }
|
|
2156
2220
|
}),
|
|
2157
2221
|
label: useLocalizedField({ label: { en: "Name", es: "Nombre" } }),
|
|
2158
|
-
order: orderField,
|
|
2222
|
+
order: { ...orderField, meta: { ...orderField.meta, showInDisplay: false } },
|
|
2159
2223
|
is_active: isActiveField,
|
|
2160
2224
|
metadata: useJsonField({
|
|
2161
2225
|
label: { en: "Metadata", es: "Metadatos" },
|
|
2162
|
-
hint: {
|
|
2226
|
+
hint: {
|
|
2227
|
+
en: "Type-specific fields (symbol, flag, etc.)",
|
|
2228
|
+
es: "Campos espec\xEDficos del tipo"
|
|
2229
|
+
},
|
|
2230
|
+
meta: { showInDisplay: false }
|
|
2163
2231
|
})
|
|
2164
2232
|
},
|
|
2233
|
+
hooks: () => ({
|
|
2234
|
+
beforeCreate: async (data) => {
|
|
2235
|
+
if (data["type"] && data["code"] && !data["id"]) {
|
|
2236
|
+
data["id"] = `${data["type"]}:${data["code"]}`;
|
|
2237
|
+
}
|
|
2238
|
+
return data;
|
|
2239
|
+
},
|
|
2240
|
+
beforeUpdate: async (_id, data) => {
|
|
2241
|
+
if ("type" in data || "code" in data) {
|
|
2242
|
+
throw new Error("Cannot update type or code of a master record. Delete and recreate instead.");
|
|
2243
|
+
}
|
|
2244
|
+
return data;
|
|
2245
|
+
}
|
|
2246
|
+
}),
|
|
2165
2247
|
defaultSort: { field: "order", order: "asc" },
|
|
2166
2248
|
indexes: [{ columns: ["type", "code"], unique: true }],
|
|
2167
2249
|
casl: { subject: "Master", permissions: masterCaslPermissions }
|
|
@@ -2170,6 +2252,10 @@ var init_definitions = __esm({
|
|
|
2170
2252
|
});
|
|
2171
2253
|
|
|
2172
2254
|
// src/modules/masters/registry.ts
|
|
2255
|
+
var registry_exports = {};
|
|
2256
|
+
__export(registry_exports, {
|
|
2257
|
+
createMasterRegistry: () => createMasterRegistry
|
|
2258
|
+
});
|
|
2173
2259
|
function createMasterRegistry() {
|
|
2174
2260
|
const registrations = [];
|
|
2175
2261
|
return {
|
|
@@ -2207,7 +2293,7 @@ function createMasterRegistry() {
|
|
|
2207
2293
|
await ctx.db.knex("masters").insert(row).onConflict(["type", "code"]).merge();
|
|
2208
2294
|
}
|
|
2209
2295
|
} else {
|
|
2210
|
-
await ctx.db.knex("masters").insert(rows);
|
|
2296
|
+
await ctx.db.knex("masters").insert(rows).onConflict(["type", "code"]).ignore();
|
|
2211
2297
|
}
|
|
2212
2298
|
}
|
|
2213
2299
|
},
|
|
@@ -8640,15 +8726,12 @@ var init_document_types = __esm({
|
|
|
8640
8726
|
}
|
|
8641
8727
|
});
|
|
8642
8728
|
|
|
8643
|
-
// src/modules/masters/
|
|
8644
|
-
var
|
|
8645
|
-
var
|
|
8646
|
-
"src/modules/masters/
|
|
8729
|
+
// src/modules/masters/constants.ts
|
|
8730
|
+
var DEFAULT_MASTER_TYPES, PREDEFINED_MASTERS;
|
|
8731
|
+
var init_constants = __esm({
|
|
8732
|
+
"src/modules/masters/constants.ts"() {
|
|
8647
8733
|
"use strict";
|
|
8648
|
-
|
|
8649
|
-
init_registry2();
|
|
8650
|
-
init_definitions();
|
|
8651
|
-
init_registry2();
|
|
8734
|
+
DEFAULT_MASTER_TYPES = ["languages", "timezones"];
|
|
8652
8735
|
PREDEFINED_MASTERS = {
|
|
8653
8736
|
currencies: () => Promise.resolve().then(() => (init_currencies(), currencies_exports)).then((m) => m.default),
|
|
8654
8737
|
languages: () => Promise.resolve().then(() => (init_languages(), languages_exports)).then((m) => m.default),
|
|
@@ -8665,15 +8748,137 @@ var init_masters = __esm({
|
|
|
8665
8748
|
"phone-prefixes": () => Promise.resolve().then(() => (init_phone_prefixes(), phone_prefixes_exports)).then((m) => m.default),
|
|
8666
8749
|
"document-types": () => Promise.resolve().then(() => (init_document_types(), document_types_exports)).then((m) => m.default)
|
|
8667
8750
|
};
|
|
8751
|
+
}
|
|
8752
|
+
});
|
|
8753
|
+
|
|
8754
|
+
// src/modules/masters/actions/install-type.ts
|
|
8755
|
+
import { useSelectField as useSelectField2 } from "@gzl10/nexus-sdk/fields";
|
|
8756
|
+
var installTypeAction;
|
|
8757
|
+
var init_install_type = __esm({
|
|
8758
|
+
"src/modules/masters/actions/install-type.ts"() {
|
|
8759
|
+
"use strict";
|
|
8760
|
+
init_constants();
|
|
8761
|
+
installTypeAction = {
|
|
8762
|
+
key: "install-type",
|
|
8763
|
+
scope: "module",
|
|
8764
|
+
label: { en: "Install Master Type", es: "Instalar Tipo de Maestro" },
|
|
8765
|
+
icon: "mdi:database-plus",
|
|
8766
|
+
variant: "primary",
|
|
8767
|
+
output: {},
|
|
8768
|
+
input: {
|
|
8769
|
+
type: useSelectField2({
|
|
8770
|
+
label: { en: "Master Type", es: "Tipo de Maestro" },
|
|
8771
|
+
required: true,
|
|
8772
|
+
options: Object.keys(PREDEFINED_MASTERS).filter((t) => !DEFAULT_MASTER_TYPES.includes(t)).map((t) => ({
|
|
8773
|
+
value: t,
|
|
8774
|
+
label: t.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
8775
|
+
}))
|
|
8776
|
+
})
|
|
8777
|
+
},
|
|
8778
|
+
handler: async (ctx, input) => {
|
|
8779
|
+
if (process.env["NODE_ENV"] === "production") {
|
|
8780
|
+
throw new ctx.core.errors.ForbiddenError("Master type management is only available in development");
|
|
8781
|
+
}
|
|
8782
|
+
const { type: type2 } = input;
|
|
8783
|
+
const loader = PREDEFINED_MASTERS[type2];
|
|
8784
|
+
if (!loader) {
|
|
8785
|
+
throw new ctx.core.errors.AppError(`Unknown predefined master type: ${type2}`, 400);
|
|
8786
|
+
}
|
|
8787
|
+
const existing = await ctx.db.knex("masters").where({ type: type2 }).first();
|
|
8788
|
+
if (existing) {
|
|
8789
|
+
throw new ctx.core.errors.ConflictError(`Master type "${type2}" is already installed`);
|
|
8790
|
+
}
|
|
8791
|
+
const entries = await loader();
|
|
8792
|
+
const rows = entries.map((entry, i) => ({
|
|
8793
|
+
id: `${type2}:${entry.code}`,
|
|
8794
|
+
type: type2,
|
|
8795
|
+
code: entry.code,
|
|
8796
|
+
label: JSON.stringify(typeof entry.label === "string" ? { en: entry.label } : entry.label),
|
|
8797
|
+
order: entry.order ?? i,
|
|
8798
|
+
is_active: entry.is_active ?? true,
|
|
8799
|
+
metadata: entry.metadata ? JSON.stringify(entry.metadata) : null
|
|
8800
|
+
}));
|
|
8801
|
+
await ctx.db.knex("masters").insert(rows).onConflict(["type", "code"]).ignore();
|
|
8802
|
+
return { installed: type2, count: rows.length };
|
|
8803
|
+
}
|
|
8804
|
+
};
|
|
8805
|
+
}
|
|
8806
|
+
});
|
|
8807
|
+
|
|
8808
|
+
// src/modules/masters/actions/uninstall-type.ts
|
|
8809
|
+
import { useTextField as useTextField3 } from "@gzl10/nexus-sdk/fields";
|
|
8810
|
+
var uninstallTypeAction;
|
|
8811
|
+
var init_uninstall_type = __esm({
|
|
8812
|
+
"src/modules/masters/actions/uninstall-type.ts"() {
|
|
8813
|
+
"use strict";
|
|
8814
|
+
init_constants();
|
|
8815
|
+
uninstallTypeAction = {
|
|
8816
|
+
key: "uninstall-type",
|
|
8817
|
+
scope: "module",
|
|
8818
|
+
label: { en: "Uninstall Master Type", es: "Desinstalar Tipo de Maestro" },
|
|
8819
|
+
icon: "mdi:database-minus",
|
|
8820
|
+
variant: "danger",
|
|
8821
|
+
output: {},
|
|
8822
|
+
confirm: {
|
|
8823
|
+
type: "simple",
|
|
8824
|
+
title: { en: "Uninstall Master Type", es: "Desinstalar Tipo de Maestro" },
|
|
8825
|
+
message: {
|
|
8826
|
+
en: "This will delete ALL records of the selected type. This action cannot be undone.",
|
|
8827
|
+
es: "Esto eliminar\xE1 TODOS los registros del tipo seleccionado. Esta acci\xF3n no se puede deshacer."
|
|
8828
|
+
}
|
|
8829
|
+
},
|
|
8830
|
+
input: {
|
|
8831
|
+
type: useTextField3({
|
|
8832
|
+
label: { en: "Type slug to uninstall", es: "Slug del tipo a desinstalar" },
|
|
8833
|
+
required: true,
|
|
8834
|
+
hint: {
|
|
8835
|
+
en: 'Enter the master type slug (e.g., "currencies", "countries")',
|
|
8836
|
+
es: 'Introduce el slug del tipo (ej: "currencies", "countries")'
|
|
8837
|
+
}
|
|
8838
|
+
})
|
|
8839
|
+
},
|
|
8840
|
+
handler: async (ctx, input) => {
|
|
8841
|
+
if (process.env["NODE_ENV"] === "production") {
|
|
8842
|
+
throw new ctx.core.errors.ForbiddenError("Master type management is only available in development");
|
|
8843
|
+
}
|
|
8844
|
+
const { type: type2 } = input;
|
|
8845
|
+
if (DEFAULT_MASTER_TYPES.includes(type2)) {
|
|
8846
|
+
throw new ctx.core.errors.AppError(`Cannot uninstall default master type "${type2}" (required by core)`, 400);
|
|
8847
|
+
}
|
|
8848
|
+
const existing = await ctx.db.knex("masters").where({ type: type2 }).first();
|
|
8849
|
+
if (!existing) {
|
|
8850
|
+
throw new ctx.core.errors.NotFoundError(`Master type "${type2}" is not installed`);
|
|
8851
|
+
}
|
|
8852
|
+
const deleted = await ctx.db.knex("masters").where({ type: type2 }).del();
|
|
8853
|
+
return { uninstalled: type2, count: deleted };
|
|
8854
|
+
}
|
|
8855
|
+
};
|
|
8856
|
+
}
|
|
8857
|
+
});
|
|
8858
|
+
|
|
8859
|
+
// src/modules/masters/index.ts
|
|
8860
|
+
var mastersModule;
|
|
8861
|
+
var init_masters = __esm({
|
|
8862
|
+
"src/modules/masters/index.ts"() {
|
|
8863
|
+
"use strict";
|
|
8864
|
+
init_definitions();
|
|
8865
|
+
init_registry2();
|
|
8866
|
+
init_constants();
|
|
8867
|
+
init_install_type();
|
|
8868
|
+
init_uninstall_type();
|
|
8869
|
+
init_definitions();
|
|
8870
|
+
init_registry2();
|
|
8871
|
+
init_constants();
|
|
8668
8872
|
mastersModule = {
|
|
8669
8873
|
name: "masters",
|
|
8670
8874
|
type: "core",
|
|
8671
|
-
label: { en: "
|
|
8875
|
+
label: { en: "Masters", es: "Maestros" },
|
|
8672
8876
|
icon: "mdi:database-outline",
|
|
8673
8877
|
description: { en: "Reference data catalogs", es: "Cat\xE1logos de datos de referencia" },
|
|
8674
|
-
category: "
|
|
8878
|
+
category: "settings",
|
|
8675
8879
|
routePrefix: "/masters",
|
|
8676
8880
|
definitions: [mastersEntity],
|
|
8881
|
+
actions: [installTypeAction, uninstallTypeAction],
|
|
8677
8882
|
init: (ctx) => {
|
|
8678
8883
|
if (!ctx.services.has("masters")) {
|
|
8679
8884
|
ctx.services.register("masters", createMasterRegistry());
|
|
@@ -8684,13 +8889,14 @@ var init_masters = __esm({
|
|
|
8684
8889
|
ctx.services.register("masters", createMasterRegistry());
|
|
8685
8890
|
}
|
|
8686
8891
|
const registry2 = ctx.services.get("masters");
|
|
8687
|
-
const
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8892
|
+
const existing = await ctx.db.knex("masters").first();
|
|
8893
|
+
if (!existing) {
|
|
8894
|
+
for (const type2 of DEFAULT_MASTER_TYPES) {
|
|
8895
|
+
const loader = PREDEFINED_MASTERS[type2];
|
|
8896
|
+
if (!loader) continue;
|
|
8897
|
+
const entries = await loader();
|
|
8898
|
+
registry2.register(type2, entries, { seed: "if-empty" });
|
|
8899
|
+
}
|
|
8694
8900
|
}
|
|
8695
8901
|
await registry2.seed(ctx);
|
|
8696
8902
|
}
|
|
@@ -8848,15 +9054,18 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8848
9054
|
const meta = field["meta"];
|
|
8849
9055
|
return meta?.["sortable"] === true && !field["hidden"];
|
|
8850
9056
|
});
|
|
9057
|
+
const explicitGroupable = def["groupableFields"];
|
|
8851
9058
|
const groupableInputTypes = ["select", "switch", "checkbox", "radio", "tags"];
|
|
8852
|
-
const
|
|
9059
|
+
const autoGroupableFields = fieldEntries.filter(([, f]) => {
|
|
8853
9060
|
const field = f;
|
|
8854
9061
|
const inputType = field["input"];
|
|
8855
9062
|
return groupableInputTypes.includes(inputType ?? "") && !field["hidden"];
|
|
8856
9063
|
});
|
|
9064
|
+
const resolvedGroupableFields = explicitGroupable ?? (autoGroupableFields.length > 0 ? autoGroupableFields.map(([name]) => name) : void 0);
|
|
8857
9065
|
const entityType = def["type"] ?? "collection";
|
|
8858
9066
|
const explicitDisplayMode = def["displayMode"];
|
|
8859
|
-
const
|
|
9067
|
+
const explicitAvailableModes = def["availableDisplayModes"];
|
|
9068
|
+
const defaultDisplayMode = explicitDisplayMode ?? (explicitAvailableModes?.length === 1 ? explicitAvailableModes[0] : void 0) ?? (["tree", "dag"].includes(entityType) ? "tree" : "table");
|
|
8860
9069
|
const entityIdent = def["table"] ?? def["key"];
|
|
8861
9070
|
return {
|
|
8862
9071
|
id: def._id,
|
|
@@ -8876,9 +9085,11 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8876
9085
|
displayMode: explicitDisplayMode,
|
|
8877
9086
|
defaultDisplayMode,
|
|
8878
9087
|
availableDisplayModes: (() => {
|
|
9088
|
+
const explicit = def["availableDisplayModes"];
|
|
9089
|
+
if (explicit?.length) return explicit;
|
|
8879
9090
|
const modes = ["table", "list", "masonry"];
|
|
8880
9091
|
if (["tree", "dag"].includes(entityType)) modes.push("tree");
|
|
8881
|
-
if (
|
|
9092
|
+
if ((resolvedGroupableFields?.length ?? 0) > 0) modes.push("board");
|
|
8882
9093
|
if (def["calendarFrom"]) modes.push("calendar");
|
|
8883
9094
|
return modes;
|
|
8884
9095
|
})(),
|
|
@@ -8888,10 +9099,8 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8888
9099
|
value: name,
|
|
8889
9100
|
label: f["label"]
|
|
8890
9101
|
})),
|
|
8891
|
-
groupableFields:
|
|
8892
|
-
|
|
8893
|
-
label: f["label"]
|
|
8894
|
-
})) : void 0,
|
|
9102
|
+
groupableFields: resolvedGroupableFields,
|
|
9103
|
+
columnDragFields: def["columnDragFields"],
|
|
8895
9104
|
groupBy: def["groupBy"],
|
|
8896
9105
|
subgroupBy: def["subgroupBy"],
|
|
8897
9106
|
calendarFrom: def["calendarFrom"],
|
|
@@ -8931,21 +9140,6 @@ function toModuleDTO(mod, ctx) {
|
|
|
8931
9140
|
hasInit: !!mod.init
|
|
8932
9141
|
};
|
|
8933
9142
|
}
|
|
8934
|
-
function getOrderedModulesViaContext(ctx) {
|
|
8935
|
-
return ctx.engine.getModules();
|
|
8936
|
-
}
|
|
8937
|
-
async function runModuleSeedViaContext(mod, ctx) {
|
|
8938
|
-
if (!mod.seed) {
|
|
8939
|
-
return false;
|
|
8940
|
-
}
|
|
8941
|
-
try {
|
|
8942
|
-
await mod.seed(ctx);
|
|
8943
|
-
return true;
|
|
8944
|
-
} catch (err) {
|
|
8945
|
-
ctx.core.logger.error({ module: mod.name, err }, "Seed failed");
|
|
8946
|
-
return false;
|
|
8947
|
-
}
|
|
8948
|
-
}
|
|
8949
9143
|
var init_system_helpers = __esm({
|
|
8950
9144
|
"src/modules/system/system.helpers.ts"() {
|
|
8951
9145
|
"use strict";
|
|
@@ -8966,6 +9160,7 @@ function toPageDTO(page) {
|
|
|
8966
9160
|
dataSource: page.dataSource,
|
|
8967
9161
|
widgets: page.widgets,
|
|
8968
9162
|
component: page.component,
|
|
9163
|
+
contentEndpoint: page.contentEndpoint,
|
|
8969
9164
|
meta: page.meta,
|
|
8970
9165
|
layout: page.layout
|
|
8971
9166
|
};
|
|
@@ -9180,7 +9375,8 @@ function createSystemController(ctx) {
|
|
|
9180
9375
|
const plugins = engine.getPlugins();
|
|
9181
9376
|
const body = {
|
|
9182
9377
|
version: manifest.version,
|
|
9183
|
-
plugins: plugins.map((p) => p.code)
|
|
9378
|
+
plugins: plugins.map((p) => p.code),
|
|
9379
|
+
locales: ctx.locales
|
|
9184
9380
|
};
|
|
9185
9381
|
res.json(body);
|
|
9186
9382
|
}
|
|
@@ -9228,7 +9424,7 @@ var init_system_routes = __esm({
|
|
|
9228
9424
|
|
|
9229
9425
|
// src/modules/system/system.entity.ts
|
|
9230
9426
|
import * as os from "os";
|
|
9231
|
-
import { useIconField, useTextField as
|
|
9427
|
+
import { useIconField, useTextField as useTextField4, useSelectField as useSelectField3, useNumberField as useNumberField2, useCheckboxField, useTagsField, useNameField, useDescriptionField } from "@gzl10/nexus-sdk/fields";
|
|
9232
9428
|
var moduleEntity, osEntity;
|
|
9233
9429
|
var init_system_entity = __esm({
|
|
9234
9430
|
"src/modules/system/system.entity.ts"() {
|
|
@@ -9246,7 +9442,7 @@ var init_system_entity = __esm({
|
|
|
9246
9442
|
name: useNameField({
|
|
9247
9443
|
size: 50
|
|
9248
9444
|
}),
|
|
9249
|
-
label:
|
|
9445
|
+
label: useTextField4({
|
|
9250
9446
|
label: { en: "Label", es: "Etiqueta" },
|
|
9251
9447
|
size: 100,
|
|
9252
9448
|
nullable: false,
|
|
@@ -9254,7 +9450,7 @@ var init_system_entity = __esm({
|
|
|
9254
9450
|
}),
|
|
9255
9451
|
icon: useIconField({ label: { en: "Icon", es: "Icono" }, size: 50 }),
|
|
9256
9452
|
type: {
|
|
9257
|
-
...
|
|
9453
|
+
...useSelectField3({
|
|
9258
9454
|
label: { en: "Type", es: "Tipo" },
|
|
9259
9455
|
options: [
|
|
9260
9456
|
{ value: "core", label: { en: "Core", es: "Core" } },
|
|
@@ -9270,7 +9466,7 @@ var init_system_entity = __esm({
|
|
|
9270
9466
|
description: useDescriptionField({
|
|
9271
9467
|
mode: "text"
|
|
9272
9468
|
}),
|
|
9273
|
-
routePrefix:
|
|
9469
|
+
routePrefix: useTextField4({
|
|
9274
9470
|
label: { en: "Route", es: "Ruta" },
|
|
9275
9471
|
size: 50,
|
|
9276
9472
|
nullable: true
|
|
@@ -9328,14 +9524,14 @@ var init_system_entity = __esm({
|
|
|
9328
9524
|
order: 1,
|
|
9329
9525
|
refreshInterval: 5e3,
|
|
9330
9526
|
fields: {
|
|
9331
|
-
hostname:
|
|
9527
|
+
hostname: useTextField4({
|
|
9332
9528
|
label: { en: "Hostname", es: "Nombre de servidor" },
|
|
9333
9529
|
size: 100,
|
|
9334
9530
|
nullable: false,
|
|
9335
9531
|
inputProps: { order: 1 }
|
|
9336
9532
|
}),
|
|
9337
9533
|
platform: {
|
|
9338
|
-
...
|
|
9534
|
+
...useSelectField3({
|
|
9339
9535
|
label: { en: "Platform", es: "Plataforma" },
|
|
9340
9536
|
options: [
|
|
9341
9537
|
{ value: "darwin", label: { en: "macOS", es: "macOS" } },
|
|
@@ -9349,7 +9545,7 @@ var init_system_entity = __esm({
|
|
|
9349
9545
|
inputProps: { order: 2 }
|
|
9350
9546
|
},
|
|
9351
9547
|
arch: {
|
|
9352
|
-
...
|
|
9548
|
+
...useSelectField3({
|
|
9353
9549
|
label: { en: "Architecture", es: "Arquitectura" },
|
|
9354
9550
|
options: [
|
|
9355
9551
|
{ value: "x64", label: { en: "x64", es: "x64" } },
|
|
@@ -9362,7 +9558,7 @@ var init_system_entity = __esm({
|
|
|
9362
9558
|
inputProps: { order: 3 }
|
|
9363
9559
|
},
|
|
9364
9560
|
type: {
|
|
9365
|
-
...
|
|
9561
|
+
...useTextField4({
|
|
9366
9562
|
label: { en: "Type", es: "Tipo" },
|
|
9367
9563
|
size: 30,
|
|
9368
9564
|
nullable: false
|
|
@@ -9370,7 +9566,7 @@ var init_system_entity = __esm({
|
|
|
9370
9566
|
inputProps: { order: 4 }
|
|
9371
9567
|
},
|
|
9372
9568
|
release: {
|
|
9373
|
-
...
|
|
9569
|
+
...useTextField4({
|
|
9374
9570
|
label: { en: "Release", es: "Versi\xF3n" },
|
|
9375
9571
|
size: 50,
|
|
9376
9572
|
nullable: false
|
|
@@ -9393,7 +9589,7 @@ var init_system_entity = __esm({
|
|
|
9393
9589
|
inputProps: { order: 7, format: "duration" }
|
|
9394
9590
|
},
|
|
9395
9591
|
cpuModel: {
|
|
9396
|
-
...
|
|
9592
|
+
...useTextField4({
|
|
9397
9593
|
label: { en: "CPU Model", es: "Modelo de CPU" },
|
|
9398
9594
|
size: 100,
|
|
9399
9595
|
nullable: false
|
|
@@ -9459,7 +9655,7 @@ var init_system_entity = __esm({
|
|
|
9459
9655
|
});
|
|
9460
9656
|
|
|
9461
9657
|
// src/modules/system/migration-history.entity.ts
|
|
9462
|
-
import { useIdField as useIdField2, useTextField as
|
|
9658
|
+
import { useIdField as useIdField2, useTextField as useTextField5, useNumberField as useNumberField3, useSelectField as useSelectField4, useDatetimeField as useDatetimeField2, useTextareaField as useTextareaField2 } from "@gzl10/nexus-sdk/fields";
|
|
9463
9659
|
var migrationHistoryEntity;
|
|
9464
9660
|
var init_migration_history_entity = __esm({
|
|
9465
9661
|
"src/modules/system/migration-history.entity.ts"() {
|
|
@@ -9476,9 +9672,9 @@ var init_migration_history_entity = __esm({
|
|
|
9476
9672
|
calendarFrom: "executed_at",
|
|
9477
9673
|
fields: {
|
|
9478
9674
|
id: useIdField2(),
|
|
9479
|
-
name:
|
|
9675
|
+
name: useTextField5({ label: { en: "Migration Name", es: "Nombre de la Migraci\xF3n" }, required: true, size: 255, unique: true, meta: { sortable: true, searchable: true } }),
|
|
9480
9676
|
batch: useNumberField3({ label: { en: "Batch", es: "Lote" }, required: true, meta: { sortable: true } }),
|
|
9481
|
-
status:
|
|
9677
|
+
status: useSelectField4({
|
|
9482
9678
|
label: { en: "Status", es: "Estado" },
|
|
9483
9679
|
options: [
|
|
9484
9680
|
{ value: "running", label: { en: "Running", es: "Ejecutando" } },
|
|
@@ -9510,7 +9706,7 @@ var init_migration_history_entity = __esm({
|
|
|
9510
9706
|
});
|
|
9511
9707
|
|
|
9512
9708
|
// src/modules/system/env-config.entity.ts
|
|
9513
|
-
import { useTextField as
|
|
9709
|
+
import { useTextField as useTextField6, useSelectField as useSelectField5, useCheckboxField as useCheckboxField2 } from "@gzl10/nexus-sdk/fields";
|
|
9514
9710
|
function maskValue(value, sensitive) {
|
|
9515
9711
|
if (!sensitive) return value;
|
|
9516
9712
|
try {
|
|
@@ -9535,14 +9731,14 @@ var init_env_config_entity = __esm({
|
|
|
9535
9731
|
routePrefix: "/env-config",
|
|
9536
9732
|
defaultSort: { field: "category", order: "asc" },
|
|
9537
9733
|
fields: {
|
|
9538
|
-
name:
|
|
9734
|
+
name: useTextField6({
|
|
9539
9735
|
label: { en: "Variable", es: "Variable" },
|
|
9540
9736
|
size: 100,
|
|
9541
9737
|
nullable: false,
|
|
9542
9738
|
meta: { sortable: true, searchable: true }
|
|
9543
9739
|
}),
|
|
9544
9740
|
category: {
|
|
9545
|
-
...
|
|
9741
|
+
...useSelectField5({
|
|
9546
9742
|
label: { en: "Category", es: "Categor\xEDa" },
|
|
9547
9743
|
options: [
|
|
9548
9744
|
{ value: "server", label: { en: "Server", es: "Servidor" } },
|
|
@@ -9557,18 +9753,18 @@ var init_env_config_entity = __esm({
|
|
|
9557
9753
|
meta: { sortable: true }
|
|
9558
9754
|
})
|
|
9559
9755
|
},
|
|
9560
|
-
source:
|
|
9756
|
+
source: useTextField6({
|
|
9561
9757
|
label: { en: "Source", es: "Origen" },
|
|
9562
9758
|
size: 50,
|
|
9563
9759
|
nullable: false,
|
|
9564
9760
|
meta: { sortable: true }
|
|
9565
9761
|
}),
|
|
9566
|
-
value:
|
|
9762
|
+
value: useTextField6({
|
|
9567
9763
|
label: { en: "Value", es: "Valor" },
|
|
9568
9764
|
size: 255,
|
|
9569
9765
|
nullable: true
|
|
9570
9766
|
}),
|
|
9571
|
-
default:
|
|
9767
|
+
default: useTextField6({
|
|
9572
9768
|
label: { en: "Default", es: "Por defecto" },
|
|
9573
9769
|
size: 100,
|
|
9574
9770
|
nullable: true
|
|
@@ -10067,7 +10263,6 @@ var SYSTEM_TABLES, factoryResetAction;
|
|
|
10067
10263
|
var init_factory_reset_action = __esm({
|
|
10068
10264
|
"src/modules/system/actions/factory-reset.action.ts"() {
|
|
10069
10265
|
"use strict";
|
|
10070
|
-
init_system_helpers();
|
|
10071
10266
|
SYSTEM_TABLES = /* @__PURE__ */ new Set([
|
|
10072
10267
|
"_nexus_migrations",
|
|
10073
10268
|
"_nexus_migration_lock",
|
|
@@ -10110,8 +10305,8 @@ var init_factory_reset_action = __esm({
|
|
|
10110
10305
|
source: "core:system",
|
|
10111
10306
|
action: "factory_reset",
|
|
10112
10307
|
actorId: authReq.user?.id,
|
|
10113
|
-
ip: req
|
|
10114
|
-
userAgent: req
|
|
10308
|
+
ip: req?.ip,
|
|
10309
|
+
userAgent: req?.headers["user-agent"]
|
|
10115
10310
|
});
|
|
10116
10311
|
await new Promise((resolve2) => setImmediate(resolve2));
|
|
10117
10312
|
const allTables = await getAllTables(knex3);
|
|
@@ -10149,11 +10344,11 @@ var init_factory_reset_action = __esm({
|
|
|
10149
10344
|
} catch {
|
|
10150
10345
|
}
|
|
10151
10346
|
ctx.core.logger.info({ tables: dataTables.length }, "All data tables cleared");
|
|
10152
|
-
const modules =
|
|
10347
|
+
const modules = ctx.engine.getModules();
|
|
10153
10348
|
let modulesSeeded = 0;
|
|
10154
10349
|
for (const mod of modules) {
|
|
10155
10350
|
try {
|
|
10156
|
-
const seeded = await
|
|
10351
|
+
const seeded = await ctx.db.seedModule(mod);
|
|
10157
10352
|
if (seeded) modulesSeeded++;
|
|
10158
10353
|
} catch (err) {
|
|
10159
10354
|
ctx.core.logger.error({ module: mod.name, err }, "Seed failed during factory reset");
|
|
@@ -10207,8 +10402,8 @@ var init_restart_server_action = __esm({
|
|
|
10207
10402
|
source: "core:system",
|
|
10208
10403
|
action: "server_restart",
|
|
10209
10404
|
actorId: authReq.user?.id,
|
|
10210
|
-
ip: req
|
|
10211
|
-
userAgent: req
|
|
10405
|
+
ip: req?.ip,
|
|
10406
|
+
userAgent: req?.headers["user-agent"]
|
|
10212
10407
|
});
|
|
10213
10408
|
setTimeout(() => process.exit(0), 500);
|
|
10214
10409
|
return { success: true, message: "Server is restarting..." };
|
|
@@ -10275,7 +10470,7 @@ var init_system = __esm({
|
|
|
10275
10470
|
});
|
|
10276
10471
|
|
|
10277
10472
|
// src/modules/ui-settings/ui-branding.entity.ts
|
|
10278
|
-
import { useTextField as
|
|
10473
|
+
import { useTextField as useTextField7, useImageField } from "@gzl10/nexus-sdk/fields";
|
|
10279
10474
|
var uiBrandingEntity;
|
|
10280
10475
|
var init_ui_branding_entity = __esm({
|
|
10281
10476
|
"src/modules/ui-settings/ui-branding.entity.ts"() {
|
|
@@ -10295,7 +10490,7 @@ var init_ui_branding_entity = __esm({
|
|
|
10295
10490
|
favicon: null
|
|
10296
10491
|
},
|
|
10297
10492
|
fields: {
|
|
10298
|
-
appName:
|
|
10493
|
+
appName: useTextField7({
|
|
10299
10494
|
label: { en: "App Name", es: "Nombre de la App" },
|
|
10300
10495
|
hint: { en: "Displayed in the header, browser tab and emails", es: "Se muestra en el header, pesta\xF1a del navegador y emails" },
|
|
10301
10496
|
size: 100,
|
|
@@ -10336,7 +10531,7 @@ var init_ui_branding_entity = __esm({
|
|
|
10336
10531
|
});
|
|
10337
10532
|
|
|
10338
10533
|
// src/modules/ui-settings/ui-theme.entity.ts
|
|
10339
|
-
import { useSelectField as
|
|
10534
|
+
import { useSelectField as useSelectField6, useColorField } from "@gzl10/nexus-sdk/fields";
|
|
10340
10535
|
var uiThemeEntity;
|
|
10341
10536
|
var init_ui_theme_entity = __esm({
|
|
10342
10537
|
"src/modules/ui-settings/ui-theme.entity.ts"() {
|
|
@@ -10361,7 +10556,7 @@ var init_ui_theme_entity = __esm({
|
|
|
10361
10556
|
},
|
|
10362
10557
|
fields: {
|
|
10363
10558
|
// === Typography ===
|
|
10364
|
-
font:
|
|
10559
|
+
font: useSelectField6({
|
|
10365
10560
|
label: { en: "Font", es: "Fuente" },
|
|
10366
10561
|
hint: { en: "Primary font for headings and UI elements", es: "Fuente principal para t\xEDtulos y elementos de interfaz" },
|
|
10367
10562
|
options: [
|
|
@@ -10374,7 +10569,7 @@ var init_ui_theme_entity = __esm({
|
|
|
10374
10569
|
]
|
|
10375
10570
|
}),
|
|
10376
10571
|
// === Theme & Colors ===
|
|
10377
|
-
theme:
|
|
10572
|
+
theme: useSelectField6({
|
|
10378
10573
|
label: { en: "Theme", es: "Tema" },
|
|
10379
10574
|
hint: { en: "System follows your device preferences", es: "Sistema sigue las preferencias de tu dispositivo" },
|
|
10380
10575
|
options: [
|
|
@@ -10383,7 +10578,7 @@ var init_ui_theme_entity = __esm({
|
|
|
10383
10578
|
{ value: "system", label: { en: "System", es: "Sistema" } }
|
|
10384
10579
|
]
|
|
10385
10580
|
}),
|
|
10386
|
-
dopamineTheme:
|
|
10581
|
+
dopamineTheme: useSelectField6({
|
|
10387
10582
|
label: { en: "Dopamine Theme", es: "Tema Dopamina" },
|
|
10388
10583
|
hint: { en: "Vibrant color presets optimized for light and dark modes (2025/2026 trends)", es: "Presets de colores vibrantes optimizados para modo claro y oscuro (tendencias 2025/2026)" },
|
|
10389
10584
|
options: [
|
|
@@ -10401,7 +10596,7 @@ var init_ui_theme_entity = __esm({
|
|
|
10401
10596
|
]
|
|
10402
10597
|
}),
|
|
10403
10598
|
// === Login Layout ===
|
|
10404
|
-
loginLayout:
|
|
10599
|
+
loginLayout: useSelectField6({
|
|
10405
10600
|
label: { en: "Login Layout", es: "Dise\xF1o de Login" },
|
|
10406
10601
|
hint: { en: "Visual layout for authentication pages", es: "Dise\xF1o visual para p\xE1ginas de autenticaci\xF3n" },
|
|
10407
10602
|
options: [
|
|
@@ -10432,7 +10627,7 @@ var init_ui_theme_entity = __esm({
|
|
|
10432
10627
|
});
|
|
10433
10628
|
|
|
10434
10629
|
// src/modules/ui-settings/ui-effects.entity.ts
|
|
10435
|
-
import { useSelectField as
|
|
10630
|
+
import { useSelectField as useSelectField7, useSwitchField as useSwitchField2 } from "@gzl10/nexus-sdk/fields";
|
|
10436
10631
|
var uiEffectsEntity;
|
|
10437
10632
|
var init_ui_effects_entity = __esm({
|
|
10438
10633
|
"src/modules/ui-settings/ui-effects.entity.ts"() {
|
|
@@ -10452,7 +10647,7 @@ var init_ui_effects_entity = __esm({
|
|
|
10452
10647
|
enableOrganicShapes: false
|
|
10453
10648
|
},
|
|
10454
10649
|
fields: {
|
|
10455
|
-
glassIntensity:
|
|
10650
|
+
glassIntensity: useSelectField7({
|
|
10456
10651
|
label: { en: "Glass Intensity", es: "Intensidad Glass" },
|
|
10457
10652
|
hint: { en: "Glassmorphism blur effect on cards and modals", es: "Efecto de desenfoque glassmorphism en cards y modales" },
|
|
10458
10653
|
options: [
|
|
@@ -10462,7 +10657,7 @@ var init_ui_effects_entity = __esm({
|
|
|
10462
10657
|
{ value: "high", label: { en: "High", es: "Alta" } }
|
|
10463
10658
|
]
|
|
10464
10659
|
}),
|
|
10465
|
-
borderStyle:
|
|
10660
|
+
borderStyle: useSelectField7({
|
|
10466
10661
|
label: { en: "Border Style", es: "Estilo de Bordes" },
|
|
10467
10662
|
hint: { en: "Corner radius for buttons, cards and inputs", es: "Radio de esquinas para botones, cards e inputs" },
|
|
10468
10663
|
options: [
|
|
@@ -10496,7 +10691,7 @@ var init_ui_effects_entity = __esm({
|
|
|
10496
10691
|
});
|
|
10497
10692
|
|
|
10498
10693
|
// src/modules/ui-settings/ui-accessibility.entity.ts
|
|
10499
|
-
import { useSelectField as
|
|
10694
|
+
import { useSelectField as useSelectField8, useSwitchField as useSwitchField3 } from "@gzl10/nexus-sdk/fields";
|
|
10500
10695
|
var uiAccessibilityEntity;
|
|
10501
10696
|
var init_ui_accessibility_entity = __esm({
|
|
10502
10697
|
"src/modules/ui-settings/ui-accessibility.entity.ts"() {
|
|
@@ -10515,7 +10710,7 @@ var init_ui_accessibility_entity = __esm({
|
|
|
10515
10710
|
highContrast: false
|
|
10516
10711
|
},
|
|
10517
10712
|
fields: {
|
|
10518
|
-
typographyScale:
|
|
10713
|
+
typographyScale: useSelectField8({
|
|
10519
10714
|
label: { en: "Typography Scale", es: "Escala Tipogr\xE1fica" },
|
|
10520
10715
|
hint: { en: "Adjusts font sizes for better readability (WCAG 1.4.4)", es: "Ajusta tama\xF1os de fuente para mejor legibilidad (WCAG 1.4.4)" },
|
|
10521
10716
|
options: [
|
|
@@ -11506,7 +11701,7 @@ var init_storage_service = __esm({
|
|
|
11506
11701
|
});
|
|
11507
11702
|
|
|
11508
11703
|
// src/modules/storage/storage.entity.ts
|
|
11509
|
-
import { useIdField as useIdField3, useTextField as
|
|
11704
|
+
import { useIdField as useIdField3, useTextField as useTextField8, useSelectField as useSelectField9, useUrlField, useNumberField as useNumberField4, useCheckboxField as useCheckboxField3, useJsonField as useJsonField2, useMetadataField, usePublicField } from "@gzl10/nexus-sdk/fields";
|
|
11510
11705
|
var DEFAULT_MAX_SIZE2, storageConfigEntity, storageFilesEntity;
|
|
11511
11706
|
var init_storage_entity = __esm({
|
|
11512
11707
|
"src/modules/storage/storage.entity.ts"() {
|
|
@@ -11532,7 +11727,7 @@ var init_storage_entity = __esm({
|
|
|
11532
11727
|
},
|
|
11533
11728
|
fields: {
|
|
11534
11729
|
id: useIdField3(),
|
|
11535
|
-
scope:
|
|
11730
|
+
scope: useTextField8({
|
|
11536
11731
|
label: { en: "Scope", es: "\xC1mbito" },
|
|
11537
11732
|
disabled: true,
|
|
11538
11733
|
size: 100,
|
|
@@ -11541,7 +11736,7 @@ var init_storage_entity = __esm({
|
|
|
11541
11736
|
hint: { en: "Unique identifier (e.g. default_filesystem, default_s3)", es: "Identificador \xFAnico (ej: default_filesystem, default_s3)" }
|
|
11542
11737
|
}),
|
|
11543
11738
|
driver: {
|
|
11544
|
-
...
|
|
11739
|
+
...useSelectField9({
|
|
11545
11740
|
label: { en: "Driver", es: "Controlador" },
|
|
11546
11741
|
required: true,
|
|
11547
11742
|
hint: { en: "Storage backend", es: "Backend de almacenamiento" },
|
|
@@ -11564,7 +11759,7 @@ var init_storage_entity = __esm({
|
|
|
11564
11759
|
nullable: false,
|
|
11565
11760
|
displayProps: { format: "bytes" }
|
|
11566
11761
|
}),
|
|
11567
|
-
allowed_mime_types:
|
|
11762
|
+
allowed_mime_types: useTextField8({
|
|
11568
11763
|
label: { en: "Allowed MIME Types", es: "Tipos MIME permitidos" },
|
|
11569
11764
|
hint: { en: "Allowed types separated by comma (e.g. image/*,application/pdf)", es: "Tipos permitidos separados por coma (ej: image/*,application/pdf)" },
|
|
11570
11765
|
size: 1e3,
|
|
@@ -11729,21 +11924,21 @@ var init_storage_entity = __esm({
|
|
|
11729
11924
|
],
|
|
11730
11925
|
fields: {
|
|
11731
11926
|
id: useIdField3(),
|
|
11732
|
-
filename:
|
|
11927
|
+
filename: useTextField8({
|
|
11733
11928
|
label: { en: "Original Filename", es: "Nombre original" },
|
|
11734
11929
|
required: true,
|
|
11735
11930
|
size: 255,
|
|
11736
11931
|
nullable: false,
|
|
11737
11932
|
meta: { sortable: true, searchable: true }
|
|
11738
11933
|
}),
|
|
11739
|
-
disk_filename:
|
|
11934
|
+
disk_filename: useTextField8({
|
|
11740
11935
|
label: { en: "Disk Filename", es: "Nombre en disco" },
|
|
11741
11936
|
required: true,
|
|
11742
11937
|
hidden: true,
|
|
11743
11938
|
size: 255,
|
|
11744
11939
|
nullable: false
|
|
11745
11940
|
}),
|
|
11746
|
-
mimetype:
|
|
11941
|
+
mimetype: useTextField8({
|
|
11747
11942
|
label: { en: "MIME Type", es: "Tipo MIME" },
|
|
11748
11943
|
required: true,
|
|
11749
11944
|
size: 100,
|
|
@@ -11759,14 +11954,14 @@ var init_storage_entity = __esm({
|
|
|
11759
11954
|
meta: { sortable: true },
|
|
11760
11955
|
displayProps: { format: "bytes" }
|
|
11761
11956
|
}),
|
|
11762
|
-
folder:
|
|
11957
|
+
folder: useTextField8({
|
|
11763
11958
|
label: { en: "Folder", es: "Carpeta" },
|
|
11764
11959
|
size: 100,
|
|
11765
11960
|
nullable: true,
|
|
11766
11961
|
index: true,
|
|
11767
11962
|
meta: { searchable: true }
|
|
11768
11963
|
}),
|
|
11769
|
-
scope:
|
|
11964
|
+
scope: useTextField8({
|
|
11770
11965
|
label: { en: "Storage Scope", es: "\xC1mbito de almacenamiento" },
|
|
11771
11966
|
hidden: true,
|
|
11772
11967
|
size: 50,
|
|
@@ -11777,7 +11972,7 @@ var init_storage_entity = __esm({
|
|
|
11777
11972
|
es: "\xC1mbito de configuraci\xF3n de almacenamiento usado para este archivo"
|
|
11778
11973
|
}
|
|
11779
11974
|
}),
|
|
11780
|
-
path:
|
|
11975
|
+
path: useTextField8({
|
|
11781
11976
|
label: { en: "Full Path", es: "Ruta completa" },
|
|
11782
11977
|
required: true,
|
|
11783
11978
|
hidden: true,
|
|
@@ -11790,13 +11985,13 @@ var init_storage_entity = __esm({
|
|
|
11790
11985
|
nullable: true,
|
|
11791
11986
|
meta: { exportable: true, showInDisplay: false }
|
|
11792
11987
|
}),
|
|
11793
|
-
thumbnail_path:
|
|
11988
|
+
thumbnail_path: useTextField8({
|
|
11794
11989
|
label: { en: "Thumbnail Path", es: "Ruta de miniatura" },
|
|
11795
11990
|
size: 500,
|
|
11796
11991
|
nullable: true,
|
|
11797
11992
|
meta: { showInDisplay: false }
|
|
11798
11993
|
}),
|
|
11799
|
-
hash:
|
|
11994
|
+
hash: useTextField8({
|
|
11800
11995
|
label: { en: "SHA256 Hash", es: "Hash SHA256" },
|
|
11801
11996
|
hidden: true,
|
|
11802
11997
|
size: 64,
|
|
@@ -11830,7 +12025,7 @@ function createUploadMiddleware(ctx, options) {
|
|
|
11830
12025
|
const rateLimit2 = ctx.core.middleware.rateLimit({
|
|
11831
12026
|
windowMs: 60 * 1e3,
|
|
11832
12027
|
max: 20,
|
|
11833
|
-
message: "
|
|
12028
|
+
message: "Too many uploads, try again in 1 minute"
|
|
11834
12029
|
});
|
|
11835
12030
|
const upload = multer({
|
|
11836
12031
|
storage: multer.memoryStorage(),
|
|
@@ -12077,7 +12272,7 @@ function createStorageRoutes(ctx) {
|
|
|
12077
12272
|
}
|
|
12078
12273
|
res.status(201).json(results);
|
|
12079
12274
|
};
|
|
12080
|
-
const uploadRateLimit = ctx.core.middleware.rateLimit({ windowMs: 60 * 1e3, max: 20, message: "
|
|
12275
|
+
const uploadRateLimit = ctx.core.middleware.rateLimit({ windowMs: 60 * 1e3, max: 20, message: "Too many uploads, try again in 1 minute" });
|
|
12081
12276
|
if (auth) {
|
|
12082
12277
|
router.post("/upload/multiple", uploadRateLimit, auth, upload.array("files", 10), uploadMultiple);
|
|
12083
12278
|
} else {
|
|
@@ -12293,7 +12488,7 @@ var init_storage = __esm({
|
|
|
12293
12488
|
});
|
|
12294
12489
|
|
|
12295
12490
|
// src/modules/users/users.entity.ts
|
|
12296
|
-
import { useIdField as useIdField4, useSelectField as
|
|
12491
|
+
import { useIdField as useIdField4, useSelectField as useSelectField10, useEmailField, usePasswordField, useTextField as useTextField9, useDatetimeField as useDatetimeField3, useCheckboxField as useCheckboxField4, useImageField as useImageField2, useNameField as useNameField2, useMetadataField as useMetadataField2, useDescriptionField as useDescriptionField2 } from "@gzl10/nexus-sdk/fields";
|
|
12297
12492
|
import { z as z3 } from "zod";
|
|
12298
12493
|
var userEntity, roleEntity, userRoleEntity;
|
|
12299
12494
|
var init_users_entity = __esm({
|
|
@@ -12356,7 +12551,7 @@ var init_users_entity = __esm({
|
|
|
12356
12551
|
nullable: true,
|
|
12357
12552
|
meta: { exportable: true, showInForm: false, showInDisplay: false }
|
|
12358
12553
|
}),
|
|
12359
|
-
consent_version:
|
|
12554
|
+
consent_version: useTextField9({
|
|
12360
12555
|
label: { en: "Consent Version", es: "Versi\xF3n de consentimiento" },
|
|
12361
12556
|
hidden: true,
|
|
12362
12557
|
size: 20,
|
|
@@ -12367,7 +12562,7 @@ var init_users_entity = __esm({
|
|
|
12367
12562
|
label: { en: "Marketing Opt-in", es: "Aceptar marketing" },
|
|
12368
12563
|
meta: { exportable: true, showInForm: false, showInDisplay: false }
|
|
12369
12564
|
}),
|
|
12370
|
-
locale:
|
|
12565
|
+
locale: useSelectField10({
|
|
12371
12566
|
label: { en: "Language", es: "Idioma" },
|
|
12372
12567
|
options: [
|
|
12373
12568
|
{ value: "es", label: { en: "Spanish", es: "Espa\xF1ol" } },
|
|
@@ -12375,15 +12570,15 @@ var init_users_entity = __esm({
|
|
|
12375
12570
|
],
|
|
12376
12571
|
nullable: true,
|
|
12377
12572
|
meta: { sortable: true },
|
|
12378
|
-
defaultValue: "
|
|
12573
|
+
defaultValue: "en"
|
|
12379
12574
|
}),
|
|
12380
|
-
timezone:
|
|
12575
|
+
timezone: useSelectField10({
|
|
12381
12576
|
label: { en: "Timezone", es: "Zona horaria" },
|
|
12382
12577
|
master: "timezones",
|
|
12383
12578
|
meta: { sortable: true },
|
|
12384
12579
|
defaultValue: "timezones:Europe/Madrid"
|
|
12385
12580
|
}),
|
|
12386
|
-
type:
|
|
12581
|
+
type: useSelectField10({
|
|
12387
12582
|
label: { en: "Type", es: "Tipo" },
|
|
12388
12583
|
defaultValue: "human",
|
|
12389
12584
|
options: [
|
|
@@ -12453,7 +12648,7 @@ var init_users_entity = __esm({
|
|
|
12453
12648
|
middleware: (ctx) => ctx.core.middleware.rateLimit({
|
|
12454
12649
|
windowMs: 15 * 60 * 1e3,
|
|
12455
12650
|
max: 5,
|
|
12456
|
-
message: "
|
|
12651
|
+
message: "Too many attempts, try again in 15 minutes"
|
|
12457
12652
|
}),
|
|
12458
12653
|
handler: async (ctx, input) => {
|
|
12459
12654
|
const {
|
|
@@ -12552,7 +12747,7 @@ var init_users_entity = __esm({
|
|
|
12552
12747
|
expose: false,
|
|
12553
12748
|
fields: {
|
|
12554
12749
|
id: useIdField4(),
|
|
12555
|
-
user_id:
|
|
12750
|
+
user_id: useSelectField10({
|
|
12556
12751
|
label: { en: "User", es: "Usuario" },
|
|
12557
12752
|
required: true,
|
|
12558
12753
|
table: "users",
|
|
@@ -12563,7 +12758,7 @@ var init_users_entity = __esm({
|
|
|
12563
12758
|
labelField: "name",
|
|
12564
12759
|
meta: { searchable: true }
|
|
12565
12760
|
}),
|
|
12566
|
-
role_id:
|
|
12761
|
+
role_id: useSelectField10({
|
|
12567
12762
|
label: { en: "Role", es: "Rol" },
|
|
12568
12763
|
required: true,
|
|
12569
12764
|
table: "roles",
|
|
@@ -13507,7 +13702,7 @@ var init_users = __esm({
|
|
|
13507
13702
|
});
|
|
13508
13703
|
|
|
13509
13704
|
// src/modules/auth/auth.entity.ts
|
|
13510
|
-
import { useIdField as useIdField5, useTextField as
|
|
13705
|
+
import { useIdField as useIdField5, useTextField as useTextField10, useSelectField as useSelectField11, useDatetimeField as useDatetimeField4, useEmailField as useEmailField2, useMetadataField as useMetadataField3, useExpiresAtField } from "@gzl10/nexus-sdk/fields";
|
|
13511
13706
|
var refreshTokenEntity, authIdentitiesEntity;
|
|
13512
13707
|
var init_auth_entity = __esm({
|
|
13513
13708
|
"src/modules/auth/auth.entity.ts"() {
|
|
@@ -13522,7 +13717,7 @@ var init_auth_entity = __esm({
|
|
|
13522
13717
|
expose: false,
|
|
13523
13718
|
fields: {
|
|
13524
13719
|
id: useIdField5(),
|
|
13525
|
-
token:
|
|
13720
|
+
token: useTextField10({
|
|
13526
13721
|
label: { en: "Token", es: "Token" },
|
|
13527
13722
|
hidden: true,
|
|
13528
13723
|
size: 255,
|
|
@@ -13549,14 +13744,14 @@ var init_auth_entity = __esm({
|
|
|
13549
13744
|
nullable: true,
|
|
13550
13745
|
meta: { sortable: true }
|
|
13551
13746
|
}),
|
|
13552
|
-
device_id:
|
|
13747
|
+
device_id: useTextField10({
|
|
13553
13748
|
label: { en: "Device ID", es: "ID de dispositivo" },
|
|
13554
13749
|
size: 64,
|
|
13555
13750
|
index: true,
|
|
13556
13751
|
nullable: true,
|
|
13557
13752
|
meta: { searchable: true }
|
|
13558
13753
|
}),
|
|
13559
|
-
device_name:
|
|
13754
|
+
device_name: useTextField10({
|
|
13560
13755
|
label: { en: "Device", es: "Dispositivo" },
|
|
13561
13756
|
size: 100,
|
|
13562
13757
|
nullable: true,
|
|
@@ -13588,7 +13783,7 @@ var init_auth_entity = __esm({
|
|
|
13588
13783
|
order: 5,
|
|
13589
13784
|
fields: {
|
|
13590
13785
|
id: useIdField5(),
|
|
13591
|
-
user_id:
|
|
13786
|
+
user_id: useSelectField11({
|
|
13592
13787
|
label: { en: "User", es: "Usuario" },
|
|
13593
13788
|
table: "users",
|
|
13594
13789
|
column: "id",
|
|
@@ -13600,7 +13795,7 @@ var init_auth_entity = __esm({
|
|
|
13600
13795
|
labelField: "name",
|
|
13601
13796
|
meta: { searchable: true }
|
|
13602
13797
|
}),
|
|
13603
|
-
provider:
|
|
13798
|
+
provider: useTextField10({
|
|
13604
13799
|
label: { en: "Provider", es: "Proveedor" },
|
|
13605
13800
|
required: true,
|
|
13606
13801
|
size: 50,
|
|
@@ -13609,7 +13804,7 @@ var init_auth_entity = __esm({
|
|
|
13609
13804
|
hint: { en: "e.g. pocketid, google, microsoft", es: "ej. pocketid, google, microsoft" },
|
|
13610
13805
|
meta: { sortable: true, searchable: true }
|
|
13611
13806
|
}),
|
|
13612
|
-
provider_user_id:
|
|
13807
|
+
provider_user_id: useTextField10({
|
|
13613
13808
|
label: { en: "Provider User ID", es: "ID de usuario del proveedor" },
|
|
13614
13809
|
required: true,
|
|
13615
13810
|
size: 255,
|
|
@@ -13904,7 +14099,7 @@ var init_auth_middleware = __esm({
|
|
|
13904
14099
|
});
|
|
13905
14100
|
|
|
13906
14101
|
// src/modules/auth/auth.pat.entity.ts
|
|
13907
|
-
import { useIdField as useIdField6, useTextField as
|
|
14102
|
+
import { useIdField as useIdField6, useTextField as useTextField11, useSelectField as useSelectField12, useDatetimeField as useDatetimeField5, useExpiresAtField as useExpiresAtField2 } from "@gzl10/nexus-sdk/fields";
|
|
13908
14103
|
var personalTokenEntity;
|
|
13909
14104
|
var init_auth_pat_entity = __esm({
|
|
13910
14105
|
"src/modules/auth/auth.pat.entity.ts"() {
|
|
@@ -13921,7 +14116,7 @@ var init_auth_pat_entity = __esm({
|
|
|
13921
14116
|
routePrefix: "/personal-tokens",
|
|
13922
14117
|
fields: {
|
|
13923
14118
|
id: useIdField6(),
|
|
13924
|
-
user_id:
|
|
14119
|
+
user_id: useSelectField12({
|
|
13925
14120
|
label: { en: "User", es: "Usuario" },
|
|
13926
14121
|
table: "users",
|
|
13927
14122
|
column: "id",
|
|
@@ -13933,7 +14128,7 @@ var init_auth_pat_entity = __esm({
|
|
|
13933
14128
|
labelField: "name",
|
|
13934
14129
|
meta: { searchable: true }
|
|
13935
14130
|
}),
|
|
13936
|
-
name:
|
|
14131
|
+
name: useTextField11({
|
|
13937
14132
|
label: { en: "Name", es: "Nombre" },
|
|
13938
14133
|
required: true,
|
|
13939
14134
|
size: 100,
|
|
@@ -13941,14 +14136,14 @@ var init_auth_pat_entity = __esm({
|
|
|
13941
14136
|
hint: { en: "Descriptive name for this token", es: "Nombre descriptivo para este token" },
|
|
13942
14137
|
meta: { searchable: true }
|
|
13943
14138
|
}),
|
|
13944
|
-
token_prefix:
|
|
14139
|
+
token_prefix: useTextField11({
|
|
13945
14140
|
label: { en: "Token", es: "Token" },
|
|
13946
14141
|
size: 20,
|
|
13947
14142
|
disabled: true,
|
|
13948
14143
|
nullable: false,
|
|
13949
14144
|
hint: { en: "Partial token for identification", es: "Token parcial para identificaci\xF3n" }
|
|
13950
14145
|
}),
|
|
13951
|
-
token_hash:
|
|
14146
|
+
token_hash: useTextField11({
|
|
13952
14147
|
label: { en: "Token Hash", es: "Hash del token" },
|
|
13953
14148
|
size: 64,
|
|
13954
14149
|
hidden: true,
|
|
@@ -13956,7 +14151,7 @@ var init_auth_pat_entity = __esm({
|
|
|
13956
14151
|
unique: true,
|
|
13957
14152
|
meta: { exportable: false }
|
|
13958
14153
|
}),
|
|
13959
|
-
scope:
|
|
14154
|
+
scope: useSelectField12({
|
|
13960
14155
|
label: { en: "Permission", es: "Permiso" },
|
|
13961
14156
|
required: true,
|
|
13962
14157
|
options: [
|
|
@@ -15712,7 +15907,7 @@ var init_mail_service = __esm({
|
|
|
15712
15907
|
});
|
|
15713
15908
|
|
|
15714
15909
|
// src/modules/mail/mail.entity.ts
|
|
15715
|
-
import { useIdField as useIdField7, useTextField as
|
|
15910
|
+
import { useIdField as useIdField7, useTextField as useTextField12, useSelectField as useSelectField13, useNumberField as useNumberField5, useSwitchField as useSwitchField4, useEmailField as useEmailField3, usePasswordField as usePasswordField2, useTextareaField as useTextareaField3, useTagsField as useTagsField2, useDatetimeField as useDatetimeField6 } from "@gzl10/nexus-sdk/fields";
|
|
15716
15911
|
import nodemailer2 from "nodemailer";
|
|
15717
15912
|
async function getMailConfigFromDB(ctx) {
|
|
15718
15913
|
const configService = ctx.services["config"];
|
|
@@ -15775,7 +15970,7 @@ var init_mail_entity = __esm({
|
|
|
15775
15970
|
},
|
|
15776
15971
|
fields: {
|
|
15777
15972
|
id: useIdField7(),
|
|
15778
|
-
host:
|
|
15973
|
+
host: useTextField12({
|
|
15779
15974
|
label: { en: "SMTP Host", es: "Host SMTP" },
|
|
15780
15975
|
size: 255,
|
|
15781
15976
|
nullable: false,
|
|
@@ -15795,7 +15990,7 @@ var init_mail_entity = __esm({
|
|
|
15795
15990
|
nullable: false,
|
|
15796
15991
|
hint: { en: "Default: SMTP_FROM env var", es: "Por defecto: variable SMTP_FROM" }
|
|
15797
15992
|
}),
|
|
15798
|
-
auth_user:
|
|
15993
|
+
auth_user: useTextField12({
|
|
15799
15994
|
label: { en: "Auth User", es: "Usuario de autenticaci\xF3n" },
|
|
15800
15995
|
size: 255,
|
|
15801
15996
|
nullable: true,
|
|
@@ -15827,12 +16022,12 @@ var init_mail_entity = __esm({
|
|
|
15827
16022
|
required: true,
|
|
15828
16023
|
validation: { format: "email" }
|
|
15829
16024
|
}),
|
|
15830
|
-
subject:
|
|
16025
|
+
subject: useTextField12({
|
|
15831
16026
|
label: { en: "Subject", es: "Asunto" },
|
|
15832
16027
|
required: true,
|
|
15833
16028
|
validation: { min: 1, max: 255 }
|
|
15834
16029
|
}),
|
|
15835
|
-
title:
|
|
16030
|
+
title: useTextField12({
|
|
15836
16031
|
label: { en: "Title", es: "T\xEDtulo" },
|
|
15837
16032
|
hint: { en: "Large title in email header", es: "T\xEDtulo grande en la cabecera del correo" }
|
|
15838
16033
|
}),
|
|
@@ -15976,20 +16171,20 @@ var init_mail_entity = __esm({
|
|
|
15976
16171
|
nullable: false,
|
|
15977
16172
|
meta: { sortable: true }
|
|
15978
16173
|
}),
|
|
15979
|
-
to:
|
|
16174
|
+
to: useTextField12({
|
|
15980
16175
|
label: { en: "Recipient(s)", es: "Destinatario(s)" },
|
|
15981
16176
|
size: 1e3,
|
|
15982
16177
|
nullable: false,
|
|
15983
16178
|
meta: { searchable: true }
|
|
15984
16179
|
}),
|
|
15985
|
-
subject:
|
|
16180
|
+
subject: useTextField12({
|
|
15986
16181
|
label: { en: "Subject", es: "Asunto" },
|
|
15987
16182
|
size: 255,
|
|
15988
16183
|
nullable: false,
|
|
15989
16184
|
meta: { searchable: true, sortable: true }
|
|
15990
16185
|
}),
|
|
15991
16186
|
status: {
|
|
15992
|
-
...
|
|
16187
|
+
...useSelectField13({
|
|
15993
16188
|
label: { en: "Status", es: "Estado" },
|
|
15994
16189
|
options: [
|
|
15995
16190
|
{ value: "pending", label: { en: "Pending", es: "Pendiente" } },
|
|
@@ -16003,7 +16198,7 @@ var init_mail_entity = __esm({
|
|
|
16003
16198
|
}),
|
|
16004
16199
|
validation: { enum: ["pending", "sent", "failed", "bounced"] }
|
|
16005
16200
|
},
|
|
16006
|
-
message_id:
|
|
16201
|
+
message_id: useTextField12({
|
|
16007
16202
|
label: { en: "Message ID", es: "ID de mensaje" },
|
|
16008
16203
|
hidden: true,
|
|
16009
16204
|
size: 255,
|
|
@@ -16013,7 +16208,7 @@ var init_mail_entity = __esm({
|
|
|
16013
16208
|
label: { en: "Error", es: "Error" },
|
|
16014
16209
|
nullable: true
|
|
16015
16210
|
}),
|
|
16016
|
-
sent_by:
|
|
16211
|
+
sent_by: useSelectField13({
|
|
16017
16212
|
label: { en: "Sent by", es: "Enviado por" },
|
|
16018
16213
|
table: "users",
|
|
16019
16214
|
column: "id",
|
|
@@ -16619,7 +16814,7 @@ var init_toggle_plugin_action = __esm({
|
|
|
16619
16814
|
});
|
|
16620
16815
|
|
|
16621
16816
|
// src/modules/plugins/plugins.entity.ts
|
|
16622
|
-
import { useTextField as
|
|
16817
|
+
import { useTextField as useTextField13, useSelectField as useSelectField14, useCheckboxField as useCheckboxField5 } from "@gzl10/nexus-sdk/fields";
|
|
16623
16818
|
import { OFFICIAL_PLUGINS } from "@gzl10/nexus-sdk";
|
|
16624
16819
|
var allowPluginManagement, pluginsEntity;
|
|
16625
16820
|
var init_plugins_entity = __esm({
|
|
@@ -16635,33 +16830,33 @@ var init_plugins_entity = __esm({
|
|
|
16635
16830
|
label: "Plugins",
|
|
16636
16831
|
icon: "mdi:puzzle",
|
|
16637
16832
|
labelField: "code",
|
|
16638
|
-
routePrefix: "/
|
|
16833
|
+
routePrefix: "/",
|
|
16639
16834
|
defaultSort: { field: "name", order: "asc" },
|
|
16640
16835
|
fields: {
|
|
16641
|
-
name:
|
|
16836
|
+
name: useTextField13({
|
|
16642
16837
|
label: { en: "Name", es: "Nombre" },
|
|
16643
16838
|
size: 50,
|
|
16644
16839
|
nullable: false,
|
|
16645
16840
|
meta: { sortable: true, searchable: true }
|
|
16646
16841
|
}),
|
|
16647
|
-
code:
|
|
16842
|
+
code: useTextField13({
|
|
16648
16843
|
label: { en: "Code", es: "C\xF3digo" },
|
|
16649
16844
|
size: 10,
|
|
16650
16845
|
nullable: false,
|
|
16651
16846
|
meta: { sortable: true }
|
|
16652
16847
|
}),
|
|
16653
|
-
label:
|
|
16848
|
+
label: useTextField13({
|
|
16654
16849
|
label: { en: "Label", es: "Etiqueta" },
|
|
16655
16850
|
size: 100,
|
|
16656
16851
|
nullable: false,
|
|
16657
16852
|
meta: { sortable: true }
|
|
16658
16853
|
}),
|
|
16659
|
-
version:
|
|
16854
|
+
version: useTextField13({
|
|
16660
16855
|
label: { en: "Version", es: "Versi\xF3n" },
|
|
16661
16856
|
size: 20,
|
|
16662
16857
|
nullable: false
|
|
16663
16858
|
}),
|
|
16664
|
-
category:
|
|
16859
|
+
category: useSelectField14({
|
|
16665
16860
|
label: { en: "Category", es: "Categor\xEDa" },
|
|
16666
16861
|
options: [
|
|
16667
16862
|
{ value: "content", label: { en: "Content", es: "Contenido" } },
|
|
@@ -16802,8 +16997,8 @@ var init_plugins = __esm({
|
|
|
16802
16997
|
// src/modules/audit/audit.entity.ts
|
|
16803
16998
|
import {
|
|
16804
16999
|
useIdField as useIdField8,
|
|
16805
|
-
useTextField as
|
|
16806
|
-
useSelectField as
|
|
17000
|
+
useTextField as useTextField14,
|
|
17001
|
+
useSelectField as useSelectField15,
|
|
16807
17002
|
useTextareaField as useTextareaField4,
|
|
16808
17003
|
useJsonField as useJsonField3,
|
|
16809
17004
|
useDatetimeField as useDatetimeField7,
|
|
@@ -16826,7 +17021,7 @@ var init_audit_entity = __esm({
|
|
|
16826
17021
|
fields: {
|
|
16827
17022
|
id: useIdField8(),
|
|
16828
17023
|
source: {
|
|
16829
|
-
...
|
|
17024
|
+
...useTextField14({
|
|
16830
17025
|
label: { en: "Source", es: "Origen" },
|
|
16831
17026
|
size: 100,
|
|
16832
17027
|
nullable: false,
|
|
@@ -16836,7 +17031,7 @@ var init_audit_entity = __esm({
|
|
|
16836
17031
|
validation: { min: 1, max: 100 }
|
|
16837
17032
|
},
|
|
16838
17033
|
action: {
|
|
16839
|
-
...
|
|
17034
|
+
...useTextField14({
|
|
16840
17035
|
label: { en: "Action", es: "Acci\xF3n" },
|
|
16841
17036
|
size: 100,
|
|
16842
17037
|
nullable: false,
|
|
@@ -16845,7 +17040,7 @@ var init_audit_entity = __esm({
|
|
|
16845
17040
|
}),
|
|
16846
17041
|
validation: { min: 1, max: 100 }
|
|
16847
17042
|
},
|
|
16848
|
-
actor_id:
|
|
17043
|
+
actor_id: useSelectField15({
|
|
16849
17044
|
label: { en: "Actor", es: "Actor" },
|
|
16850
17045
|
table: "users",
|
|
16851
17046
|
column: "id",
|
|
@@ -16862,20 +17057,20 @@ var init_audit_entity = __esm({
|
|
|
16862
17057
|
nullable: true,
|
|
16863
17058
|
meta: { searchable: true }
|
|
16864
17059
|
}),
|
|
16865
|
-
resource_type:
|
|
17060
|
+
resource_type: useTextField14({
|
|
16866
17061
|
label: { en: "Resource Type", es: "Tipo de recurso" },
|
|
16867
17062
|
size: 100,
|
|
16868
17063
|
nullable: true,
|
|
16869
17064
|
index: true,
|
|
16870
17065
|
meta: { searchable: true }
|
|
16871
17066
|
}),
|
|
16872
|
-
resource_id:
|
|
17067
|
+
resource_id: useTextField14({
|
|
16873
17068
|
label: { en: "Resource ID", es: "ID del recurso" },
|
|
16874
17069
|
size: 100,
|
|
16875
17070
|
nullable: true,
|
|
16876
17071
|
meta: { searchable: true }
|
|
16877
17072
|
}),
|
|
16878
|
-
ip_address:
|
|
17073
|
+
ip_address: useTextField14({
|
|
16879
17074
|
label: { en: "IP Address", es: "Direcci\xF3n IP" },
|
|
16880
17075
|
size: 45,
|
|
16881
17076
|
nullable: true,
|
|
@@ -17048,12 +17243,12 @@ var init_loader = __esm({
|
|
|
17048
17243
|
"src/engine/loader.ts"() {
|
|
17049
17244
|
"use strict";
|
|
17050
17245
|
init_registry();
|
|
17051
|
-
|
|
17246
|
+
init_definition_extractors();
|
|
17052
17247
|
init_modules();
|
|
17053
17248
|
}
|
|
17054
17249
|
});
|
|
17055
17250
|
|
|
17056
|
-
// src/engine/
|
|
17251
|
+
// src/engine/subject-extractor.ts
|
|
17057
17252
|
function getModuleSubjects(mod) {
|
|
17058
17253
|
const subjects = /* @__PURE__ */ new Set();
|
|
17059
17254
|
for (const def of mod.definitions ?? []) {
|
|
@@ -17062,10 +17257,10 @@ function getModuleSubjects(mod) {
|
|
|
17062
17257
|
}
|
|
17063
17258
|
return [...subjects];
|
|
17064
17259
|
}
|
|
17065
|
-
var
|
|
17066
|
-
"src/engine/
|
|
17260
|
+
var init_subject_extractor = __esm({
|
|
17261
|
+
"src/engine/subject-extractor.ts"() {
|
|
17067
17262
|
"use strict";
|
|
17068
|
-
|
|
17263
|
+
init_definition_extractors();
|
|
17069
17264
|
}
|
|
17070
17265
|
});
|
|
17071
17266
|
|
|
@@ -17143,7 +17338,7 @@ function initSocketIO(httpServer, options) {
|
|
|
17143
17338
|
maxHttpBufferSize: 1e6
|
|
17144
17339
|
// 1MB - match Express json body limit
|
|
17145
17340
|
});
|
|
17146
|
-
logger.info({
|
|
17341
|
+
logger.info({ cors: corsOrigin }, "Socket.IO initialized");
|
|
17147
17342
|
io.use((socket, next) => {
|
|
17148
17343
|
const token = socket.handshake.auth?.["token"] || socket.handshake.query?.["token"];
|
|
17149
17344
|
if (token && typeof token === "string" && jwtSecret) {
|
|
@@ -17166,7 +17361,6 @@ function initSocketIO(httpServer, options) {
|
|
|
17166
17361
|
logger.warn({ code: err.code, message: err.message }, "Socket.IO connection error");
|
|
17167
17362
|
});
|
|
17168
17363
|
io.on("connection", handleConnection);
|
|
17169
|
-
logger.info("Socket.IO initialized");
|
|
17170
17364
|
nexusEvents.emitEvent("socket.initialized");
|
|
17171
17365
|
return io;
|
|
17172
17366
|
}
|
|
@@ -17629,6 +17823,7 @@ var init_error_codes = __esm({
|
|
|
17629
17823
|
DB_CONSTRAINT_UNIQUE: "DB_CONSTRAINT_UNIQUE",
|
|
17630
17824
|
DB_CONSTRAINT_FK: "DB_CONSTRAINT_FK",
|
|
17631
17825
|
DB_CONNECTION_ERROR: "DB_CONNECTION_ERROR",
|
|
17826
|
+
DATABASE_NOT_READY: "DATABASE_NOT_READY",
|
|
17632
17827
|
// System
|
|
17633
17828
|
SYSTEM_INTERNAL_ERROR: "SYSTEM_INTERNAL_ERROR"
|
|
17634
17829
|
};
|
|
@@ -17747,6 +17942,12 @@ var init_app_error = __esm({
|
|
|
17747
17942
|
|
|
17748
17943
|
// src/core/abilities/ability.factory.ts
|
|
17749
17944
|
import { AbilityBuilder, createMongoAbility } from "@casl/ability";
|
|
17945
|
+
function setSeedPermissions(perms) {
|
|
17946
|
+
seedPermissions = perms;
|
|
17947
|
+
}
|
|
17948
|
+
function clearSeedPermissions() {
|
|
17949
|
+
seedPermissions = null;
|
|
17950
|
+
}
|
|
17750
17951
|
function setCustomCaslRules(fn) {
|
|
17751
17952
|
customCaslRules = fn;
|
|
17752
17953
|
}
|
|
@@ -17804,16 +18005,28 @@ async function defineAbilityFor(user, roleNames) {
|
|
|
17804
18005
|
if (customCaslRules) {
|
|
17805
18006
|
await customCaslRules(user, { can, cannot });
|
|
17806
18007
|
}
|
|
18008
|
+
if (seedPermissions && !isSuperuser) {
|
|
18009
|
+
for (const roleName of roleNames) {
|
|
18010
|
+
const rolePerms = seedPermissions.get(roleName);
|
|
18011
|
+
if (!rolePerms) continue;
|
|
18012
|
+
for (const [subject2, actions] of rolePerms) {
|
|
18013
|
+
for (const action of actions) {
|
|
18014
|
+
can(action, subject2);
|
|
18015
|
+
}
|
|
18016
|
+
}
|
|
18017
|
+
}
|
|
18018
|
+
}
|
|
17807
18019
|
return build();
|
|
17808
18020
|
}
|
|
17809
18021
|
function packRules(ability) {
|
|
17810
18022
|
return ability.rules;
|
|
17811
18023
|
}
|
|
17812
|
-
var customCaslRules, entityDefinitionsRegistry, SUPERUSER_ROLES;
|
|
18024
|
+
var customCaslRules, seedPermissions, entityDefinitionsRegistry, SUPERUSER_ROLES;
|
|
17813
18025
|
var init_ability_factory = __esm({
|
|
17814
18026
|
"src/core/abilities/ability.factory.ts"() {
|
|
17815
18027
|
"use strict";
|
|
17816
18028
|
init_logger();
|
|
18029
|
+
seedPermissions = null;
|
|
17817
18030
|
entityDefinitionsRegistry = null;
|
|
17818
18031
|
SUPERUSER_ROLES = ["ADMIN", "OWNER"];
|
|
17819
18032
|
}
|
|
@@ -17918,7 +18131,7 @@ var init_env = __esm({
|
|
|
17918
18131
|
envSchema = z8.object({
|
|
17919
18132
|
NODE_ENV: z8.enum(["development", "production", "test"]).default("development"),
|
|
17920
18133
|
PORT: z8.coerce.number().default(3e3),
|
|
17921
|
-
CORS_ORIGIN: z8.string().default("
|
|
18134
|
+
CORS_ORIGIN: z8.string().default("*"),
|
|
17922
18135
|
BACKEND_URL: z8.string().optional(),
|
|
17923
18136
|
DATABASE_URL: z8.string().default("file:./dev.db"),
|
|
17924
18137
|
REDIS_URL: z8.string().url().optional(),
|
|
@@ -18366,7 +18579,7 @@ var init_sequence = __esm({
|
|
|
18366
18579
|
}
|
|
18367
18580
|
});
|
|
18368
18581
|
|
|
18369
|
-
// src/core/utils/
|
|
18582
|
+
// src/core/utils/safe-json.ts
|
|
18370
18583
|
function safeJsonParse(logger2, jsonString, fallback, context) {
|
|
18371
18584
|
try {
|
|
18372
18585
|
return JSON.parse(jsonString);
|
|
@@ -18375,8 +18588,8 @@ function safeJsonParse(logger2, jsonString, fallback, context) {
|
|
|
18375
18588
|
return fallback;
|
|
18376
18589
|
}
|
|
18377
18590
|
}
|
|
18378
|
-
var
|
|
18379
|
-
"src/core/utils/
|
|
18591
|
+
var init_safe_json = __esm({
|
|
18592
|
+
"src/core/utils/safe-json.ts"() {
|
|
18380
18593
|
"use strict";
|
|
18381
18594
|
}
|
|
18382
18595
|
});
|
|
@@ -18385,14 +18598,15 @@ var init_error_handler = __esm({
|
|
|
18385
18598
|
import express from "express";
|
|
18386
18599
|
import { resolve, join as join9 } from "path";
|
|
18387
18600
|
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
18388
|
-
function createServeSPA(app) {
|
|
18389
|
-
return (endpoint, distPath, options = {}) => {
|
|
18601
|
+
function createServeSPA(app, httpServer) {
|
|
18602
|
+
return async (endpoint, distPath, options = {}) => {
|
|
18390
18603
|
const {
|
|
18391
18604
|
maxAge = "1d",
|
|
18392
18605
|
etag = true,
|
|
18393
18606
|
immutable = false,
|
|
18394
18607
|
index = "index.html",
|
|
18395
|
-
absolute = false
|
|
18608
|
+
absolute = false,
|
|
18609
|
+
viteSrc
|
|
18396
18610
|
} = options;
|
|
18397
18611
|
if (endpoint === "/api" || endpoint.startsWith("/api/")) {
|
|
18398
18612
|
logger.error(`Cannot mount SPA on ${endpoint} - reserved for API routes`);
|
|
@@ -18403,58 +18617,117 @@ function createServeSPA(app) {
|
|
|
18403
18617
|
return;
|
|
18404
18618
|
}
|
|
18405
18619
|
registeredEndpoints.add(endpoint);
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
const projectPath2 = resolve(getProjectPath(), distPath);
|
|
18411
|
-
if (existsSync9(projectPath2)) {
|
|
18412
|
-
resolvedPath = projectPath2;
|
|
18620
|
+
if (env.NODE_ENV === "development" && viteSrc) {
|
|
18621
|
+
const srcPath = resolve(getProjectPath(), viteSrc);
|
|
18622
|
+
if (!existsSync9(srcPath)) {
|
|
18623
|
+
logger.warn({ endpoint, viteSrc, resolved: srcPath }, "Vite source not found \u2014 falling back to static");
|
|
18413
18624
|
} else {
|
|
18414
|
-
|
|
18625
|
+
const mounted = await mountViteDevMiddleware(app, endpoint, srcPath, httpServer);
|
|
18626
|
+
if (mounted) return;
|
|
18415
18627
|
}
|
|
18416
18628
|
}
|
|
18417
|
-
|
|
18418
|
-
|
|
18419
|
-
|
|
18629
|
+
mountStaticSPA(app, endpoint, distPath, { maxAge, etag, immutable, index, absolute });
|
|
18630
|
+
};
|
|
18631
|
+
}
|
|
18632
|
+
async function mountViteDevMiddleware(app, endpoint, srcPath, httpServer) {
|
|
18633
|
+
try {
|
|
18634
|
+
const vite = await import("vite");
|
|
18635
|
+
const apiUrl = env.BACKEND_URL ? `${env.BACKEND_URL}/api/v1` : "/api/v1";
|
|
18636
|
+
const server2 = await vite.createServer({
|
|
18637
|
+
root: srcPath,
|
|
18638
|
+
server: {
|
|
18639
|
+
middlewareMode: true,
|
|
18640
|
+
allowedHosts: true,
|
|
18641
|
+
hmr: httpServer ? { server: httpServer } : true
|
|
18642
|
+
},
|
|
18643
|
+
plugins: [{
|
|
18644
|
+
name: "nexus-config-inject",
|
|
18645
|
+
transformIndexHtml(html) {
|
|
18646
|
+
const config3 = JSON.stringify({ apiUrl });
|
|
18647
|
+
return html.replace("</head>", `<script>window.__NEXUS__=${config3}</script>
|
|
18648
|
+
</head>`);
|
|
18649
|
+
}
|
|
18650
|
+
}],
|
|
18651
|
+
appType: "spa",
|
|
18652
|
+
clearScreen: false
|
|
18653
|
+
});
|
|
18654
|
+
viteServers.push(server2);
|
|
18655
|
+
if (endpoint === "/") {
|
|
18656
|
+
app.use(server2.middlewares);
|
|
18657
|
+
} else {
|
|
18658
|
+
app.use(endpoint, server2.middlewares);
|
|
18420
18659
|
}
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
if (existsSync9(indexPath)) {
|
|
18428
|
-
const rawHtml = readFileSync5(indexPath, "utf-8");
|
|
18429
|
-
const apiUrl = env.BACKEND_URL ? `${env.BACKEND_URL}/api/v1` : "/api/v1";
|
|
18430
|
-
const nexusConfig = JSON.stringify({ apiUrl });
|
|
18431
|
-
injectedHtml = rawHtml.replace(
|
|
18432
|
-
"</head>",
|
|
18433
|
-
`<script>window.__NEXUS__=${nexusConfig}</script>
|
|
18434
|
-
</head>`
|
|
18435
|
-
);
|
|
18660
|
+
logger.info({ path: srcPath }, `Vite dev server mounted at ${endpoint} (HMR enabled)`);
|
|
18661
|
+
return true;
|
|
18662
|
+
} catch (err) {
|
|
18663
|
+
if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
|
|
18664
|
+
logger.warn(`vite not installed \u2014 falling back to static serving for ${endpoint}`);
|
|
18665
|
+
return false;
|
|
18436
18666
|
}
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18667
|
+
logger.error({ err }, `Failed to mount Vite dev server at ${endpoint}`);
|
|
18668
|
+
return false;
|
|
18669
|
+
}
|
|
18670
|
+
}
|
|
18671
|
+
function mountStaticSPA(app, endpoint, distPath, options) {
|
|
18672
|
+
const { maxAge, etag, immutable, index, absolute } = options;
|
|
18673
|
+
let resolvedPath;
|
|
18674
|
+
if (absolute) {
|
|
18675
|
+
resolvedPath = distPath;
|
|
18676
|
+
} else {
|
|
18677
|
+
const projectPath2 = resolve(getProjectPath(), distPath);
|
|
18678
|
+
if (existsSync9(projectPath2)) {
|
|
18679
|
+
resolvedPath = projectPath2;
|
|
18447
18680
|
} else {
|
|
18448
|
-
|
|
18449
|
-
app.get(`${endpoint}/{*splat}`, fallbackHandler);
|
|
18681
|
+
resolvedPath = resolve(getLibPath(), distPath);
|
|
18450
18682
|
}
|
|
18451
|
-
|
|
18683
|
+
}
|
|
18684
|
+
if (!existsSync9(resolvedPath)) {
|
|
18685
|
+
logger.warn({ endpoint, distPath, hint: "Build the frontend first" }, `SPA directory not found: ${resolvedPath}`);
|
|
18686
|
+
return;
|
|
18687
|
+
}
|
|
18688
|
+
const indexPath = join9(resolvedPath, index);
|
|
18689
|
+
if (!existsSync9(indexPath)) {
|
|
18690
|
+
logger.warn({ endpoint, index }, `Index file not found: ${indexPath}`);
|
|
18691
|
+
}
|
|
18692
|
+
app.use(endpoint, express.static(resolvedPath, { maxAge, etag, immutable }));
|
|
18693
|
+
let injectedHtml = "";
|
|
18694
|
+
if (existsSync9(indexPath)) {
|
|
18695
|
+
const rawHtml = readFileSync5(indexPath, "utf-8");
|
|
18696
|
+
const apiUrl = env.BACKEND_URL ? `${env.BACKEND_URL}/api/v1` : "/api/v1";
|
|
18697
|
+
const nexusConfig = JSON.stringify({ apiUrl });
|
|
18698
|
+
injectedHtml = rawHtml.replace(
|
|
18699
|
+
"</head>",
|
|
18700
|
+
`<script>window.__NEXUS__=${nexusConfig}</script>
|
|
18701
|
+
</head>`
|
|
18702
|
+
);
|
|
18703
|
+
}
|
|
18704
|
+
const fallbackHandler = (_req, res) => {
|
|
18705
|
+
if (!injectedHtml) {
|
|
18706
|
+
res.status(404).send("index.html not found");
|
|
18707
|
+
return;
|
|
18708
|
+
}
|
|
18709
|
+
res.set("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
18710
|
+
res.type("html").send(injectedHtml);
|
|
18452
18711
|
};
|
|
18712
|
+
if (endpoint === "/") {
|
|
18713
|
+
app.get("{*splat}", fallbackHandler);
|
|
18714
|
+
} else {
|
|
18715
|
+
app.get(endpoint, fallbackHandler);
|
|
18716
|
+
app.get(`${endpoint}/{*splat}`, fallbackHandler);
|
|
18717
|
+
}
|
|
18718
|
+
logger.info({ path: resolvedPath }, `SPA mounted at ${endpoint}`);
|
|
18453
18719
|
}
|
|
18454
|
-
function
|
|
18720
|
+
async function resetServeSPA() {
|
|
18721
|
+
for (const server2 of viteServers) {
|
|
18722
|
+
try {
|
|
18723
|
+
await server2.close();
|
|
18724
|
+
} catch {
|
|
18725
|
+
}
|
|
18726
|
+
}
|
|
18727
|
+
viteServers.length = 0;
|
|
18455
18728
|
registeredEndpoints.clear();
|
|
18456
18729
|
}
|
|
18457
|
-
var registeredEndpoints;
|
|
18730
|
+
var registeredEndpoints, viteServers;
|
|
18458
18731
|
var init_spa_handler = __esm({
|
|
18459
18732
|
"src/core/spa-handler.ts"() {
|
|
18460
18733
|
"use strict";
|
|
@@ -18462,6 +18735,7 @@ var init_spa_handler = __esm({
|
|
|
18462
18735
|
init_logger();
|
|
18463
18736
|
init_env();
|
|
18464
18737
|
registeredEndpoints = /* @__PURE__ */ new Set();
|
|
18738
|
+
viteServers = [];
|
|
18465
18739
|
}
|
|
18466
18740
|
});
|
|
18467
18741
|
|
|
@@ -19032,7 +19306,7 @@ var init_core = __esm({
|
|
|
19032
19306
|
init_id();
|
|
19033
19307
|
init_sequence();
|
|
19034
19308
|
init_paths();
|
|
19035
|
-
|
|
19309
|
+
init_safe_json();
|
|
19036
19310
|
init_spa_handler();
|
|
19037
19311
|
init_cache();
|
|
19038
19312
|
init_jwt();
|
|
@@ -19747,7 +20021,9 @@ var init_base_service = __esm({
|
|
|
19747
20021
|
const countResult = await qb.clone().count("* as count").first();
|
|
19748
20022
|
const total = Number(countResult?.count ?? 0);
|
|
19749
20023
|
qb = this.applySortingWithDefaults(qb, query);
|
|
19750
|
-
|
|
20024
|
+
if (limit > 0) {
|
|
20025
|
+
qb = qb.limit(limit).offset(offset);
|
|
20026
|
+
}
|
|
19751
20027
|
const rawItems = await qb;
|
|
19752
20028
|
const items = this.parseJsonFieldsFromArray(rawItems);
|
|
19753
20029
|
const processedItems = await this.afterFindAll(items);
|
|
@@ -19832,7 +20108,7 @@ var init_base_service = __esm({
|
|
|
19832
20108
|
});
|
|
19833
20109
|
}
|
|
19834
20110
|
const total = result.length;
|
|
19835
|
-
const paginatedItems = result.slice(offset, offset + limit);
|
|
20111
|
+
const paginatedItems = limit === 0 ? result : result.slice(offset, offset + limit);
|
|
19836
20112
|
return this.buildPaginatedResult(paginatedItems, total, page, limit);
|
|
19837
20113
|
}
|
|
19838
20114
|
/**
|
|
@@ -20087,14 +20363,14 @@ var init_base_service = __esm({
|
|
|
20087
20363
|
* Build paginated result from items and count
|
|
20088
20364
|
*/
|
|
20089
20365
|
buildPaginatedResult(items, total, page, limit) {
|
|
20090
|
-
const totalPages = Math.ceil(total / limit);
|
|
20366
|
+
const totalPages = limit === 0 ? 1 : Math.ceil(total / limit);
|
|
20091
20367
|
return {
|
|
20092
20368
|
items,
|
|
20093
20369
|
total,
|
|
20094
|
-
page,
|
|
20095
|
-
limit,
|
|
20370
|
+
page: limit === 0 ? 1 : page,
|
|
20371
|
+
limit: limit === 0 ? total : limit,
|
|
20096
20372
|
totalPages,
|
|
20097
|
-
hasNext: page < totalPages
|
|
20373
|
+
hasNext: limit === 0 ? false : page < totalPages
|
|
20098
20374
|
};
|
|
20099
20375
|
}
|
|
20100
20376
|
/**
|
|
@@ -20103,8 +20379,8 @@ var init_base_service = __esm({
|
|
|
20103
20379
|
getPagination(query) {
|
|
20104
20380
|
const maxLimit = query?.maxLimit ?? 100;
|
|
20105
20381
|
const page = Math.max(1, query?.page ?? 1);
|
|
20106
|
-
const limit = Math.min(maxLimit, Math.max(1, query?.limit ?? 20));
|
|
20107
|
-
const offset = (page - 1) * limit;
|
|
20382
|
+
const limit = query?.limit === 0 ? 0 : Math.min(maxLimit, Math.max(1, query?.limit ?? 20));
|
|
20383
|
+
const offset = limit === 0 ? 0 : (page - 1) * limit;
|
|
20108
20384
|
return { page, limit, offset };
|
|
20109
20385
|
}
|
|
20110
20386
|
/**
|
|
@@ -20124,10 +20400,31 @@ var init_base_service = __esm({
|
|
|
20124
20400
|
* Override in subclasses for entity-specific search
|
|
20125
20401
|
*/
|
|
20126
20402
|
applySearch(qb, search) {
|
|
20403
|
+
const searchTerm = `%${search}%`;
|
|
20404
|
+
const searchableFields = [];
|
|
20405
|
+
const fields = "fields" in this.definition ? this.definition.fields : {};
|
|
20406
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
20407
|
+
if (field.meta?.searchable) {
|
|
20408
|
+
searchableFields.push(name);
|
|
20409
|
+
}
|
|
20410
|
+
}
|
|
20127
20411
|
if ("labelField" in this.definition && this.definition.labelField) {
|
|
20128
|
-
const
|
|
20129
|
-
|
|
20412
|
+
const lf = this.definition.labelField;
|
|
20413
|
+
if (!searchableFields.includes(lf)) {
|
|
20414
|
+
searchableFields.unshift(lf);
|
|
20415
|
+
}
|
|
20130
20416
|
}
|
|
20417
|
+
if (searchableFields.length === 0) return qb;
|
|
20418
|
+
qb.where(function() {
|
|
20419
|
+
for (const fieldName of searchableFields) {
|
|
20420
|
+
const field = fields[fieldName];
|
|
20421
|
+
if (field?.db?.type === "json") {
|
|
20422
|
+
this.orWhereRaw(`CAST(?? AS TEXT) LIKE ?`, [fieldName, searchTerm]);
|
|
20423
|
+
} else {
|
|
20424
|
+
this.orWhere(fieldName, "like", searchTerm);
|
|
20425
|
+
}
|
|
20426
|
+
}
|
|
20427
|
+
});
|
|
20131
20428
|
return qb;
|
|
20132
20429
|
}
|
|
20133
20430
|
/**
|
|
@@ -21751,7 +22048,8 @@ function createEntityController(service, definition, ctx) {
|
|
|
21751
22048
|
async list(req, res) {
|
|
21752
22049
|
checkPermission(req, "read");
|
|
21753
22050
|
const page = Math.max(1, parseInt(req.query["page"]) || 1);
|
|
21754
|
-
const
|
|
22051
|
+
const rawLimit = parseInt(req.query["limit"]);
|
|
22052
|
+
const limit = rawLimit === 0 ? 0 : Math.min(100, Math.max(1, rawLimit || 20));
|
|
21755
22053
|
let filters;
|
|
21756
22054
|
if (req.query["filters"]) {
|
|
21757
22055
|
filters = parseFilters(req.query["filters"], ctx.core.errors);
|
|
@@ -23217,17 +23515,18 @@ async function createModuleRouters(ctx, definitions, modulePrefix) {
|
|
|
23217
23515
|
const runtime = await createEntityRuntimeAsync(ctx, definition);
|
|
23218
23516
|
const route = inferEntityRoutePath(definition);
|
|
23219
23517
|
const entityLabel = resolveLocalized7(definition.label, "en");
|
|
23220
|
-
|
|
23518
|
+
const isExposed = !("expose" in definition && definition.expose === false);
|
|
23519
|
+
if (isExposed && modulePrefix && route === modulePrefix) {
|
|
23221
23520
|
ctx.core.logger.warn(
|
|
23222
23521
|
`Entity "${entityLabel}" inferred route "${route}" duplicates module prefix \u2014 add routePrefix to the entity definition to fix`
|
|
23223
23522
|
);
|
|
23224
23523
|
}
|
|
23225
|
-
if (routeMap.has(route)) {
|
|
23524
|
+
if (isExposed && routeMap.has(route)) {
|
|
23226
23525
|
ctx.core.logger.warn(
|
|
23227
23526
|
`Entity "${entityLabel}" route "${route}" collides with "${routeMap.get(route)}" in the same module`
|
|
23228
23527
|
);
|
|
23229
23528
|
}
|
|
23230
|
-
routeMap.set(route, entityLabel);
|
|
23529
|
+
if (isExposed) routeMap.set(route, entityLabel);
|
|
23231
23530
|
router.use(route, runtime.router);
|
|
23232
23531
|
const key = getServiceKey(definition);
|
|
23233
23532
|
if (ctx.services.has(key)) {
|
|
@@ -23443,7 +23742,7 @@ var init_runtime = __esm({
|
|
|
23443
23742
|
}
|
|
23444
23743
|
});
|
|
23445
23744
|
|
|
23446
|
-
// src/db/
|
|
23745
|
+
// src/db/seed-runner.ts
|
|
23447
23746
|
import { existsSync as existsSync10 } from "fs";
|
|
23448
23747
|
import { join as join10 } from "path";
|
|
23449
23748
|
import { pathToFileURL } from "url";
|
|
@@ -23511,8 +23810,8 @@ function hasSeedData(seed5) {
|
|
|
23511
23810
|
if (!Array.isArray(seed5) && "source" in seed5 && seed5.source === "url") return true;
|
|
23512
23811
|
return Array.isArray(seed5) && seed5.length > 0;
|
|
23513
23812
|
}
|
|
23514
|
-
var
|
|
23515
|
-
"src/db/
|
|
23813
|
+
var init_seed_runner = __esm({
|
|
23814
|
+
"src/db/seed-runner.ts"() {
|
|
23516
23815
|
"use strict";
|
|
23517
23816
|
init_runtime();
|
|
23518
23817
|
init_paths();
|
|
@@ -23584,15 +23883,6 @@ var init_ensure_system_tables = __esm({
|
|
|
23584
23883
|
}
|
|
23585
23884
|
});
|
|
23586
23885
|
|
|
23587
|
-
// src/cli/shared.ts
|
|
23588
|
-
import { consola } from "consola";
|
|
23589
|
-
var init_shared = __esm({
|
|
23590
|
-
"src/cli/shared.ts"() {
|
|
23591
|
-
"use strict";
|
|
23592
|
-
init_logger();
|
|
23593
|
-
}
|
|
23594
|
-
});
|
|
23595
|
-
|
|
23596
23886
|
// src/db/migration-sources.ts
|
|
23597
23887
|
function buildMigrationSources() {
|
|
23598
23888
|
const sources = [
|
|
@@ -23612,10 +23902,8 @@ function buildMigrationSources() {
|
|
|
23612
23902
|
var init_migration_sources = __esm({
|
|
23613
23903
|
"src/db/migration-sources.ts"() {
|
|
23614
23904
|
"use strict";
|
|
23615
|
-
init_shared();
|
|
23616
23905
|
init_paths();
|
|
23617
|
-
|
|
23618
|
-
init_store();
|
|
23906
|
+
init_module_store();
|
|
23619
23907
|
}
|
|
23620
23908
|
});
|
|
23621
23909
|
|
|
@@ -23948,7 +24236,7 @@ async function runMigrations(knexInstance, sources) {
|
|
|
23948
24236
|
const executedMigrations = await knex3("_nexus_migrations").where({ status: "completed" }).select("name").then((rows) => new Set(rows.map((r) => r.name)));
|
|
23949
24237
|
const pendingMigrations = migrationFiles.filter((m) => !executedMigrations.has(m.name));
|
|
23950
24238
|
if (pendingMigrations.length === 0) {
|
|
23951
|
-
logger.
|
|
24239
|
+
logger.debug("No pending migrations");
|
|
23952
24240
|
return;
|
|
23953
24241
|
}
|
|
23954
24242
|
const batch = await getNextBatch(knex3);
|
|
@@ -24348,6 +24636,27 @@ var init_migration_helpers = __esm({
|
|
|
24348
24636
|
import path2 from "path";
|
|
24349
24637
|
import fs2 from "fs/promises";
|
|
24350
24638
|
import { readFileSync as readFileSync6, mkdirSync as mkdirSync5, realpathSync } from "fs";
|
|
24639
|
+
function getColumnIndexBytes(field) {
|
|
24640
|
+
if (!field?.db) return 255 * MYSQL_BYTES_PER_CHAR;
|
|
24641
|
+
const size = field.db.size ?? 255;
|
|
24642
|
+
if (field.db.type === "text") return 0;
|
|
24643
|
+
if (field.db.type === "string") return size * MYSQL_BYTES_PER_CHAR;
|
|
24644
|
+
if (field.db.type === "integer") return 4;
|
|
24645
|
+
if (field.db.type === "boolean") return 1;
|
|
24646
|
+
if (field.db.type === "datetime" || field.db.type === "date") return 8;
|
|
24647
|
+
if (field.db.type === "uuid") return 16;
|
|
24648
|
+
return size * MYSQL_BYTES_PER_CHAR;
|
|
24649
|
+
}
|
|
24650
|
+
function warnIfIndexExceedsMySQLLimit(table, columns, unique, fields) {
|
|
24651
|
+
if (!fields) return;
|
|
24652
|
+
const totalBytes = columns.reduce((sum, col) => sum + getColumnIndexBytes(fields[col]), 0);
|
|
24653
|
+
if (totalBytes > MYSQL_MAX_INDEX_BYTES) {
|
|
24654
|
+
const indexType = unique ? "UNIQUE" : "INDEX";
|
|
24655
|
+
logger.warn(
|
|
24656
|
+
`${indexType} on ${table}(${columns.join(", ")}) requires ${totalBytes} bytes \u2014 exceeds MySQL utf8mb4 limit of ${MYSQL_MAX_INDEX_BYTES} bytes. Reduce column sizes or restructure the index for MySQL compatibility.`
|
|
24657
|
+
);
|
|
24658
|
+
}
|
|
24659
|
+
}
|
|
24351
24660
|
async function detectSchemaDrift(knexInstance) {
|
|
24352
24661
|
const knex3 = knexInstance ?? getDb();
|
|
24353
24662
|
const entities = getAllPersistentEntities();
|
|
@@ -24455,6 +24764,7 @@ function computeSchemaDiff(entities, currentSchema, options) {
|
|
|
24455
24764
|
for (const idx of entityIndexes) {
|
|
24456
24765
|
const key = normalizeKey(idx.columns, !!idx.unique);
|
|
24457
24766
|
if (!currentKeys.has(key)) {
|
|
24767
|
+
warnIfIndexExceedsMySQLLimit(tableName, idx.columns, !!idx.unique, entity.fields);
|
|
24458
24768
|
diff.newIndexes.push({ columns: idx.columns, unique: !!idx.unique });
|
|
24459
24769
|
}
|
|
24460
24770
|
}
|
|
@@ -24626,7 +24936,7 @@ function formatDriftMessage(drift) {
|
|
|
24626
24936
|
lines.push('Run "pnpm migrate:dev" to generate and apply migrations.');
|
|
24627
24937
|
return lines.join("\n");
|
|
24628
24938
|
}
|
|
24629
|
-
var PERSISTENT_TYPES;
|
|
24939
|
+
var MYSQL_MAX_INDEX_BYTES, MYSQL_BYTES_PER_CHAR, PERSISTENT_TYPES;
|
|
24630
24940
|
var init_migration_generator = __esm({
|
|
24631
24941
|
"src/db/migration-generator.ts"() {
|
|
24632
24942
|
"use strict";
|
|
@@ -24635,9 +24945,11 @@ var init_migration_generator = __esm({
|
|
|
24635
24945
|
init_paths();
|
|
24636
24946
|
init_schema_reader();
|
|
24637
24947
|
init_engine();
|
|
24638
|
-
|
|
24948
|
+
init_module_queries();
|
|
24639
24949
|
init_migration_helpers();
|
|
24640
|
-
|
|
24950
|
+
init_module_store();
|
|
24951
|
+
MYSQL_MAX_INDEX_BYTES = 3072;
|
|
24952
|
+
MYSQL_BYTES_PER_CHAR = 4;
|
|
24641
24953
|
PERSISTENT_TYPES = /* @__PURE__ */ new Set([
|
|
24642
24954
|
"collection",
|
|
24643
24955
|
"tree",
|
|
@@ -24868,6 +25180,10 @@ function handleDbError(err) {
|
|
|
24868
25180
|
{ path: "foreignKey", message: "Foreign key constraint violation" }
|
|
24869
25181
|
]);
|
|
24870
25182
|
}
|
|
25183
|
+
if (code === "42P01" || code === "ER_NO_SUCH_TABLE" || dbErr.errno === 1146 || msg.includes("no such table")) {
|
|
25184
|
+
logger.error({ err }, "Database table not found \u2014 database may need migration or was wiped");
|
|
25185
|
+
throw new AppError({ code: ErrorCodes.DATABASE_NOT_READY, message: "Database not ready" }, 503);
|
|
25186
|
+
}
|
|
24871
25187
|
logger.error({ err }, "Unexpected database error");
|
|
24872
25188
|
throw new AppError({ code: ErrorCodes.SYSTEM_INTERNAL_ERROR, message: "Internal database error" }, 500);
|
|
24873
25189
|
}
|
|
@@ -26211,7 +26527,7 @@ var init_db = __esm({
|
|
|
26211
26527
|
init_schema_helpers();
|
|
26212
26528
|
init_sql_utils();
|
|
26213
26529
|
init_sqlite_compat();
|
|
26214
|
-
|
|
26530
|
+
init_seed_runner();
|
|
26215
26531
|
init_ensure_system_tables();
|
|
26216
26532
|
init_migration_sources();
|
|
26217
26533
|
init_migration_runner();
|
|
@@ -26475,8 +26791,11 @@ var init_events_api = __esm({
|
|
|
26475
26791
|
|
|
26476
26792
|
// src/engine/context.ts
|
|
26477
26793
|
import { ForbiddenError as CASLForbiddenError3, subject } from "@casl/ability";
|
|
26478
|
-
import { DEFAULT_TENANT_ID as DEFAULT_TENANT_ID2 } from "@gzl10/nexus-sdk";
|
|
26794
|
+
import { DEFAULT_TENANT_ID as DEFAULT_TENANT_ID2, DEFAULT_LOCALES } from "@gzl10/nexus-sdk";
|
|
26479
26795
|
import { Redis as Redis2 } from "ioredis";
|
|
26796
|
+
function setLocales(locales) {
|
|
26797
|
+
platformLocales = locales;
|
|
26798
|
+
}
|
|
26480
26799
|
function getSharedCacheManager() {
|
|
26481
26800
|
if (!sharedCacheManager) {
|
|
26482
26801
|
const redisUrl = env.REDIS_URL;
|
|
@@ -26552,7 +26871,7 @@ function createModuleContext() {
|
|
|
26552
26871
|
const defaultAdapter = createKnexAdapter(knex3);
|
|
26553
26872
|
const defaultSchemaAdapter = createKnexSchemaAdapter(knex3);
|
|
26554
26873
|
adaptersRegistry["temp"] = { data: getSharedTempAdapter() };
|
|
26555
|
-
logger.
|
|
26874
|
+
logger.trace(env.REDIS_URL ? "Temp adapter: Redis (shared)" : "Temp adapter: InMemory (shared)");
|
|
26556
26875
|
const middleware = {
|
|
26557
26876
|
validate,
|
|
26558
26877
|
rateLimit: createRateLimit,
|
|
@@ -26660,7 +26979,9 @@ function createModuleContext() {
|
|
|
26660
26979
|
throw new Error(`Knex connection for adapter "${adapter}" not found. Available: ${Object.keys(knexConnections).join(", ")}`);
|
|
26661
26980
|
}
|
|
26662
26981
|
return conn;
|
|
26663
|
-
}
|
|
26982
|
+
},
|
|
26983
|
+
// Placeholder — bound after ctx construction (needs full ModuleContext)
|
|
26984
|
+
seedModule: null
|
|
26664
26985
|
};
|
|
26665
26986
|
const configContext = {
|
|
26666
26987
|
env,
|
|
@@ -26753,7 +27074,8 @@ function createModuleContext() {
|
|
|
26753
27074
|
adapters: adaptersContext,
|
|
26754
27075
|
// Root-level shortcuts for frequently used utilities
|
|
26755
27076
|
events: createEventsApi(nexusEvents, logger),
|
|
26756
|
-
createRouter: () => createRouter()
|
|
27077
|
+
createRouter: () => createRouter(),
|
|
27078
|
+
locales: platformLocales
|
|
26757
27079
|
};
|
|
26758
27080
|
servicesRegistry["cacheManager"] = getSharedCacheManager();
|
|
26759
27081
|
ctx.runtime = {
|
|
@@ -26762,9 +27084,10 @@ function createModuleContext() {
|
|
|
26762
27084
|
createEntityController: (service, def) => createEntityController(service, def, ctx),
|
|
26763
27085
|
createEntityRouter: (controller, def) => createEntityRouter(controller, def, ctx)
|
|
26764
27086
|
};
|
|
27087
|
+
ctx.db.seedModule = (mod) => runModuleSeed(mod, ctx);
|
|
26765
27088
|
return ctx;
|
|
26766
27089
|
}
|
|
26767
|
-
var sharedCacheManager, sharedTempAdapter;
|
|
27090
|
+
var platformLocales, sharedCacheManager, sharedTempAdapter;
|
|
26768
27091
|
var init_context = __esm({
|
|
26769
27092
|
"src/engine/context.ts"() {
|
|
26770
27093
|
"use strict";
|
|
@@ -26777,7 +27100,9 @@ var init_context = __esm({
|
|
|
26777
27100
|
init_plugin_ops();
|
|
26778
27101
|
init_load_config();
|
|
26779
27102
|
init_events_api();
|
|
27103
|
+
init_seed_runner();
|
|
26780
27104
|
init_cache_manager();
|
|
27105
|
+
platformLocales = DEFAULT_LOCALES;
|
|
26781
27106
|
sharedCacheManager = null;
|
|
26782
27107
|
sharedTempAdapter = null;
|
|
26783
27108
|
}
|
|
@@ -26788,11 +27113,11 @@ var init_engine = __esm({
|
|
|
26788
27113
|
"src/engine/index.ts"() {
|
|
26789
27114
|
"use strict";
|
|
26790
27115
|
init_registry();
|
|
26791
|
-
|
|
27116
|
+
init_module_queries();
|
|
26792
27117
|
init_loader();
|
|
26793
|
-
|
|
26794
|
-
|
|
26795
|
-
|
|
27118
|
+
init_module_store();
|
|
27119
|
+
init_subject_extractor();
|
|
27120
|
+
init_definition_extractors();
|
|
26796
27121
|
init_context();
|
|
26797
27122
|
}
|
|
26798
27123
|
});
|
|
@@ -27141,6 +27466,33 @@ async function setupModuleRoutes(app) {
|
|
|
27141
27466
|
}
|
|
27142
27467
|
}
|
|
27143
27468
|
const caslRegistry = /* @__PURE__ */ new Map();
|
|
27469
|
+
function mergeActionPermissions(existing, incoming) {
|
|
27470
|
+
const merged = { ...existing };
|
|
27471
|
+
for (const [role, perm] of Object.entries(incoming)) {
|
|
27472
|
+
if (!merged[role]) {
|
|
27473
|
+
merged[role] = perm;
|
|
27474
|
+
} else {
|
|
27475
|
+
const existingArr = Array.isArray(merged[role]) ? merged[role] : [merged[role]];
|
|
27476
|
+
const incomingArr = Array.isArray(perm) ? perm : [perm];
|
|
27477
|
+
merged[role] = [...existingArr, ...incomingArr];
|
|
27478
|
+
}
|
|
27479
|
+
}
|
|
27480
|
+
return merged;
|
|
27481
|
+
}
|
|
27482
|
+
function registerActionCasl(action) {
|
|
27483
|
+
const casl = action.casl;
|
|
27484
|
+
if (!casl || !("subject" in casl) || !casl.subject || !("permissions" in casl) || !casl.permissions) return;
|
|
27485
|
+
const subject2 = casl.subject;
|
|
27486
|
+
const existing = caslRegistry.get(subject2);
|
|
27487
|
+
if (existing) {
|
|
27488
|
+
existing.permissions = mergeActionPermissions(existing.permissions, casl.permissions);
|
|
27489
|
+
} else {
|
|
27490
|
+
caslRegistry.set(subject2, {
|
|
27491
|
+
subject: subject2,
|
|
27492
|
+
permissions: casl.permissions ?? {}
|
|
27493
|
+
});
|
|
27494
|
+
}
|
|
27495
|
+
}
|
|
27144
27496
|
for (const mod of modules) {
|
|
27145
27497
|
for (const def of mod.definitions ?? []) {
|
|
27146
27498
|
const casl = def.casl;
|
|
@@ -27150,6 +27502,12 @@ async function setupModuleRoutes(app) {
|
|
|
27150
27502
|
subject: casl.subject,
|
|
27151
27503
|
permissions: casl.permissions ?? {}
|
|
27152
27504
|
});
|
|
27505
|
+
for (const action of def.actions ?? []) {
|
|
27506
|
+
registerActionCasl(action);
|
|
27507
|
+
}
|
|
27508
|
+
}
|
|
27509
|
+
for (const action of mod.actions ?? []) {
|
|
27510
|
+
registerActionCasl(action);
|
|
27153
27511
|
}
|
|
27154
27512
|
}
|
|
27155
27513
|
setEntityDefinitions(caslRegistry);
|
|
@@ -27328,7 +27686,7 @@ async function createApp(options = {}) {
|
|
|
27328
27686
|
// Only accept arrays and objects
|
|
27329
27687
|
}));
|
|
27330
27688
|
app.use(cookieParser());
|
|
27331
|
-
const serveSPA = createServeSPA(app);
|
|
27689
|
+
const serveSPA = createServeSPA(app, options.httpServer);
|
|
27332
27690
|
if (options.beforeRoutes) {
|
|
27333
27691
|
const result = options.beforeRoutes(app, serveSPA);
|
|
27334
27692
|
if (result instanceof Promise) {
|
|
@@ -27422,11 +27780,11 @@ async function createApp(options = {}) {
|
|
|
27422
27780
|
});
|
|
27423
27781
|
const sortedSpas = [...servedSpas].sort((a, b) => b.endpoint.length - a.endpoint.length);
|
|
27424
27782
|
for (const spa of sortedSpas) {
|
|
27425
|
-
serveSPA(spa.endpoint, spa.path, spa);
|
|
27783
|
+
await serveSPA(spa.endpoint, spa.path, { ...spa, viteSrc: spa.viteSrc });
|
|
27426
27784
|
}
|
|
27427
27785
|
const { ui } = getConfig();
|
|
27428
27786
|
if (ui.enabled) {
|
|
27429
|
-
serveSPA(ui.base, ui.path);
|
|
27787
|
+
await serveSPA(ui.base, ui.path, { viteSrc: "../ui" });
|
|
27430
27788
|
}
|
|
27431
27789
|
app.use(errorMiddleware);
|
|
27432
27790
|
return app;
|
|
@@ -27452,58 +27810,32 @@ var init_app = __esm({
|
|
|
27452
27810
|
}
|
|
27453
27811
|
});
|
|
27454
27812
|
|
|
27455
|
-
// src/core/utils/
|
|
27813
|
+
// src/core/utils/port-check.ts
|
|
27456
27814
|
import net from "net";
|
|
27457
27815
|
import { execSync } from "child_process";
|
|
27458
27816
|
function findProcessOnPort(port) {
|
|
27459
27817
|
try {
|
|
27460
27818
|
const output = execSync(`lsof -ti :${port} 2>/dev/null`, { encoding: "utf-8" });
|
|
27461
27819
|
const pid = parseInt(output.trim().split("\n")[0] ?? "", 10);
|
|
27462
|
-
|
|
27820
|
+
if (isNaN(pid)) return null;
|
|
27821
|
+
let name = "unknown";
|
|
27822
|
+
try {
|
|
27823
|
+
name = execSync(`ps -o comm= -p ${pid} 2>/dev/null`, { encoding: "utf-8" }).trim();
|
|
27824
|
+
} catch {
|
|
27825
|
+
}
|
|
27826
|
+
return { pid, name };
|
|
27463
27827
|
} catch {
|
|
27464
27828
|
return null;
|
|
27465
27829
|
}
|
|
27466
27830
|
}
|
|
27467
|
-
function isSameProcessGroup(pid) {
|
|
27468
|
-
if (pid === process.pid || pid === process.ppid) return true;
|
|
27469
|
-
try {
|
|
27470
|
-
const ourPgid = execSync(`ps -o pgid= -p ${process.pid} 2>/dev/null`, { encoding: "utf-8" }).trim();
|
|
27471
|
-
const targetPgid = execSync(`ps -o pgid= -p ${pid} 2>/dev/null`, { encoding: "utf-8" }).trim();
|
|
27472
|
-
return ourPgid === targetPgid;
|
|
27473
|
-
} catch {
|
|
27474
|
-
return false;
|
|
27475
|
-
}
|
|
27476
|
-
}
|
|
27477
|
-
function killProcessOnPort(port) {
|
|
27478
|
-
const pid = findProcessOnPort(port);
|
|
27479
|
-
if (!pid) return false;
|
|
27480
|
-
if (isSameProcessGroup(pid)) {
|
|
27481
|
-
logger.warn({ port, pid }, `Skipping same process group (PID ${pid}) on port ${port}`);
|
|
27482
|
-
return false;
|
|
27483
|
-
}
|
|
27484
|
-
try {
|
|
27485
|
-
process.kill(pid, "SIGTERM");
|
|
27486
|
-
logger.warn({ port, pid }, `Killed process ${pid} on port ${port}`);
|
|
27487
|
-
return true;
|
|
27488
|
-
} catch {
|
|
27489
|
-
return false;
|
|
27490
|
-
}
|
|
27491
|
-
}
|
|
27492
27831
|
async function checkPortAvailable(port, host = "0.0.0.0") {
|
|
27493
27832
|
return new Promise((resolve2, reject) => {
|
|
27494
27833
|
const server2 = net.createServer();
|
|
27495
27834
|
server2.once("error", (err) => {
|
|
27496
27835
|
if (err.code === "EADDRINUSE") {
|
|
27497
|
-
|
|
27498
|
-
|
|
27499
|
-
|
|
27500
|
-
checkPortAvailable(port, host).then(resolve2).catch(reject);
|
|
27501
|
-
}, 500);
|
|
27502
|
-
return;
|
|
27503
|
-
}
|
|
27504
|
-
}
|
|
27505
|
-
logger.error({ port }, `Port ${port} is already in use`);
|
|
27506
|
-
reject(new Error(`Port ${port} is already in use`));
|
|
27836
|
+
const proc = findProcessOnPort(port);
|
|
27837
|
+
const msg = proc ? `Port ${port} is already in use by "${proc.name}" (PID ${proc.pid}). Stop that process first.` : `Port ${port} is already in use`;
|
|
27838
|
+
reject(new Error(msg));
|
|
27507
27839
|
} else {
|
|
27508
27840
|
reject(err);
|
|
27509
27841
|
}
|
|
@@ -27514,10 +27846,9 @@ async function checkPortAvailable(port, host = "0.0.0.0") {
|
|
|
27514
27846
|
server2.listen(port, host);
|
|
27515
27847
|
});
|
|
27516
27848
|
}
|
|
27517
|
-
var
|
|
27518
|
-
"src/core/utils/
|
|
27849
|
+
var init_port_check = __esm({
|
|
27850
|
+
"src/core/utils/port-check.ts"() {
|
|
27519
27851
|
"use strict";
|
|
27520
|
-
init_logger();
|
|
27521
27852
|
}
|
|
27522
27853
|
});
|
|
27523
27854
|
|
|
@@ -27555,7 +27886,7 @@ function isFrpcInstalled() {
|
|
|
27555
27886
|
return false;
|
|
27556
27887
|
}
|
|
27557
27888
|
}
|
|
27558
|
-
function startTunnel(config3) {
|
|
27889
|
+
async function startTunnel(config3) {
|
|
27559
27890
|
if (tunnelProcess) return true;
|
|
27560
27891
|
if (!isFrpcInstalled()) {
|
|
27561
27892
|
logger.warn("frpc binary not found \u2014 tunnel disabled. Install with: brew install frp");
|
|
@@ -27567,24 +27898,49 @@ function startTunnel(config3) {
|
|
|
27567
27898
|
tunnelProcess = spawn("frpc", ["-c", tmpConfigPath], {
|
|
27568
27899
|
stdio: ["ignore", "pipe", "pipe"]
|
|
27569
27900
|
});
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27574
|
-
|
|
27575
|
-
|
|
27576
|
-
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27901
|
+
outputBuffer = "";
|
|
27902
|
+
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
27903
|
+
return new Promise((resolve2) => {
|
|
27904
|
+
let settled = false;
|
|
27905
|
+
const collectOutput = (data) => {
|
|
27906
|
+
const msg = stripAnsi(data.toString()).trim();
|
|
27907
|
+
if (!msg) return;
|
|
27908
|
+
outputBuffer += msg + "\n";
|
|
27909
|
+
logger.debug({ component: "tunnel" }, msg);
|
|
27910
|
+
if (!settled && msg.includes("start proxy success")) {
|
|
27911
|
+
settled = true;
|
|
27912
|
+
const url = getTunnelUrl(config3.subdomain, config3.server);
|
|
27913
|
+
logger.info({ url, component: "tunnel" }, `Tunnel active \u2192 ${url}`);
|
|
27914
|
+
resolve2(true);
|
|
27915
|
+
}
|
|
27916
|
+
};
|
|
27917
|
+
tunnelProcess.stdout?.on("data", collectOutput);
|
|
27918
|
+
tunnelProcess.stderr?.on("data", collectOutput);
|
|
27919
|
+
tunnelProcess.on("exit", (code) => {
|
|
27920
|
+
if (code !== 0 && code !== null) {
|
|
27921
|
+
const output = outputBuffer.trim();
|
|
27922
|
+
const hint = output.includes("authorization failed") || output.includes("auth failed") || output.includes("invalid token") ? " \u2014 check FRPC_TOKEN is correct" : output.includes("login to the server failed") ? ` \u2014 ${output.split("\n").pop()}` : "";
|
|
27923
|
+
logger.error(
|
|
27924
|
+
{ code, reason: output || void 0, component: "tunnel" },
|
|
27925
|
+
`frpc failed to start${hint}`
|
|
27926
|
+
);
|
|
27927
|
+
}
|
|
27928
|
+
tunnelProcess = null;
|
|
27929
|
+
outputBuffer = "";
|
|
27930
|
+
cleanupConfig();
|
|
27931
|
+
if (!settled) {
|
|
27932
|
+
settled = true;
|
|
27933
|
+
resolve2(false);
|
|
27934
|
+
}
|
|
27935
|
+
});
|
|
27936
|
+
setTimeout(() => {
|
|
27937
|
+
if (!settled) {
|
|
27938
|
+
settled = true;
|
|
27939
|
+
logger.warn({ component: "tunnel" }, "frpc connection timeout (5s) \u2014 tunnel may not be active");
|
|
27940
|
+
resolve2(false);
|
|
27941
|
+
}
|
|
27942
|
+
}, 5e3);
|
|
27584
27943
|
});
|
|
27585
|
-
const url = getTunnelUrl(config3.subdomain, config3.server);
|
|
27586
|
-
logger.info({ url, component: "tunnel" }, `Tunnel enabled \u2192 ${url}`);
|
|
27587
|
-
return true;
|
|
27588
27944
|
}
|
|
27589
27945
|
function stopTunnel() {
|
|
27590
27946
|
if (tunnelProcess) {
|
|
@@ -27602,13 +27958,388 @@ function cleanupConfig() {
|
|
|
27602
27958
|
tmpConfigPath = null;
|
|
27603
27959
|
}
|
|
27604
27960
|
}
|
|
27605
|
-
var tunnelProcess, tmpConfigPath;
|
|
27961
|
+
var tunnelProcess, tmpConfigPath, outputBuffer;
|
|
27606
27962
|
var init_tunnel = __esm({
|
|
27607
27963
|
"src/core/tunnel.ts"() {
|
|
27608
27964
|
"use strict";
|
|
27609
27965
|
init_core();
|
|
27610
27966
|
tunnelProcess = null;
|
|
27611
27967
|
tmpConfigPath = null;
|
|
27968
|
+
outputBuffer = "";
|
|
27969
|
+
}
|
|
27970
|
+
});
|
|
27971
|
+
|
|
27972
|
+
// src/cli/shared.ts
|
|
27973
|
+
import { consola } from "consola";
|
|
27974
|
+
function initCli() {
|
|
27975
|
+
const config3 = getLoggerConfig();
|
|
27976
|
+
initLoggerService({ ...config3, level: "error", sentry: void 0 });
|
|
27977
|
+
setLoggerInstance(getPinoLogger());
|
|
27978
|
+
}
|
|
27979
|
+
var init_shared = __esm({
|
|
27980
|
+
"src/cli/shared.ts"() {
|
|
27981
|
+
"use strict";
|
|
27982
|
+
init_logger();
|
|
27983
|
+
}
|
|
27984
|
+
});
|
|
27985
|
+
|
|
27986
|
+
// src/cli/migrate-commands.ts
|
|
27987
|
+
import { readFileSync as readFileSync8, existsSync as existsSync12 } from "fs";
|
|
27988
|
+
import { join as join14 } from "path";
|
|
27989
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
27990
|
+
import Table from "cli-table3";
|
|
27991
|
+
import { consola as consola2 } from "consola";
|
|
27992
|
+
async function loadSelfPlugin() {
|
|
27993
|
+
const projectPath2 = getProjectPath();
|
|
27994
|
+
const pkgPath = join14(projectPath2, "package.json");
|
|
27995
|
+
if (!existsSync12(pkgPath)) return;
|
|
27996
|
+
try {
|
|
27997
|
+
const pkg2 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
27998
|
+
const pkgName = pkg2?.name;
|
|
27999
|
+
if (!pkgName || !/nexus-plugin-/.test(pkgName)) return;
|
|
28000
|
+
const srcEntry = join14(projectPath2, "src", "index.ts");
|
|
28001
|
+
const distEntry = join14(projectPath2, "dist", "index.js");
|
|
28002
|
+
if (existsSync12(srcEntry)) {
|
|
28003
|
+
try {
|
|
28004
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
28005
|
+
const mod = await tsImport(
|
|
28006
|
+
pathToFileURL3(srcEntry).href,
|
|
28007
|
+
import.meta.url
|
|
28008
|
+
);
|
|
28009
|
+
const manifest = extractPluginManifest(mod);
|
|
28010
|
+
if (manifest) {
|
|
28011
|
+
if (!manifest.migrationsDir) {
|
|
28012
|
+
manifest.migrationsDir = join14(projectPath2, "migrations");
|
|
28013
|
+
}
|
|
28014
|
+
registerPlugin(manifest);
|
|
28015
|
+
return;
|
|
28016
|
+
}
|
|
28017
|
+
} catch (err) {
|
|
28018
|
+
console.error(` \u26A0 Failed to load plugin src/index.ts: ${err.message}`);
|
|
28019
|
+
}
|
|
28020
|
+
}
|
|
28021
|
+
if (existsSync12(distEntry)) {
|
|
28022
|
+
try {
|
|
28023
|
+
const mod = await import(pathToFileURL3(distEntry).href);
|
|
28024
|
+
const manifest = extractPluginManifest(mod);
|
|
28025
|
+
if (manifest) {
|
|
28026
|
+
if (!manifest.migrationsDir) {
|
|
28027
|
+
manifest.migrationsDir = join14(projectPath2, "migrations");
|
|
28028
|
+
}
|
|
28029
|
+
registerPlugin(manifest);
|
|
28030
|
+
return;
|
|
28031
|
+
}
|
|
28032
|
+
} catch (err) {
|
|
28033
|
+
console.error(` \u26A0 Failed to load plugin dist/index.js: ${err.message}`);
|
|
28034
|
+
}
|
|
28035
|
+
}
|
|
28036
|
+
} catch {
|
|
28037
|
+
}
|
|
28038
|
+
}
|
|
28039
|
+
async function loadModulesForMigration() {
|
|
28040
|
+
loadCoreModules();
|
|
28041
|
+
await loadSelfPlugin();
|
|
28042
|
+
const config3 = await loadNexusConfig();
|
|
28043
|
+
if (config3.plugins?.length) {
|
|
28044
|
+
const sorted = topologicalSortPlugins(config3.plugins);
|
|
28045
|
+
for (const plugin of sorted) {
|
|
28046
|
+
registerPlugin(plugin);
|
|
28047
|
+
}
|
|
28048
|
+
}
|
|
28049
|
+
const coreNames = new Set(getOrderedModules().map((m) => m.name));
|
|
28050
|
+
for (const mod of config3.modules ?? []) {
|
|
28051
|
+
if (!coreNames.has(mod.name)) {
|
|
28052
|
+
registerModule(mod, { source: "standalone" });
|
|
28053
|
+
}
|
|
28054
|
+
}
|
|
28055
|
+
}
|
|
28056
|
+
var init_migrate_commands = __esm({
|
|
28057
|
+
"src/cli/migrate-commands.ts"() {
|
|
28058
|
+
"use strict";
|
|
28059
|
+
init_database();
|
|
28060
|
+
init_engine();
|
|
28061
|
+
init_load_config();
|
|
28062
|
+
init_shared();
|
|
28063
|
+
init_paths();
|
|
28064
|
+
init_connection();
|
|
28065
|
+
init_ensure_system_tables();
|
|
28066
|
+
init_migration_generator();
|
|
28067
|
+
init_migration_runner();
|
|
28068
|
+
}
|
|
28069
|
+
});
|
|
28070
|
+
|
|
28071
|
+
// src/cli/seed-commands.ts
|
|
28072
|
+
var seed_commands_exports = {};
|
|
28073
|
+
__export(seed_commands_exports, {
|
|
28074
|
+
handleSeedExport: () => handleSeedExport,
|
|
28075
|
+
importSeedFiles: () => importSeedFiles
|
|
28076
|
+
});
|
|
28077
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
|
|
28078
|
+
import { join as join15, basename as basename4 } from "path";
|
|
28079
|
+
import { consola as consola3 } from "consola";
|
|
28080
|
+
function deserializeJsonFields(record, fields) {
|
|
28081
|
+
const result = { ...record };
|
|
28082
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
28083
|
+
if (field.db?.type === "json" && typeof result[name] === "string") {
|
|
28084
|
+
try {
|
|
28085
|
+
result[name] = JSON.parse(result[name]);
|
|
28086
|
+
} catch {
|
|
28087
|
+
}
|
|
28088
|
+
}
|
|
28089
|
+
}
|
|
28090
|
+
return result;
|
|
28091
|
+
}
|
|
28092
|
+
function serializeJsonFields(record, fields) {
|
|
28093
|
+
const result = { ...record };
|
|
28094
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
28095
|
+
if (field.db?.type === "json" && typeof result[name] === "object" && result[name] !== null) {
|
|
28096
|
+
result[name] = JSON.stringify(result[name]);
|
|
28097
|
+
}
|
|
28098
|
+
}
|
|
28099
|
+
return result;
|
|
28100
|
+
}
|
|
28101
|
+
async function handleSeedExport(entity) {
|
|
28102
|
+
initCli();
|
|
28103
|
+
await loadModulesForMigration();
|
|
28104
|
+
const db2 = getDb();
|
|
28105
|
+
try {
|
|
28106
|
+
const modules = getOrderedModules();
|
|
28107
|
+
const seedDir = join15(getProjectPath(), "data", "seeds");
|
|
28108
|
+
const seedableEntities = [];
|
|
28109
|
+
for (const mod of modules) {
|
|
28110
|
+
for (const def of mod.definitions ?? []) {
|
|
28111
|
+
if (!("seedable" in def) || !def.seedable) continue;
|
|
28112
|
+
if (entity && def.table !== entity) continue;
|
|
28113
|
+
seedableEntities.push({
|
|
28114
|
+
module: mod.name,
|
|
28115
|
+
table: def.table,
|
|
28116
|
+
fields: def.fields
|
|
28117
|
+
});
|
|
28118
|
+
}
|
|
28119
|
+
}
|
|
28120
|
+
if (seedableEntities.length === 0) {
|
|
28121
|
+
if (entity) {
|
|
28122
|
+
consola3.warn(`No seedable entity found with table "${entity}"`);
|
|
28123
|
+
} else {
|
|
28124
|
+
consola3.warn("No seedable entities found");
|
|
28125
|
+
}
|
|
28126
|
+
return;
|
|
28127
|
+
}
|
|
28128
|
+
if (!existsSync13(seedDir)) {
|
|
28129
|
+
mkdirSync6(seedDir, { recursive: true });
|
|
28130
|
+
}
|
|
28131
|
+
for (const { module: modName, table, fields } of seedableEntities) {
|
|
28132
|
+
const rows = await db2(table).orderBy("id");
|
|
28133
|
+
if (rows.length === 0) {
|
|
28134
|
+
consola3.info(`${table}: no records, skipping`);
|
|
28135
|
+
continue;
|
|
28136
|
+
}
|
|
28137
|
+
const exported = rows.map(
|
|
28138
|
+
(row) => deserializeJsonFields(row, fields)
|
|
28139
|
+
);
|
|
28140
|
+
const filePath = join15(seedDir, `${table}.json`);
|
|
28141
|
+
writeFileSync3(filePath, JSON.stringify(exported, null, 2) + "\n", "utf-8");
|
|
28142
|
+
consola3.success(`${table}: exported ${rows.length} records to data/seeds/${table}.json (module: ${modName})`);
|
|
28143
|
+
}
|
|
28144
|
+
} catch (err) {
|
|
28145
|
+
consola3.error("Seed export failed:", err);
|
|
28146
|
+
} finally {
|
|
28147
|
+
await db2.destroy();
|
|
28148
|
+
process.exit(0);
|
|
28149
|
+
}
|
|
28150
|
+
}
|
|
28151
|
+
async function importSeedFiles(db2, modules, logger2) {
|
|
28152
|
+
const seedDir = join15(getProjectPath(), "data", "seeds");
|
|
28153
|
+
if (!existsSync13(seedDir)) return;
|
|
28154
|
+
const files = readdirSync2(seedDir).filter((f) => f.endsWith(".json"));
|
|
28155
|
+
if (files.length === 0) return;
|
|
28156
|
+
const seedableDefs = /* @__PURE__ */ new Map();
|
|
28157
|
+
for (const mod of modules) {
|
|
28158
|
+
for (const rawDef of mod.definitions ?? []) {
|
|
28159
|
+
const def = rawDef;
|
|
28160
|
+
if (!def["seedable"] || !def["table"] || !def["fields"]) continue;
|
|
28161
|
+
seedableDefs.set(
|
|
28162
|
+
def["table"],
|
|
28163
|
+
{ fields: def["fields"], module: mod.name }
|
|
28164
|
+
);
|
|
28165
|
+
}
|
|
28166
|
+
}
|
|
28167
|
+
for (const file of files) {
|
|
28168
|
+
const table = basename4(file, ".json");
|
|
28169
|
+
const defInfo = seedableDefs.get(table);
|
|
28170
|
+
if (!defInfo) {
|
|
28171
|
+
logger2.debug(`data/seeds/${file}: skipped (entity "${table}" is not seedable)`);
|
|
28172
|
+
continue;
|
|
28173
|
+
}
|
|
28174
|
+
const filePath = join15(seedDir, file);
|
|
28175
|
+
const raw = readFileSync9(filePath, "utf-8");
|
|
28176
|
+
let records;
|
|
28177
|
+
try {
|
|
28178
|
+
records = JSON.parse(raw);
|
|
28179
|
+
} catch {
|
|
28180
|
+
logger2.info(`data/seeds/${file}: skipped (invalid JSON)`);
|
|
28181
|
+
continue;
|
|
28182
|
+
}
|
|
28183
|
+
if (!Array.isArray(records) || records.length === 0) continue;
|
|
28184
|
+
const rows = records.map((r) => serializeJsonFields(r, defInfo.fields));
|
|
28185
|
+
for (const row of rows) {
|
|
28186
|
+
await db2(table).insert(row).onConflict("id").merge();
|
|
28187
|
+
}
|
|
28188
|
+
logger2.info(`Seeded ${rows.length} records into ${table} from data/seeds/${file}`);
|
|
28189
|
+
}
|
|
28190
|
+
}
|
|
28191
|
+
var init_seed_commands = __esm({
|
|
28192
|
+
"src/cli/seed-commands.ts"() {
|
|
28193
|
+
"use strict";
|
|
28194
|
+
init_engine();
|
|
28195
|
+
init_paths();
|
|
28196
|
+
init_connection();
|
|
28197
|
+
init_shared();
|
|
28198
|
+
init_migrate_commands();
|
|
28199
|
+
}
|
|
28200
|
+
});
|
|
28201
|
+
|
|
28202
|
+
// src/db/seed-context.ts
|
|
28203
|
+
var seed_context_exports = {};
|
|
28204
|
+
__export(seed_context_exports, {
|
|
28205
|
+
createSeedContext: () => createSeedContext
|
|
28206
|
+
});
|
|
28207
|
+
function createSeedContext(deps) {
|
|
28208
|
+
const { knex: db2, generateId: generateId4, hashPassword: hashPassword2, pluginPrefixes, logger: logger2 } = deps;
|
|
28209
|
+
const permissionsMap = /* @__PURE__ */ new Map();
|
|
28210
|
+
const seedContext = {
|
|
28211
|
+
masters: {
|
|
28212
|
+
register(type2, entries, options) {
|
|
28213
|
+
deps.masterRegistry.register(type2, entries, options);
|
|
28214
|
+
}
|
|
28215
|
+
},
|
|
28216
|
+
roles: {
|
|
28217
|
+
async add(role) {
|
|
28218
|
+
const hasTable = await db2.schema.hasTable("roles");
|
|
28219
|
+
if (!hasTable) return;
|
|
28220
|
+
const existing = await db2("roles").where({ name: role.name }).first();
|
|
28221
|
+
if (!existing) {
|
|
28222
|
+
const description = role.description ? JSON.stringify(typeof role.description === "string" ? { en: role.description } : role.description) : null;
|
|
28223
|
+
await db2("roles").insert({
|
|
28224
|
+
id: generateId4(),
|
|
28225
|
+
name: role.name,
|
|
28226
|
+
description,
|
|
28227
|
+
is_system: role.is_system ?? false
|
|
28228
|
+
});
|
|
28229
|
+
logger2.info({ role: role.name }, "Seeded role");
|
|
28230
|
+
}
|
|
28231
|
+
if (role.permissions) {
|
|
28232
|
+
let rolePerms = permissionsMap.get(role.name);
|
|
28233
|
+
if (!rolePerms) {
|
|
28234
|
+
rolePerms = /* @__PURE__ */ new Map();
|
|
28235
|
+
permissionsMap.set(role.name, rolePerms);
|
|
28236
|
+
}
|
|
28237
|
+
for (const [subject2, actions] of Object.entries(role.permissions)) {
|
|
28238
|
+
const normalized = subject2.charAt(0).toUpperCase() + subject2.slice(1);
|
|
28239
|
+
rolePerms.set(normalized, actions);
|
|
28240
|
+
}
|
|
28241
|
+
}
|
|
28242
|
+
}
|
|
28243
|
+
},
|
|
28244
|
+
users: {
|
|
28245
|
+
async add(user) {
|
|
28246
|
+
const hasTable = await db2.schema.hasTable("users");
|
|
28247
|
+
if (!hasTable) return;
|
|
28248
|
+
const existing = await db2("users").where({ email: user.email }).first();
|
|
28249
|
+
if (existing) return;
|
|
28250
|
+
const userId = generateId4();
|
|
28251
|
+
await db2("users").insert({
|
|
28252
|
+
id: userId,
|
|
28253
|
+
type: user.type ?? "human",
|
|
28254
|
+
email: user.email,
|
|
28255
|
+
password: await hashPassword2(user.password),
|
|
28256
|
+
name: user.name ?? user.email
|
|
28257
|
+
});
|
|
28258
|
+
if (user.roles?.length) {
|
|
28259
|
+
for (const roleName of user.roles) {
|
|
28260
|
+
const role = await db2("roles").where({ name: roleName }).first();
|
|
28261
|
+
if (role) {
|
|
28262
|
+
await db2("user_roles").insert({
|
|
28263
|
+
id: generateId4(),
|
|
28264
|
+
user_id: userId,
|
|
28265
|
+
role_id: role.id
|
|
28266
|
+
});
|
|
28267
|
+
} else {
|
|
28268
|
+
logger2.warn({ role: roleName, user: user.email }, "Role not found, skipping assignment");
|
|
28269
|
+
}
|
|
28270
|
+
}
|
|
28271
|
+
}
|
|
28272
|
+
logger2.info({ email: user.email, roles: user.roles }, "Seeded user");
|
|
28273
|
+
}
|
|
28274
|
+
},
|
|
28275
|
+
plugin(pluginName) {
|
|
28276
|
+
return {
|
|
28277
|
+
entity(entityName) {
|
|
28278
|
+
return {
|
|
28279
|
+
async upsert(data, options) {
|
|
28280
|
+
let prefix = pluginPrefixes.get(pluginName) ?? "";
|
|
28281
|
+
if (!prefix) {
|
|
28282
|
+
for (const [key2, pfx] of pluginPrefixes) {
|
|
28283
|
+
if (pluginName === key2 || pluginName.endsWith(`-${key2}`)) {
|
|
28284
|
+
prefix = pfx;
|
|
28285
|
+
break;
|
|
28286
|
+
}
|
|
28287
|
+
}
|
|
28288
|
+
}
|
|
28289
|
+
const fullTable = `${prefix}${entityName}`;
|
|
28290
|
+
const hasTable = await db2.schema.hasTable(fullTable);
|
|
28291
|
+
if (!hasTable) {
|
|
28292
|
+
logger2.warn({ table: fullTable, plugin: pluginName }, "Table not found for plugin entity seed");
|
|
28293
|
+
return 0;
|
|
28294
|
+
}
|
|
28295
|
+
const key = options?.key ?? "id";
|
|
28296
|
+
let seeded = 0;
|
|
28297
|
+
for (const row of data) {
|
|
28298
|
+
const keyValue = row[key];
|
|
28299
|
+
if (keyValue != null) {
|
|
28300
|
+
const existing = await db2(fullTable).where({ [key]: keyValue }).first();
|
|
28301
|
+
if (existing) continue;
|
|
28302
|
+
}
|
|
28303
|
+
const insertData = { ...row };
|
|
28304
|
+
if (key === "id" && !insertData["id"]) {
|
|
28305
|
+
insertData["id"] = generateId4();
|
|
28306
|
+
}
|
|
28307
|
+
await db2(fullTable).insert(insertData);
|
|
28308
|
+
seeded++;
|
|
28309
|
+
}
|
|
28310
|
+
if (seeded > 0) {
|
|
28311
|
+
logger2.info({ table: fullTable, seeded }, "Seeded plugin entity data");
|
|
28312
|
+
}
|
|
28313
|
+
return seeded;
|
|
28314
|
+
}
|
|
28315
|
+
};
|
|
28316
|
+
}
|
|
28317
|
+
};
|
|
28318
|
+
},
|
|
28319
|
+
async raw(table, data) {
|
|
28320
|
+
logger2.warn({ table }, "Using seed.raw() \u2014 prefer typed helpers when available");
|
|
28321
|
+
const hasTable = await db2.schema.hasTable(table);
|
|
28322
|
+
if (!hasTable) {
|
|
28323
|
+
logger2.warn({ table }, "Table not found for raw seed");
|
|
28324
|
+
return 0;
|
|
28325
|
+
}
|
|
28326
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
28327
|
+
await db2(table).insert(rows);
|
|
28328
|
+
return rows.length;
|
|
28329
|
+
}
|
|
28330
|
+
};
|
|
28331
|
+
return {
|
|
28332
|
+
ctx: seedContext,
|
|
28333
|
+
flushPermissions: () => {
|
|
28334
|
+
if (permissionsMap.size > 0 && deps.onPermissionsCollected) {
|
|
28335
|
+
deps.onPermissionsCollected(permissionsMap);
|
|
28336
|
+
}
|
|
28337
|
+
}
|
|
28338
|
+
};
|
|
28339
|
+
}
|
|
28340
|
+
var init_seed_context = __esm({
|
|
28341
|
+
"src/db/seed-context.ts"() {
|
|
28342
|
+
"use strict";
|
|
27612
28343
|
}
|
|
27613
28344
|
});
|
|
27614
28345
|
|
|
@@ -27620,7 +28351,9 @@ __export(server_exports, {
|
|
|
27620
28351
|
start: () => start,
|
|
27621
28352
|
stop: () => stop
|
|
27622
28353
|
});
|
|
28354
|
+
import http from "http";
|
|
27623
28355
|
import { entityRoom as entityRoom6 } from "@gzl10/nexus-sdk";
|
|
28356
|
+
import { DEFAULT_LOCALES as DEFAULT_LOCALES2 } from "@gzl10/nexus-sdk";
|
|
27624
28357
|
async function runMigrationsAndSeeds(config3) {
|
|
27625
28358
|
initLoggerService(getLoggerConfig());
|
|
27626
28359
|
setLoggerInstance(getPinoLogger());
|
|
@@ -27673,7 +28406,7 @@ async function runMigrationsAndSeeds(config3) {
|
|
|
27673
28406
|
const sources = buildMigrationSources();
|
|
27674
28407
|
const migrationFiles = await loadAllMigrationFiles(sources);
|
|
27675
28408
|
if (migrationFiles.length > 0) {
|
|
27676
|
-
logger.info({
|
|
28409
|
+
logger.info({ sources: sources.length, files: migrationFiles.length }, "Running migration deploy...");
|
|
27677
28410
|
try {
|
|
27678
28411
|
await runMigrations(void 0, sources);
|
|
27679
28412
|
} catch (err) {
|
|
@@ -27682,7 +28415,7 @@ async function runMigrationsAndSeeds(config3) {
|
|
|
27682
28415
|
throw err;
|
|
27683
28416
|
}
|
|
27684
28417
|
}
|
|
27685
|
-
logger.
|
|
28418
|
+
logger.debug("Checking schema drift...");
|
|
27686
28419
|
const drift = await detectSchemaDrift();
|
|
27687
28420
|
if (drift && (drift.newTables.length > 0 || drift.alteredTables.length > 0)) {
|
|
27688
28421
|
const message = formatDriftMessage(drift);
|
|
@@ -27729,7 +28462,16 @@ ${dirs}`);
|
|
|
27729
28462
|
}
|
|
27730
28463
|
const allDefinitions = modules.flatMap((m) => m.definitions ?? []);
|
|
27731
28464
|
await createMemoryTables(allDefinitions);
|
|
27732
|
-
|
|
28465
|
+
try {
|
|
28466
|
+
const { importSeedFiles: importSeedFiles2 } = await Promise.resolve().then(() => (init_seed_commands(), seed_commands_exports));
|
|
28467
|
+
await importSeedFiles2(ctx.db.knex, modules, {
|
|
28468
|
+
info: (msg) => logger.info(msg),
|
|
28469
|
+
debug: (msg) => logger.debug(msg)
|
|
28470
|
+
});
|
|
28471
|
+
} catch (err) {
|
|
28472
|
+
logger.debug({ err }, "Seed file import skipped (no data/seeds/ or error)");
|
|
28473
|
+
}
|
|
28474
|
+
logger.debug("Running seeds...");
|
|
27733
28475
|
for (const mod of modules) {
|
|
27734
28476
|
try {
|
|
27735
28477
|
await runModuleSeed(mod, ctx);
|
|
@@ -27737,14 +28479,41 @@ ${dirs}`);
|
|
|
27737
28479
|
logger.error({ module: mod.name, err }, "Seed failed - continuing with next module");
|
|
27738
28480
|
}
|
|
27739
28481
|
}
|
|
28482
|
+
if (config3?.onSeed) {
|
|
28483
|
+
const { getPlugins: getPlugins2 } = await Promise.resolve().then(() => (init_module_queries(), module_queries_exports));
|
|
28484
|
+
const { createMasterRegistry: createMasterRegistry2 } = await Promise.resolve().then(() => (init_registry2(), registry_exports));
|
|
28485
|
+
const masterRegistry = ctx.services.has("masters") ? ctx.services.get("masters") : createMasterRegistry2();
|
|
28486
|
+
const pluginPrefixes = /* @__PURE__ */ new Map();
|
|
28487
|
+
for (const plugin of getPlugins2()) {
|
|
28488
|
+
pluginPrefixes.set(plugin.code, `${plugin.code}_`);
|
|
28489
|
+
const shortName = plugin.name.replace(/^@[^/]+\/nexus-plugin-/, "");
|
|
28490
|
+
if (shortName !== plugin.code) {
|
|
28491
|
+
pluginPrefixes.set(shortName, `${plugin.code}_`);
|
|
28492
|
+
}
|
|
28493
|
+
}
|
|
28494
|
+
const { createSeedContext: createSeedContext2 } = await Promise.resolve().then(() => (init_seed_context(), seed_context_exports));
|
|
28495
|
+
const { ctx: seedCtx, flushPermissions } = createSeedContext2({
|
|
28496
|
+
knex: ctx.db.knex,
|
|
28497
|
+
generateId: ctx.core.generateId,
|
|
28498
|
+
hashPassword: ctx.core.crypto.hashPassword,
|
|
28499
|
+
masterRegistry,
|
|
28500
|
+
pluginPrefixes,
|
|
28501
|
+
logger: ctx.core.logger,
|
|
28502
|
+
onPermissionsCollected: (perms) => setSeedPermissions(perms)
|
|
28503
|
+
});
|
|
28504
|
+
await config3.onSeed(seedCtx);
|
|
28505
|
+
await masterRegistry.seed(ctx);
|
|
28506
|
+
flushPermissions();
|
|
28507
|
+
}
|
|
27740
28508
|
}
|
|
27741
28509
|
async function start(config3) {
|
|
27742
28510
|
if (server) {
|
|
27743
28511
|
throw new Error("Server already running. Call stop() first.");
|
|
27744
28512
|
}
|
|
27745
28513
|
currentConfig = config3;
|
|
27746
|
-
|
|
27747
|
-
|
|
28514
|
+
setLocales(config3?.locales ?? DEFAULT_LOCALES2);
|
|
28515
|
+
if (env.NODE_ENV === "development" && env.FRPC_SERVER && !env.TRUST_PROXY) {
|
|
28516
|
+
process.env["TRUST_PROXY"] = "true";
|
|
27748
28517
|
}
|
|
27749
28518
|
const resolved = resolveConfig();
|
|
27750
28519
|
if (resolved.port > 0) {
|
|
@@ -27767,13 +28536,17 @@ async function start(config3) {
|
|
|
27767
28536
|
await initTelemetry2();
|
|
27768
28537
|
await runMigrationsAndSeeds(config3);
|
|
27769
28538
|
const effectiveCorsOrigins = buildEffectiveCorsOrigins(env.CORS_ORIGIN, config3?.spas);
|
|
28539
|
+
const httpServer = http.createServer();
|
|
27770
28540
|
const app = await createApp({
|
|
27771
28541
|
beforeRoutes: config3?.beforeRoutes,
|
|
27772
28542
|
afterRoutes: config3?.afterRoutes,
|
|
27773
|
-
spas: config3?.spas
|
|
28543
|
+
spas: config3?.spas,
|
|
28544
|
+
httpServer
|
|
27774
28545
|
});
|
|
28546
|
+
httpServer.on("request", app);
|
|
27775
28547
|
return new Promise((resolve2) => {
|
|
27776
|
-
server =
|
|
28548
|
+
server = httpServer;
|
|
28549
|
+
httpServer.listen(resolved.port, resolved.host, async () => {
|
|
27777
28550
|
const timeoutMs = parseInt(process.env["REQUEST_TIMEOUT_MS"] || "30000", 10);
|
|
27778
28551
|
if (timeoutMs > 0) {
|
|
27779
28552
|
server.setTimeout(timeoutMs);
|
|
@@ -27799,22 +28572,24 @@ async function start(config3) {
|
|
|
27799
28572
|
eventBridge.init();
|
|
27800
28573
|
const addr = server.address();
|
|
27801
28574
|
const actualPort = typeof addr === "object" && addr ? addr.port : resolved.port;
|
|
28575
|
+
let tunnelActive = false;
|
|
27802
28576
|
if (env.NODE_ENV === "development" && env.FRPC_SERVER && env.FRPC_SUBDOMAIN) {
|
|
27803
|
-
startTunnel({
|
|
28577
|
+
tunnelActive = await startTunnel({
|
|
27804
28578
|
server: env.FRPC_SERVER,
|
|
27805
28579
|
serverPort: env.FRPC_SERVER_PORT,
|
|
27806
28580
|
token: env.FRPC_TOKEN,
|
|
27807
28581
|
subdomain: env.FRPC_SUBDOMAIN,
|
|
27808
28582
|
localPort: actualPort
|
|
27809
28583
|
});
|
|
28584
|
+
if (tunnelActive && !env.BACKEND_URL) {
|
|
28585
|
+
process.env["BACKEND_URL"] = getTunnelUrl(env.FRPC_SUBDOMAIN, env.FRPC_SERVER);
|
|
28586
|
+
}
|
|
27810
28587
|
}
|
|
27811
28588
|
const baseUrl = env.BACKEND_URL || `http://localhost:${actualPort}`;
|
|
27812
|
-
logger.
|
|
27813
|
-
|
|
27814
|
-
if (resolved.ui.enabled)
|
|
27815
|
-
|
|
27816
|
-
}
|
|
27817
|
-
logger.info({ port: actualPort, mode: resolved.nodeEnv }, "Server started");
|
|
28589
|
+
logger.debug({ libPath: getLibPath(), projectPath: getProjectPath() }, "Paths");
|
|
28590
|
+
const urls = { api: `${baseUrl}/api/v1` };
|
|
28591
|
+
if (resolved.ui.enabled) urls["ui"] = baseUrl;
|
|
28592
|
+
logger.info({ port: actualPort, mode: resolved.nodeEnv, ...urls }, "Server started");
|
|
27818
28593
|
nexusEvents.emitEvent("server.started", { port: actualPort, host: resolved.host });
|
|
27819
28594
|
if (config3?.onReady) {
|
|
27820
28595
|
try {
|
|
@@ -27840,7 +28615,8 @@ async function stop() {
|
|
|
27840
28615
|
await resetSharedAdapters();
|
|
27841
28616
|
resetConfigCache();
|
|
27842
28617
|
clearCustomCaslRules();
|
|
27843
|
-
|
|
28618
|
+
clearSeedPermissions();
|
|
28619
|
+
await resetServeSPA();
|
|
27844
28620
|
return;
|
|
27845
28621
|
}
|
|
27846
28622
|
if (currentConfig?.beforeClose) {
|
|
@@ -27874,7 +28650,8 @@ async function stop() {
|
|
|
27874
28650
|
await resetSharedAdapters();
|
|
27875
28651
|
resetConfigCache();
|
|
27876
28652
|
clearCustomCaslRules();
|
|
27877
|
-
|
|
28653
|
+
clearSeedPermissions();
|
|
28654
|
+
await resetServeSPA();
|
|
27878
28655
|
currentConfig = void 0;
|
|
27879
28656
|
server = null;
|
|
27880
28657
|
nexusEvents.emitEvent("server.stopped");
|
|
@@ -27934,7 +28711,7 @@ var init_server = __esm({
|
|
|
27934
28711
|
init_cors();
|
|
27935
28712
|
init_logger();
|
|
27936
28713
|
init_error_middleware();
|
|
27937
|
-
|
|
28714
|
+
init_port_check();
|
|
27938
28715
|
init_engine();
|
|
27939
28716
|
init_context();
|
|
27940
28717
|
init_db();
|