@gzl10/nexus-backend 0.17.0 → 0.18.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/cli.js +551 -7296
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +113 -7
- package/dist/index.js +497 -215
- package/dist/index.js.map +1 -1
- package/dist/main.js +507 -215
- package/dist/main.js.map +1 -1
- package/package.json +12 -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.18.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",
|
|
@@ -162,7 +162,7 @@ var init_package = __esm({
|
|
|
162
162
|
"jwt"
|
|
163
163
|
],
|
|
164
164
|
scripts: {
|
|
165
|
-
dev: "
|
|
165
|
+
dev: "node --watch-path=./src --import tsx/esm src/main.ts",
|
|
166
166
|
build: "tsup",
|
|
167
167
|
start: "node dist/main.js",
|
|
168
168
|
nexus: "tsx src/cli.ts",
|
|
@@ -218,26 +218,6 @@ var init_package = __esm({
|
|
|
218
218
|
zod: "^3.24.0"
|
|
219
219
|
},
|
|
220
220
|
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
221
|
"@types/bcryptjs": "^2.4.0",
|
|
242
222
|
"@types/compression": "^1.8.1",
|
|
243
223
|
"@types/cookie-parser": "^1.4.10",
|
|
@@ -250,7 +230,16 @@ var init_package = __esm({
|
|
|
250
230
|
"pino-pretty": "^13.1.3",
|
|
251
231
|
"socket.io-client": "^4.8.3",
|
|
252
232
|
supertest: "^7.2.2",
|
|
253
|
-
tsx: "^4.21.0"
|
|
233
|
+
tsx: "^4.21.0",
|
|
234
|
+
vite: "^8.0.3"
|
|
235
|
+
},
|
|
236
|
+
peerDependencies: {
|
|
237
|
+
vite: ">=6.0.0"
|
|
238
|
+
},
|
|
239
|
+
peerDependenciesMeta: {
|
|
240
|
+
vite: {
|
|
241
|
+
optional: true
|
|
242
|
+
}
|
|
254
243
|
},
|
|
255
244
|
publishConfig: {
|
|
256
245
|
access: "public",
|
|
@@ -1252,7 +1241,7 @@ var init_table_prefix = __esm({
|
|
|
1252
1241
|
}
|
|
1253
1242
|
});
|
|
1254
1243
|
|
|
1255
|
-
// src/engine/store.ts
|
|
1244
|
+
// src/engine/module-store.ts
|
|
1256
1245
|
function resetStore() {
|
|
1257
1246
|
moduleStore.modules.length = 0;
|
|
1258
1247
|
moduleStore.plugins.clear();
|
|
@@ -1263,8 +1252,8 @@ function resetStore() {
|
|
|
1263
1252
|
moduleStore.tableToSubject.clear();
|
|
1264
1253
|
}
|
|
1265
1254
|
var moduleStore;
|
|
1266
|
-
var
|
|
1267
|
-
"src/engine/store.ts"() {
|
|
1255
|
+
var init_module_store = __esm({
|
|
1256
|
+
"src/engine/module-store.ts"() {
|
|
1268
1257
|
"use strict";
|
|
1269
1258
|
moduleStore = {
|
|
1270
1259
|
/** Registered modules with source metadata */
|
|
@@ -1317,7 +1306,7 @@ var init_id = __esm({
|
|
|
1317
1306
|
}
|
|
1318
1307
|
});
|
|
1319
1308
|
|
|
1320
|
-
// src/engine/extractors.ts
|
|
1309
|
+
// src/engine/definition-extractors.ts
|
|
1321
1310
|
function getTableAndSubject(def) {
|
|
1322
1311
|
const caslSubject = def.casl?.subject;
|
|
1323
1312
|
if (!TYPES_WITH_TABLE.has(def.type)) {
|
|
@@ -1385,8 +1374,8 @@ function validateModuleDependencies(modules) {
|
|
|
1385
1374
|
}
|
|
1386
1375
|
}
|
|
1387
1376
|
var TYPES_WITH_TABLE;
|
|
1388
|
-
var
|
|
1389
|
-
"src/engine/extractors.ts"() {
|
|
1377
|
+
var init_definition_extractors = __esm({
|
|
1378
|
+
"src/engine/definition-extractors.ts"() {
|
|
1390
1379
|
"use strict";
|
|
1391
1380
|
TYPES_WITH_TABLE = /* @__PURE__ */ new Set(["collection", "reference", "event", "config", "temp", "view", void 0]);
|
|
1392
1381
|
}
|
|
@@ -1506,9 +1495,9 @@ var init_registry = __esm({
|
|
|
1506
1495
|
"use strict";
|
|
1507
1496
|
init_plugin_ops();
|
|
1508
1497
|
init_table_prefix();
|
|
1509
|
-
|
|
1498
|
+
init_module_store();
|
|
1510
1499
|
init_id();
|
|
1511
|
-
|
|
1500
|
+
init_definition_extractors();
|
|
1512
1501
|
}
|
|
1513
1502
|
});
|
|
1514
1503
|
|
|
@@ -1560,7 +1549,28 @@ var init_paths = __esm({
|
|
|
1560
1549
|
}
|
|
1561
1550
|
});
|
|
1562
1551
|
|
|
1563
|
-
// src/engine/queries.ts
|
|
1552
|
+
// src/engine/module-queries.ts
|
|
1553
|
+
var module_queries_exports = {};
|
|
1554
|
+
__export(module_queries_exports, {
|
|
1555
|
+
getCoreManifest: () => getCoreManifest,
|
|
1556
|
+
getCoreModules: () => getCoreModules,
|
|
1557
|
+
getModule: () => getModule,
|
|
1558
|
+
getModules: () => getModules,
|
|
1559
|
+
getOrderedModules: () => getOrderedModules,
|
|
1560
|
+
getOrderedModulesInternal: () => getOrderedModulesInternal,
|
|
1561
|
+
getPlugin: () => getPlugin,
|
|
1562
|
+
getPluginByCode: () => getPluginByCode,
|
|
1563
|
+
getPlugins: () => getPlugins,
|
|
1564
|
+
getRegisteredSubjects: () => getRegisteredSubjects,
|
|
1565
|
+
getSubjectForTable: () => getSubjectForTable,
|
|
1566
|
+
getUserManifest: () => getUserManifest,
|
|
1567
|
+
getUserModules: () => getUserModules,
|
|
1568
|
+
hasModule: () => hasModule,
|
|
1569
|
+
hasPlugin: () => hasPlugin,
|
|
1570
|
+
hasPluginByCode: () => hasPluginByCode,
|
|
1571
|
+
hasUserApp: () => hasUserApp,
|
|
1572
|
+
isValidSubject: () => isValidSubject
|
|
1573
|
+
});
|
|
1564
1574
|
import { join as join4 } from "path";
|
|
1565
1575
|
import { readFileSync as readFileSync3 } from "fs";
|
|
1566
1576
|
function readPackageJson(dir) {
|
|
@@ -1594,12 +1604,22 @@ function getOrderedModulesInternal() {
|
|
|
1594
1604
|
moduleStore.modules.forEach(visit);
|
|
1595
1605
|
return sorted;
|
|
1596
1606
|
}
|
|
1607
|
+
function getModule(name) {
|
|
1608
|
+
const mod = moduleStore.modules.find((m) => m.name === name);
|
|
1609
|
+
return mod ? toModuleManifest(mod) : void 0;
|
|
1610
|
+
}
|
|
1611
|
+
function getPlugin(name) {
|
|
1612
|
+
return moduleStore.plugins.get(name);
|
|
1613
|
+
}
|
|
1597
1614
|
function getPlugins() {
|
|
1598
1615
|
return [...moduleStore.plugins.values()];
|
|
1599
1616
|
}
|
|
1600
1617
|
function getRegisteredSubjects() {
|
|
1601
1618
|
return [...moduleStore.subjects];
|
|
1602
1619
|
}
|
|
1620
|
+
function isValidSubject(subject2) {
|
|
1621
|
+
return moduleStore.subjects.has(subject2);
|
|
1622
|
+
}
|
|
1603
1623
|
function getSubjectForTable(table) {
|
|
1604
1624
|
return moduleStore.tableToSubject.get(table);
|
|
1605
1625
|
}
|
|
@@ -1646,10 +1666,10 @@ function getPluginByCode(code) {
|
|
|
1646
1666
|
function hasPluginByCode(code) {
|
|
1647
1667
|
return moduleStore.pluginsByCode.has(code);
|
|
1648
1668
|
}
|
|
1649
|
-
var
|
|
1650
|
-
"src/engine/queries.ts"() {
|
|
1669
|
+
var init_module_queries = __esm({
|
|
1670
|
+
"src/engine/module-queries.ts"() {
|
|
1651
1671
|
"use strict";
|
|
1652
|
-
|
|
1672
|
+
init_module_store();
|
|
1653
1673
|
init_paths();
|
|
1654
1674
|
}
|
|
1655
1675
|
});
|
|
@@ -2133,12 +2153,16 @@ var init_definitions = __esm({
|
|
|
2133
2153
|
labelPlural: { en: "Masters", es: "Maestros" },
|
|
2134
2154
|
labelField: "label",
|
|
2135
2155
|
timestamps: true,
|
|
2156
|
+
availableDisplayModes: ["board"],
|
|
2157
|
+
groupBy: "type",
|
|
2158
|
+
groupableFields: ["type"],
|
|
2159
|
+
//columnDragFields: ['is_active'],
|
|
2136
2160
|
fields: {
|
|
2137
2161
|
id: useTextField2({
|
|
2138
2162
|
label: { en: "ID", es: "ID" },
|
|
2139
2163
|
required: true,
|
|
2140
2164
|
size: 100,
|
|
2141
|
-
|
|
2165
|
+
hidden: true,
|
|
2142
2166
|
meta: { sortable: true }
|
|
2143
2167
|
}),
|
|
2144
2168
|
type: useTextField2({
|
|
@@ -2159,9 +2183,20 @@ var init_definitions = __esm({
|
|
|
2159
2183
|
is_active: isActiveField,
|
|
2160
2184
|
metadata: useJsonField({
|
|
2161
2185
|
label: { en: "Metadata", es: "Metadatos" },
|
|
2162
|
-
hint: {
|
|
2186
|
+
hint: {
|
|
2187
|
+
en: "Type-specific fields (symbol, flag, etc.)",
|
|
2188
|
+
es: "Campos espec\xEDficos del tipo"
|
|
2189
|
+
}
|
|
2163
2190
|
})
|
|
2164
2191
|
},
|
|
2192
|
+
hooks: () => ({
|
|
2193
|
+
beforeCreate: async (data) => {
|
|
2194
|
+
if (data["type"] && data["code"] && !data["id"]) {
|
|
2195
|
+
data["id"] = `${data["type"]}:${data["code"]}`;
|
|
2196
|
+
}
|
|
2197
|
+
return data;
|
|
2198
|
+
}
|
|
2199
|
+
}),
|
|
2165
2200
|
defaultSort: { field: "order", order: "asc" },
|
|
2166
2201
|
indexes: [{ columns: ["type", "code"], unique: true }],
|
|
2167
2202
|
casl: { subject: "Master", permissions: masterCaslPermissions }
|
|
@@ -2170,6 +2205,10 @@ var init_definitions = __esm({
|
|
|
2170
2205
|
});
|
|
2171
2206
|
|
|
2172
2207
|
// src/modules/masters/registry.ts
|
|
2208
|
+
var registry_exports = {};
|
|
2209
|
+
__export(registry_exports, {
|
|
2210
|
+
createMasterRegistry: () => createMasterRegistry
|
|
2211
|
+
});
|
|
2173
2212
|
function createMasterRegistry() {
|
|
2174
2213
|
const registrations = [];
|
|
2175
2214
|
return {
|
|
@@ -8848,15 +8887,18 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8848
8887
|
const meta = field["meta"];
|
|
8849
8888
|
return meta?.["sortable"] === true && !field["hidden"];
|
|
8850
8889
|
});
|
|
8890
|
+
const explicitGroupable = def["groupableFields"];
|
|
8851
8891
|
const groupableInputTypes = ["select", "switch", "checkbox", "radio", "tags"];
|
|
8852
|
-
const
|
|
8892
|
+
const autoGroupableFields = fieldEntries.filter(([, f]) => {
|
|
8853
8893
|
const field = f;
|
|
8854
8894
|
const inputType = field["input"];
|
|
8855
8895
|
return groupableInputTypes.includes(inputType ?? "") && !field["hidden"];
|
|
8856
8896
|
});
|
|
8897
|
+
const resolvedGroupableFields = explicitGroupable ?? (autoGroupableFields.length > 0 ? autoGroupableFields.map(([name]) => name) : void 0);
|
|
8857
8898
|
const entityType = def["type"] ?? "collection";
|
|
8858
8899
|
const explicitDisplayMode = def["displayMode"];
|
|
8859
|
-
const
|
|
8900
|
+
const explicitAvailableModes = def["availableDisplayModes"];
|
|
8901
|
+
const defaultDisplayMode = explicitDisplayMode ?? (explicitAvailableModes?.length === 1 ? explicitAvailableModes[0] : void 0) ?? (["tree", "dag"].includes(entityType) ? "tree" : "table");
|
|
8860
8902
|
const entityIdent = def["table"] ?? def["key"];
|
|
8861
8903
|
return {
|
|
8862
8904
|
id: def._id,
|
|
@@ -8876,9 +8918,11 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8876
8918
|
displayMode: explicitDisplayMode,
|
|
8877
8919
|
defaultDisplayMode,
|
|
8878
8920
|
availableDisplayModes: (() => {
|
|
8921
|
+
const explicit = def["availableDisplayModes"];
|
|
8922
|
+
if (explicit?.length) return explicit;
|
|
8879
8923
|
const modes = ["table", "list", "masonry"];
|
|
8880
8924
|
if (["tree", "dag"].includes(entityType)) modes.push("tree");
|
|
8881
|
-
if (
|
|
8925
|
+
if ((resolvedGroupableFields?.length ?? 0) > 0) modes.push("board");
|
|
8882
8926
|
if (def["calendarFrom"]) modes.push("calendar");
|
|
8883
8927
|
return modes;
|
|
8884
8928
|
})(),
|
|
@@ -8888,10 +8932,8 @@ function toEntityDefinitionDTO(def, _engine, moduleName) {
|
|
|
8888
8932
|
value: name,
|
|
8889
8933
|
label: f["label"]
|
|
8890
8934
|
})),
|
|
8891
|
-
groupableFields:
|
|
8892
|
-
|
|
8893
|
-
label: f["label"]
|
|
8894
|
-
})) : void 0,
|
|
8935
|
+
groupableFields: resolvedGroupableFields,
|
|
8936
|
+
columnDragFields: def["columnDragFields"],
|
|
8895
8937
|
groupBy: def["groupBy"],
|
|
8896
8938
|
subgroupBy: def["subgroupBy"],
|
|
8897
8939
|
calendarFrom: def["calendarFrom"],
|
|
@@ -8931,21 +8973,6 @@ function toModuleDTO(mod, ctx) {
|
|
|
8931
8973
|
hasInit: !!mod.init
|
|
8932
8974
|
};
|
|
8933
8975
|
}
|
|
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
8976
|
var init_system_helpers = __esm({
|
|
8950
8977
|
"src/modules/system/system.helpers.ts"() {
|
|
8951
8978
|
"use strict";
|
|
@@ -9180,7 +9207,8 @@ function createSystemController(ctx) {
|
|
|
9180
9207
|
const plugins = engine.getPlugins();
|
|
9181
9208
|
const body = {
|
|
9182
9209
|
version: manifest.version,
|
|
9183
|
-
plugins: plugins.map((p) => p.code)
|
|
9210
|
+
plugins: plugins.map((p) => p.code),
|
|
9211
|
+
locales: ctx.locales
|
|
9184
9212
|
};
|
|
9185
9213
|
res.json(body);
|
|
9186
9214
|
}
|
|
@@ -10067,7 +10095,6 @@ var SYSTEM_TABLES, factoryResetAction;
|
|
|
10067
10095
|
var init_factory_reset_action = __esm({
|
|
10068
10096
|
"src/modules/system/actions/factory-reset.action.ts"() {
|
|
10069
10097
|
"use strict";
|
|
10070
|
-
init_system_helpers();
|
|
10071
10098
|
SYSTEM_TABLES = /* @__PURE__ */ new Set([
|
|
10072
10099
|
"_nexus_migrations",
|
|
10073
10100
|
"_nexus_migration_lock",
|
|
@@ -10110,8 +10137,8 @@ var init_factory_reset_action = __esm({
|
|
|
10110
10137
|
source: "core:system",
|
|
10111
10138
|
action: "factory_reset",
|
|
10112
10139
|
actorId: authReq.user?.id,
|
|
10113
|
-
ip: req
|
|
10114
|
-
userAgent: req
|
|
10140
|
+
ip: req?.ip,
|
|
10141
|
+
userAgent: req?.headers["user-agent"]
|
|
10115
10142
|
});
|
|
10116
10143
|
await new Promise((resolve2) => setImmediate(resolve2));
|
|
10117
10144
|
const allTables = await getAllTables(knex3);
|
|
@@ -10149,11 +10176,11 @@ var init_factory_reset_action = __esm({
|
|
|
10149
10176
|
} catch {
|
|
10150
10177
|
}
|
|
10151
10178
|
ctx.core.logger.info({ tables: dataTables.length }, "All data tables cleared");
|
|
10152
|
-
const modules =
|
|
10179
|
+
const modules = ctx.engine.getModules();
|
|
10153
10180
|
let modulesSeeded = 0;
|
|
10154
10181
|
for (const mod of modules) {
|
|
10155
10182
|
try {
|
|
10156
|
-
const seeded = await
|
|
10183
|
+
const seeded = await ctx.db.seedModule(mod);
|
|
10157
10184
|
if (seeded) modulesSeeded++;
|
|
10158
10185
|
} catch (err) {
|
|
10159
10186
|
ctx.core.logger.error({ module: mod.name, err }, "Seed failed during factory reset");
|
|
@@ -10207,8 +10234,8 @@ var init_restart_server_action = __esm({
|
|
|
10207
10234
|
source: "core:system",
|
|
10208
10235
|
action: "server_restart",
|
|
10209
10236
|
actorId: authReq.user?.id,
|
|
10210
|
-
ip: req
|
|
10211
|
-
userAgent: req
|
|
10237
|
+
ip: req?.ip,
|
|
10238
|
+
userAgent: req?.headers["user-agent"]
|
|
10212
10239
|
});
|
|
10213
10240
|
setTimeout(() => process.exit(0), 500);
|
|
10214
10241
|
return { success: true, message: "Server is restarting..." };
|
|
@@ -11830,7 +11857,7 @@ function createUploadMiddleware(ctx, options) {
|
|
|
11830
11857
|
const rateLimit2 = ctx.core.middleware.rateLimit({
|
|
11831
11858
|
windowMs: 60 * 1e3,
|
|
11832
11859
|
max: 20,
|
|
11833
|
-
message: "
|
|
11860
|
+
message: "Too many uploads, try again in 1 minute"
|
|
11834
11861
|
});
|
|
11835
11862
|
const upload = multer({
|
|
11836
11863
|
storage: multer.memoryStorage(),
|
|
@@ -12077,7 +12104,7 @@ function createStorageRoutes(ctx) {
|
|
|
12077
12104
|
}
|
|
12078
12105
|
res.status(201).json(results);
|
|
12079
12106
|
};
|
|
12080
|
-
const uploadRateLimit = ctx.core.middleware.rateLimit({ windowMs: 60 * 1e3, max: 20, message: "
|
|
12107
|
+
const uploadRateLimit = ctx.core.middleware.rateLimit({ windowMs: 60 * 1e3, max: 20, message: "Too many uploads, try again in 1 minute" });
|
|
12081
12108
|
if (auth) {
|
|
12082
12109
|
router.post("/upload/multiple", uploadRateLimit, auth, upload.array("files", 10), uploadMultiple);
|
|
12083
12110
|
} else {
|
|
@@ -12375,7 +12402,7 @@ var init_users_entity = __esm({
|
|
|
12375
12402
|
],
|
|
12376
12403
|
nullable: true,
|
|
12377
12404
|
meta: { sortable: true },
|
|
12378
|
-
defaultValue: "
|
|
12405
|
+
defaultValue: "en"
|
|
12379
12406
|
}),
|
|
12380
12407
|
timezone: useSelectField9({
|
|
12381
12408
|
label: { en: "Timezone", es: "Zona horaria" },
|
|
@@ -12453,7 +12480,7 @@ var init_users_entity = __esm({
|
|
|
12453
12480
|
middleware: (ctx) => ctx.core.middleware.rateLimit({
|
|
12454
12481
|
windowMs: 15 * 60 * 1e3,
|
|
12455
12482
|
max: 5,
|
|
12456
|
-
message: "
|
|
12483
|
+
message: "Too many attempts, try again in 15 minutes"
|
|
12457
12484
|
}),
|
|
12458
12485
|
handler: async (ctx, input) => {
|
|
12459
12486
|
const {
|
|
@@ -16635,7 +16662,7 @@ var init_plugins_entity = __esm({
|
|
|
16635
16662
|
label: "Plugins",
|
|
16636
16663
|
icon: "mdi:puzzle",
|
|
16637
16664
|
labelField: "code",
|
|
16638
|
-
routePrefix: "/
|
|
16665
|
+
routePrefix: "/",
|
|
16639
16666
|
defaultSort: { field: "name", order: "asc" },
|
|
16640
16667
|
fields: {
|
|
16641
16668
|
name: useTextField12({
|
|
@@ -17048,12 +17075,12 @@ var init_loader = __esm({
|
|
|
17048
17075
|
"src/engine/loader.ts"() {
|
|
17049
17076
|
"use strict";
|
|
17050
17077
|
init_registry();
|
|
17051
|
-
|
|
17078
|
+
init_definition_extractors();
|
|
17052
17079
|
init_modules();
|
|
17053
17080
|
}
|
|
17054
17081
|
});
|
|
17055
17082
|
|
|
17056
|
-
// src/engine/
|
|
17083
|
+
// src/engine/subject-extractor.ts
|
|
17057
17084
|
function getModuleSubjects(mod) {
|
|
17058
17085
|
const subjects = /* @__PURE__ */ new Set();
|
|
17059
17086
|
for (const def of mod.definitions ?? []) {
|
|
@@ -17062,10 +17089,10 @@ function getModuleSubjects(mod) {
|
|
|
17062
17089
|
}
|
|
17063
17090
|
return [...subjects];
|
|
17064
17091
|
}
|
|
17065
|
-
var
|
|
17066
|
-
"src/engine/
|
|
17092
|
+
var init_subject_extractor = __esm({
|
|
17093
|
+
"src/engine/subject-extractor.ts"() {
|
|
17067
17094
|
"use strict";
|
|
17068
|
-
|
|
17095
|
+
init_definition_extractors();
|
|
17069
17096
|
}
|
|
17070
17097
|
});
|
|
17071
17098
|
|
|
@@ -17143,7 +17170,7 @@ function initSocketIO(httpServer, options) {
|
|
|
17143
17170
|
maxHttpBufferSize: 1e6
|
|
17144
17171
|
// 1MB - match Express json body limit
|
|
17145
17172
|
});
|
|
17146
|
-
logger.info({
|
|
17173
|
+
logger.info({ cors: corsOrigin }, "Socket.IO initialized");
|
|
17147
17174
|
io.use((socket, next) => {
|
|
17148
17175
|
const token = socket.handshake.auth?.["token"] || socket.handshake.query?.["token"];
|
|
17149
17176
|
if (token && typeof token === "string" && jwtSecret) {
|
|
@@ -17166,7 +17193,6 @@ function initSocketIO(httpServer, options) {
|
|
|
17166
17193
|
logger.warn({ code: err.code, message: err.message }, "Socket.IO connection error");
|
|
17167
17194
|
});
|
|
17168
17195
|
io.on("connection", handleConnection);
|
|
17169
|
-
logger.info("Socket.IO initialized");
|
|
17170
17196
|
nexusEvents.emitEvent("socket.initialized");
|
|
17171
17197
|
return io;
|
|
17172
17198
|
}
|
|
@@ -17747,6 +17773,12 @@ var init_app_error = __esm({
|
|
|
17747
17773
|
|
|
17748
17774
|
// src/core/abilities/ability.factory.ts
|
|
17749
17775
|
import { AbilityBuilder, createMongoAbility } from "@casl/ability";
|
|
17776
|
+
function setSeedPermissions(perms) {
|
|
17777
|
+
seedPermissions = perms;
|
|
17778
|
+
}
|
|
17779
|
+
function clearSeedPermissions() {
|
|
17780
|
+
seedPermissions = null;
|
|
17781
|
+
}
|
|
17750
17782
|
function setCustomCaslRules(fn) {
|
|
17751
17783
|
customCaslRules = fn;
|
|
17752
17784
|
}
|
|
@@ -17804,16 +17836,28 @@ async function defineAbilityFor(user, roleNames) {
|
|
|
17804
17836
|
if (customCaslRules) {
|
|
17805
17837
|
await customCaslRules(user, { can, cannot });
|
|
17806
17838
|
}
|
|
17839
|
+
if (seedPermissions && !isSuperuser) {
|
|
17840
|
+
for (const roleName of roleNames) {
|
|
17841
|
+
const rolePerms = seedPermissions.get(roleName);
|
|
17842
|
+
if (!rolePerms) continue;
|
|
17843
|
+
for (const [subject2, actions] of rolePerms) {
|
|
17844
|
+
for (const action of actions) {
|
|
17845
|
+
can(action, subject2);
|
|
17846
|
+
}
|
|
17847
|
+
}
|
|
17848
|
+
}
|
|
17849
|
+
}
|
|
17807
17850
|
return build();
|
|
17808
17851
|
}
|
|
17809
17852
|
function packRules(ability) {
|
|
17810
17853
|
return ability.rules;
|
|
17811
17854
|
}
|
|
17812
|
-
var customCaslRules, entityDefinitionsRegistry, SUPERUSER_ROLES;
|
|
17855
|
+
var customCaslRules, seedPermissions, entityDefinitionsRegistry, SUPERUSER_ROLES;
|
|
17813
17856
|
var init_ability_factory = __esm({
|
|
17814
17857
|
"src/core/abilities/ability.factory.ts"() {
|
|
17815
17858
|
"use strict";
|
|
17816
17859
|
init_logger();
|
|
17860
|
+
seedPermissions = null;
|
|
17817
17861
|
entityDefinitionsRegistry = null;
|
|
17818
17862
|
SUPERUSER_ROLES = ["ADMIN", "OWNER"];
|
|
17819
17863
|
}
|
|
@@ -18366,7 +18410,7 @@ var init_sequence = __esm({
|
|
|
18366
18410
|
}
|
|
18367
18411
|
});
|
|
18368
18412
|
|
|
18369
|
-
// src/core/utils/
|
|
18413
|
+
// src/core/utils/safe-json.ts
|
|
18370
18414
|
function safeJsonParse(logger2, jsonString, fallback, context) {
|
|
18371
18415
|
try {
|
|
18372
18416
|
return JSON.parse(jsonString);
|
|
@@ -18375,8 +18419,8 @@ function safeJsonParse(logger2, jsonString, fallback, context) {
|
|
|
18375
18419
|
return fallback;
|
|
18376
18420
|
}
|
|
18377
18421
|
}
|
|
18378
|
-
var
|
|
18379
|
-
"src/core/utils/
|
|
18422
|
+
var init_safe_json = __esm({
|
|
18423
|
+
"src/core/utils/safe-json.ts"() {
|
|
18380
18424
|
"use strict";
|
|
18381
18425
|
}
|
|
18382
18426
|
});
|
|
@@ -18385,14 +18429,15 @@ var init_error_handler = __esm({
|
|
|
18385
18429
|
import express from "express";
|
|
18386
18430
|
import { resolve, join as join9 } from "path";
|
|
18387
18431
|
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
18388
|
-
function createServeSPA(app) {
|
|
18389
|
-
return (endpoint, distPath, options = {}) => {
|
|
18432
|
+
function createServeSPA(app, httpServer) {
|
|
18433
|
+
return async (endpoint, distPath, options = {}) => {
|
|
18390
18434
|
const {
|
|
18391
18435
|
maxAge = "1d",
|
|
18392
18436
|
etag = true,
|
|
18393
18437
|
immutable = false,
|
|
18394
18438
|
index = "index.html",
|
|
18395
|
-
absolute = false
|
|
18439
|
+
absolute = false,
|
|
18440
|
+
viteSrc
|
|
18396
18441
|
} = options;
|
|
18397
18442
|
if (endpoint === "/api" || endpoint.startsWith("/api/")) {
|
|
18398
18443
|
logger.error(`Cannot mount SPA on ${endpoint} - reserved for API routes`);
|
|
@@ -18403,58 +18448,117 @@ function createServeSPA(app) {
|
|
|
18403
18448
|
return;
|
|
18404
18449
|
}
|
|
18405
18450
|
registeredEndpoints.add(endpoint);
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
const projectPath2 = resolve(getProjectPath(), distPath);
|
|
18411
|
-
if (existsSync9(projectPath2)) {
|
|
18412
|
-
resolvedPath = projectPath2;
|
|
18451
|
+
if (env.NODE_ENV === "development" && viteSrc) {
|
|
18452
|
+
const srcPath = resolve(getProjectPath(), viteSrc);
|
|
18453
|
+
if (!existsSync9(srcPath)) {
|
|
18454
|
+
logger.warn({ endpoint, viteSrc, resolved: srcPath }, "Vite source not found \u2014 falling back to static");
|
|
18413
18455
|
} else {
|
|
18414
|
-
|
|
18456
|
+
const mounted = await mountViteDevMiddleware(app, endpoint, srcPath, httpServer);
|
|
18457
|
+
if (mounted) return;
|
|
18415
18458
|
}
|
|
18416
18459
|
}
|
|
18417
|
-
|
|
18418
|
-
|
|
18419
|
-
|
|
18460
|
+
mountStaticSPA(app, endpoint, distPath, { maxAge, etag, immutable, index, absolute });
|
|
18461
|
+
};
|
|
18462
|
+
}
|
|
18463
|
+
async function mountViteDevMiddleware(app, endpoint, srcPath, httpServer) {
|
|
18464
|
+
try {
|
|
18465
|
+
const vite = await import("vite");
|
|
18466
|
+
const apiUrl = env.BACKEND_URL ? `${env.BACKEND_URL}/api/v1` : "/api/v1";
|
|
18467
|
+
const server2 = await vite.createServer({
|
|
18468
|
+
root: srcPath,
|
|
18469
|
+
server: {
|
|
18470
|
+
middlewareMode: true,
|
|
18471
|
+
allowedHosts: true,
|
|
18472
|
+
hmr: httpServer ? { server: httpServer } : true
|
|
18473
|
+
},
|
|
18474
|
+
plugins: [{
|
|
18475
|
+
name: "nexus-config-inject",
|
|
18476
|
+
transformIndexHtml(html) {
|
|
18477
|
+
const config3 = JSON.stringify({ apiUrl });
|
|
18478
|
+
return html.replace("</head>", `<script>window.__NEXUS__=${config3}</script>
|
|
18479
|
+
</head>`);
|
|
18480
|
+
}
|
|
18481
|
+
}],
|
|
18482
|
+
appType: "spa",
|
|
18483
|
+
clearScreen: false
|
|
18484
|
+
});
|
|
18485
|
+
viteServers.push(server2);
|
|
18486
|
+
if (endpoint === "/") {
|
|
18487
|
+
app.use(server2.middlewares);
|
|
18488
|
+
} else {
|
|
18489
|
+
app.use(endpoint, server2.middlewares);
|
|
18420
18490
|
}
|
|
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
|
-
);
|
|
18491
|
+
logger.info({ path: srcPath }, `Vite dev server mounted at ${endpoint} (HMR enabled)`);
|
|
18492
|
+
return true;
|
|
18493
|
+
} catch (err) {
|
|
18494
|
+
if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
|
|
18495
|
+
logger.warn(`vite not installed \u2014 falling back to static serving for ${endpoint}`);
|
|
18496
|
+
return false;
|
|
18436
18497
|
}
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18498
|
+
logger.error({ err }, `Failed to mount Vite dev server at ${endpoint}`);
|
|
18499
|
+
return false;
|
|
18500
|
+
}
|
|
18501
|
+
}
|
|
18502
|
+
function mountStaticSPA(app, endpoint, distPath, options) {
|
|
18503
|
+
const { maxAge, etag, immutable, index, absolute } = options;
|
|
18504
|
+
let resolvedPath;
|
|
18505
|
+
if (absolute) {
|
|
18506
|
+
resolvedPath = distPath;
|
|
18507
|
+
} else {
|
|
18508
|
+
const projectPath2 = resolve(getProjectPath(), distPath);
|
|
18509
|
+
if (existsSync9(projectPath2)) {
|
|
18510
|
+
resolvedPath = projectPath2;
|
|
18447
18511
|
} else {
|
|
18448
|
-
|
|
18449
|
-
|
|
18512
|
+
resolvedPath = resolve(getLibPath(), distPath);
|
|
18513
|
+
}
|
|
18514
|
+
}
|
|
18515
|
+
if (!existsSync9(resolvedPath)) {
|
|
18516
|
+
logger.warn({ endpoint, distPath, hint: "Build the frontend first" }, `SPA directory not found: ${resolvedPath}`);
|
|
18517
|
+
return;
|
|
18518
|
+
}
|
|
18519
|
+
const indexPath = join9(resolvedPath, index);
|
|
18520
|
+
if (!existsSync9(indexPath)) {
|
|
18521
|
+
logger.warn({ endpoint, index }, `Index file not found: ${indexPath}`);
|
|
18522
|
+
}
|
|
18523
|
+
app.use(endpoint, express.static(resolvedPath, { maxAge, etag, immutable }));
|
|
18524
|
+
let injectedHtml = "";
|
|
18525
|
+
if (existsSync9(indexPath)) {
|
|
18526
|
+
const rawHtml = readFileSync5(indexPath, "utf-8");
|
|
18527
|
+
const apiUrl = env.BACKEND_URL ? `${env.BACKEND_URL}/api/v1` : "/api/v1";
|
|
18528
|
+
const nexusConfig = JSON.stringify({ apiUrl });
|
|
18529
|
+
injectedHtml = rawHtml.replace(
|
|
18530
|
+
"</head>",
|
|
18531
|
+
`<script>window.__NEXUS__=${nexusConfig}</script>
|
|
18532
|
+
</head>`
|
|
18533
|
+
);
|
|
18534
|
+
}
|
|
18535
|
+
const fallbackHandler = (_req, res) => {
|
|
18536
|
+
if (!injectedHtml) {
|
|
18537
|
+
res.status(404).send("index.html not found");
|
|
18538
|
+
return;
|
|
18450
18539
|
}
|
|
18451
|
-
|
|
18540
|
+
res.set("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
18541
|
+
res.type("html").send(injectedHtml);
|
|
18452
18542
|
};
|
|
18543
|
+
if (endpoint === "/") {
|
|
18544
|
+
app.get("{*splat}", fallbackHandler);
|
|
18545
|
+
} else {
|
|
18546
|
+
app.get(endpoint, fallbackHandler);
|
|
18547
|
+
app.get(`${endpoint}/{*splat}`, fallbackHandler);
|
|
18548
|
+
}
|
|
18549
|
+
logger.info({ path: resolvedPath }, `SPA mounted at ${endpoint}`);
|
|
18453
18550
|
}
|
|
18454
|
-
function
|
|
18551
|
+
async function resetServeSPA() {
|
|
18552
|
+
for (const server2 of viteServers) {
|
|
18553
|
+
try {
|
|
18554
|
+
await server2.close();
|
|
18555
|
+
} catch {
|
|
18556
|
+
}
|
|
18557
|
+
}
|
|
18558
|
+
viteServers.length = 0;
|
|
18455
18559
|
registeredEndpoints.clear();
|
|
18456
18560
|
}
|
|
18457
|
-
var registeredEndpoints;
|
|
18561
|
+
var registeredEndpoints, viteServers;
|
|
18458
18562
|
var init_spa_handler = __esm({
|
|
18459
18563
|
"src/core/spa-handler.ts"() {
|
|
18460
18564
|
"use strict";
|
|
@@ -18462,6 +18566,7 @@ var init_spa_handler = __esm({
|
|
|
18462
18566
|
init_logger();
|
|
18463
18567
|
init_env();
|
|
18464
18568
|
registeredEndpoints = /* @__PURE__ */ new Set();
|
|
18569
|
+
viteServers = [];
|
|
18465
18570
|
}
|
|
18466
18571
|
});
|
|
18467
18572
|
|
|
@@ -19032,7 +19137,7 @@ var init_core = __esm({
|
|
|
19032
19137
|
init_id();
|
|
19033
19138
|
init_sequence();
|
|
19034
19139
|
init_paths();
|
|
19035
|
-
|
|
19140
|
+
init_safe_json();
|
|
19036
19141
|
init_spa_handler();
|
|
19037
19142
|
init_cache();
|
|
19038
19143
|
init_jwt();
|
|
@@ -19747,7 +19852,9 @@ var init_base_service = __esm({
|
|
|
19747
19852
|
const countResult = await qb.clone().count("* as count").first();
|
|
19748
19853
|
const total = Number(countResult?.count ?? 0);
|
|
19749
19854
|
qb = this.applySortingWithDefaults(qb, query);
|
|
19750
|
-
|
|
19855
|
+
if (limit > 0) {
|
|
19856
|
+
qb = qb.limit(limit).offset(offset);
|
|
19857
|
+
}
|
|
19751
19858
|
const rawItems = await qb;
|
|
19752
19859
|
const items = this.parseJsonFieldsFromArray(rawItems);
|
|
19753
19860
|
const processedItems = await this.afterFindAll(items);
|
|
@@ -19832,7 +19939,7 @@ var init_base_service = __esm({
|
|
|
19832
19939
|
});
|
|
19833
19940
|
}
|
|
19834
19941
|
const total = result.length;
|
|
19835
|
-
const paginatedItems = result.slice(offset, offset + limit);
|
|
19942
|
+
const paginatedItems = limit === 0 ? result : result.slice(offset, offset + limit);
|
|
19836
19943
|
return this.buildPaginatedResult(paginatedItems, total, page, limit);
|
|
19837
19944
|
}
|
|
19838
19945
|
/**
|
|
@@ -20087,14 +20194,14 @@ var init_base_service = __esm({
|
|
|
20087
20194
|
* Build paginated result from items and count
|
|
20088
20195
|
*/
|
|
20089
20196
|
buildPaginatedResult(items, total, page, limit) {
|
|
20090
|
-
const totalPages = Math.ceil(total / limit);
|
|
20197
|
+
const totalPages = limit === 0 ? 1 : Math.ceil(total / limit);
|
|
20091
20198
|
return {
|
|
20092
20199
|
items,
|
|
20093
20200
|
total,
|
|
20094
|
-
page,
|
|
20095
|
-
limit,
|
|
20201
|
+
page: limit === 0 ? 1 : page,
|
|
20202
|
+
limit: limit === 0 ? total : limit,
|
|
20096
20203
|
totalPages,
|
|
20097
|
-
hasNext: page < totalPages
|
|
20204
|
+
hasNext: limit === 0 ? false : page < totalPages
|
|
20098
20205
|
};
|
|
20099
20206
|
}
|
|
20100
20207
|
/**
|
|
@@ -20103,8 +20210,8 @@ var init_base_service = __esm({
|
|
|
20103
20210
|
getPagination(query) {
|
|
20104
20211
|
const maxLimit = query?.maxLimit ?? 100;
|
|
20105
20212
|
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;
|
|
20213
|
+
const limit = query?.limit === 0 ? 0 : Math.min(maxLimit, Math.max(1, query?.limit ?? 20));
|
|
20214
|
+
const offset = limit === 0 ? 0 : (page - 1) * limit;
|
|
20108
20215
|
return { page, limit, offset };
|
|
20109
20216
|
}
|
|
20110
20217
|
/**
|
|
@@ -21751,7 +21858,8 @@ function createEntityController(service, definition, ctx) {
|
|
|
21751
21858
|
async list(req, res) {
|
|
21752
21859
|
checkPermission(req, "read");
|
|
21753
21860
|
const page = Math.max(1, parseInt(req.query["page"]) || 1);
|
|
21754
|
-
const
|
|
21861
|
+
const rawLimit = parseInt(req.query["limit"]);
|
|
21862
|
+
const limit = rawLimit === 0 ? 0 : Math.min(100, Math.max(1, rawLimit || 20));
|
|
21755
21863
|
let filters;
|
|
21756
21864
|
if (req.query["filters"]) {
|
|
21757
21865
|
filters = parseFilters(req.query["filters"], ctx.core.errors);
|
|
@@ -23217,17 +23325,18 @@ async function createModuleRouters(ctx, definitions, modulePrefix) {
|
|
|
23217
23325
|
const runtime = await createEntityRuntimeAsync(ctx, definition);
|
|
23218
23326
|
const route = inferEntityRoutePath(definition);
|
|
23219
23327
|
const entityLabel = resolveLocalized7(definition.label, "en");
|
|
23220
|
-
|
|
23328
|
+
const isExposed = !("expose" in definition && definition.expose === false);
|
|
23329
|
+
if (isExposed && modulePrefix && route === modulePrefix) {
|
|
23221
23330
|
ctx.core.logger.warn(
|
|
23222
23331
|
`Entity "${entityLabel}" inferred route "${route}" duplicates module prefix \u2014 add routePrefix to the entity definition to fix`
|
|
23223
23332
|
);
|
|
23224
23333
|
}
|
|
23225
|
-
if (routeMap.has(route)) {
|
|
23334
|
+
if (isExposed && routeMap.has(route)) {
|
|
23226
23335
|
ctx.core.logger.warn(
|
|
23227
23336
|
`Entity "${entityLabel}" route "${route}" collides with "${routeMap.get(route)}" in the same module`
|
|
23228
23337
|
);
|
|
23229
23338
|
}
|
|
23230
|
-
routeMap.set(route, entityLabel);
|
|
23339
|
+
if (isExposed) routeMap.set(route, entityLabel);
|
|
23231
23340
|
router.use(route, runtime.router);
|
|
23232
23341
|
const key = getServiceKey(definition);
|
|
23233
23342
|
if (ctx.services.has(key)) {
|
|
@@ -23443,7 +23552,7 @@ var init_runtime = __esm({
|
|
|
23443
23552
|
}
|
|
23444
23553
|
});
|
|
23445
23554
|
|
|
23446
|
-
// src/db/
|
|
23555
|
+
// src/db/seed-runner.ts
|
|
23447
23556
|
import { existsSync as existsSync10 } from "fs";
|
|
23448
23557
|
import { join as join10 } from "path";
|
|
23449
23558
|
import { pathToFileURL } from "url";
|
|
@@ -23511,8 +23620,8 @@ function hasSeedData(seed5) {
|
|
|
23511
23620
|
if (!Array.isArray(seed5) && "source" in seed5 && seed5.source === "url") return true;
|
|
23512
23621
|
return Array.isArray(seed5) && seed5.length > 0;
|
|
23513
23622
|
}
|
|
23514
|
-
var
|
|
23515
|
-
"src/db/
|
|
23623
|
+
var init_seed_runner = __esm({
|
|
23624
|
+
"src/db/seed-runner.ts"() {
|
|
23516
23625
|
"use strict";
|
|
23517
23626
|
init_runtime();
|
|
23518
23627
|
init_paths();
|
|
@@ -23615,7 +23724,7 @@ var init_migration_sources = __esm({
|
|
|
23615
23724
|
init_shared();
|
|
23616
23725
|
init_paths();
|
|
23617
23726
|
init_plugin_ops();
|
|
23618
|
-
|
|
23727
|
+
init_module_store();
|
|
23619
23728
|
}
|
|
23620
23729
|
});
|
|
23621
23730
|
|
|
@@ -23948,7 +24057,7 @@ async function runMigrations(knexInstance, sources) {
|
|
|
23948
24057
|
const executedMigrations = await knex3("_nexus_migrations").where({ status: "completed" }).select("name").then((rows) => new Set(rows.map((r) => r.name)));
|
|
23949
24058
|
const pendingMigrations = migrationFiles.filter((m) => !executedMigrations.has(m.name));
|
|
23950
24059
|
if (pendingMigrations.length === 0) {
|
|
23951
|
-
logger.
|
|
24060
|
+
logger.debug("No pending migrations");
|
|
23952
24061
|
return;
|
|
23953
24062
|
}
|
|
23954
24063
|
const batch = await getNextBatch(knex3);
|
|
@@ -24348,6 +24457,27 @@ var init_migration_helpers = __esm({
|
|
|
24348
24457
|
import path2 from "path";
|
|
24349
24458
|
import fs2 from "fs/promises";
|
|
24350
24459
|
import { readFileSync as readFileSync6, mkdirSync as mkdirSync5, realpathSync } from "fs";
|
|
24460
|
+
function getColumnIndexBytes(field) {
|
|
24461
|
+
if (!field?.db) return 255 * MYSQL_BYTES_PER_CHAR;
|
|
24462
|
+
const size = field.db.size ?? 255;
|
|
24463
|
+
if (field.db.type === "text") return 0;
|
|
24464
|
+
if (field.db.type === "string") return size * MYSQL_BYTES_PER_CHAR;
|
|
24465
|
+
if (field.db.type === "integer") return 4;
|
|
24466
|
+
if (field.db.type === "boolean") return 1;
|
|
24467
|
+
if (field.db.type === "datetime" || field.db.type === "date") return 8;
|
|
24468
|
+
if (field.db.type === "uuid") return 16;
|
|
24469
|
+
return size * MYSQL_BYTES_PER_CHAR;
|
|
24470
|
+
}
|
|
24471
|
+
function warnIfIndexExceedsMySQLLimit(table, columns, unique, fields) {
|
|
24472
|
+
if (!fields) return;
|
|
24473
|
+
const totalBytes = columns.reduce((sum, col) => sum + getColumnIndexBytes(fields[col]), 0);
|
|
24474
|
+
if (totalBytes > MYSQL_MAX_INDEX_BYTES) {
|
|
24475
|
+
const indexType = unique ? "UNIQUE" : "INDEX";
|
|
24476
|
+
logger.warn(
|
|
24477
|
+
`${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.`
|
|
24478
|
+
);
|
|
24479
|
+
}
|
|
24480
|
+
}
|
|
24351
24481
|
async function detectSchemaDrift(knexInstance) {
|
|
24352
24482
|
const knex3 = knexInstance ?? getDb();
|
|
24353
24483
|
const entities = getAllPersistentEntities();
|
|
@@ -24455,6 +24585,7 @@ function computeSchemaDiff(entities, currentSchema, options) {
|
|
|
24455
24585
|
for (const idx of entityIndexes) {
|
|
24456
24586
|
const key = normalizeKey(idx.columns, !!idx.unique);
|
|
24457
24587
|
if (!currentKeys.has(key)) {
|
|
24588
|
+
warnIfIndexExceedsMySQLLimit(tableName, idx.columns, !!idx.unique, entity.fields);
|
|
24458
24589
|
diff.newIndexes.push({ columns: idx.columns, unique: !!idx.unique });
|
|
24459
24590
|
}
|
|
24460
24591
|
}
|
|
@@ -24626,7 +24757,7 @@ function formatDriftMessage(drift) {
|
|
|
24626
24757
|
lines.push('Run "pnpm migrate:dev" to generate and apply migrations.');
|
|
24627
24758
|
return lines.join("\n");
|
|
24628
24759
|
}
|
|
24629
|
-
var PERSISTENT_TYPES;
|
|
24760
|
+
var MYSQL_MAX_INDEX_BYTES, MYSQL_BYTES_PER_CHAR, PERSISTENT_TYPES;
|
|
24630
24761
|
var init_migration_generator = __esm({
|
|
24631
24762
|
"src/db/migration-generator.ts"() {
|
|
24632
24763
|
"use strict";
|
|
@@ -24635,9 +24766,11 @@ var init_migration_generator = __esm({
|
|
|
24635
24766
|
init_paths();
|
|
24636
24767
|
init_schema_reader();
|
|
24637
24768
|
init_engine();
|
|
24638
|
-
|
|
24769
|
+
init_module_queries();
|
|
24639
24770
|
init_migration_helpers();
|
|
24640
|
-
|
|
24771
|
+
init_module_store();
|
|
24772
|
+
MYSQL_MAX_INDEX_BYTES = 3072;
|
|
24773
|
+
MYSQL_BYTES_PER_CHAR = 4;
|
|
24641
24774
|
PERSISTENT_TYPES = /* @__PURE__ */ new Set([
|
|
24642
24775
|
"collection",
|
|
24643
24776
|
"tree",
|
|
@@ -26211,7 +26344,7 @@ var init_db = __esm({
|
|
|
26211
26344
|
init_schema_helpers();
|
|
26212
26345
|
init_sql_utils();
|
|
26213
26346
|
init_sqlite_compat();
|
|
26214
|
-
|
|
26347
|
+
init_seed_runner();
|
|
26215
26348
|
init_ensure_system_tables();
|
|
26216
26349
|
init_migration_sources();
|
|
26217
26350
|
init_migration_runner();
|
|
@@ -26475,8 +26608,11 @@ var init_events_api = __esm({
|
|
|
26475
26608
|
|
|
26476
26609
|
// src/engine/context.ts
|
|
26477
26610
|
import { ForbiddenError as CASLForbiddenError3, subject } from "@casl/ability";
|
|
26478
|
-
import { DEFAULT_TENANT_ID as DEFAULT_TENANT_ID2 } from "@gzl10/nexus-sdk";
|
|
26611
|
+
import { DEFAULT_TENANT_ID as DEFAULT_TENANT_ID2, DEFAULT_LOCALES } from "@gzl10/nexus-sdk";
|
|
26479
26612
|
import { Redis as Redis2 } from "ioredis";
|
|
26613
|
+
function setLocales(locales) {
|
|
26614
|
+
platformLocales = locales;
|
|
26615
|
+
}
|
|
26480
26616
|
function getSharedCacheManager() {
|
|
26481
26617
|
if (!sharedCacheManager) {
|
|
26482
26618
|
const redisUrl = env.REDIS_URL;
|
|
@@ -26552,7 +26688,7 @@ function createModuleContext() {
|
|
|
26552
26688
|
const defaultAdapter = createKnexAdapter(knex3);
|
|
26553
26689
|
const defaultSchemaAdapter = createKnexSchemaAdapter(knex3);
|
|
26554
26690
|
adaptersRegistry["temp"] = { data: getSharedTempAdapter() };
|
|
26555
|
-
logger.
|
|
26691
|
+
logger.trace(env.REDIS_URL ? "Temp adapter: Redis (shared)" : "Temp adapter: InMemory (shared)");
|
|
26556
26692
|
const middleware = {
|
|
26557
26693
|
validate,
|
|
26558
26694
|
rateLimit: createRateLimit,
|
|
@@ -26660,7 +26796,9 @@ function createModuleContext() {
|
|
|
26660
26796
|
throw new Error(`Knex connection for adapter "${adapter}" not found. Available: ${Object.keys(knexConnections).join(", ")}`);
|
|
26661
26797
|
}
|
|
26662
26798
|
return conn;
|
|
26663
|
-
}
|
|
26799
|
+
},
|
|
26800
|
+
// Placeholder — bound after ctx construction (needs full ModuleContext)
|
|
26801
|
+
seedModule: null
|
|
26664
26802
|
};
|
|
26665
26803
|
const configContext = {
|
|
26666
26804
|
env,
|
|
@@ -26753,7 +26891,8 @@ function createModuleContext() {
|
|
|
26753
26891
|
adapters: adaptersContext,
|
|
26754
26892
|
// Root-level shortcuts for frequently used utilities
|
|
26755
26893
|
events: createEventsApi(nexusEvents, logger),
|
|
26756
|
-
createRouter: () => createRouter()
|
|
26894
|
+
createRouter: () => createRouter(),
|
|
26895
|
+
locales: platformLocales
|
|
26757
26896
|
};
|
|
26758
26897
|
servicesRegistry["cacheManager"] = getSharedCacheManager();
|
|
26759
26898
|
ctx.runtime = {
|
|
@@ -26762,9 +26901,10 @@ function createModuleContext() {
|
|
|
26762
26901
|
createEntityController: (service, def) => createEntityController(service, def, ctx),
|
|
26763
26902
|
createEntityRouter: (controller, def) => createEntityRouter(controller, def, ctx)
|
|
26764
26903
|
};
|
|
26904
|
+
ctx.db.seedModule = (mod) => runModuleSeed(mod, ctx);
|
|
26765
26905
|
return ctx;
|
|
26766
26906
|
}
|
|
26767
|
-
var sharedCacheManager, sharedTempAdapter;
|
|
26907
|
+
var platformLocales, sharedCacheManager, sharedTempAdapter;
|
|
26768
26908
|
var init_context = __esm({
|
|
26769
26909
|
"src/engine/context.ts"() {
|
|
26770
26910
|
"use strict";
|
|
@@ -26777,7 +26917,9 @@ var init_context = __esm({
|
|
|
26777
26917
|
init_plugin_ops();
|
|
26778
26918
|
init_load_config();
|
|
26779
26919
|
init_events_api();
|
|
26920
|
+
init_seed_runner();
|
|
26780
26921
|
init_cache_manager();
|
|
26922
|
+
platformLocales = DEFAULT_LOCALES;
|
|
26781
26923
|
sharedCacheManager = null;
|
|
26782
26924
|
sharedTempAdapter = null;
|
|
26783
26925
|
}
|
|
@@ -26788,11 +26930,11 @@ var init_engine = __esm({
|
|
|
26788
26930
|
"src/engine/index.ts"() {
|
|
26789
26931
|
"use strict";
|
|
26790
26932
|
init_registry();
|
|
26791
|
-
|
|
26933
|
+
init_module_queries();
|
|
26792
26934
|
init_loader();
|
|
26793
|
-
|
|
26794
|
-
|
|
26795
|
-
|
|
26935
|
+
init_module_store();
|
|
26936
|
+
init_subject_extractor();
|
|
26937
|
+
init_definition_extractors();
|
|
26796
26938
|
init_context();
|
|
26797
26939
|
}
|
|
26798
26940
|
});
|
|
@@ -27328,7 +27470,7 @@ async function createApp(options = {}) {
|
|
|
27328
27470
|
// Only accept arrays and objects
|
|
27329
27471
|
}));
|
|
27330
27472
|
app.use(cookieParser());
|
|
27331
|
-
const serveSPA = createServeSPA(app);
|
|
27473
|
+
const serveSPA = createServeSPA(app, options.httpServer);
|
|
27332
27474
|
if (options.beforeRoutes) {
|
|
27333
27475
|
const result = options.beforeRoutes(app, serveSPA);
|
|
27334
27476
|
if (result instanceof Promise) {
|
|
@@ -27422,11 +27564,11 @@ async function createApp(options = {}) {
|
|
|
27422
27564
|
});
|
|
27423
27565
|
const sortedSpas = [...servedSpas].sort((a, b) => b.endpoint.length - a.endpoint.length);
|
|
27424
27566
|
for (const spa of sortedSpas) {
|
|
27425
|
-
serveSPA(spa.endpoint, spa.path, spa);
|
|
27567
|
+
await serveSPA(spa.endpoint, spa.path, { ...spa, viteSrc: spa.viteSrc });
|
|
27426
27568
|
}
|
|
27427
27569
|
const { ui } = getConfig();
|
|
27428
27570
|
if (ui.enabled) {
|
|
27429
|
-
serveSPA(ui.base, ui.path);
|
|
27571
|
+
await serveSPA(ui.base, ui.path, { viteSrc: "../ui" });
|
|
27430
27572
|
}
|
|
27431
27573
|
app.use(errorMiddleware);
|
|
27432
27574
|
return app;
|
|
@@ -27452,58 +27594,32 @@ var init_app = __esm({
|
|
|
27452
27594
|
}
|
|
27453
27595
|
});
|
|
27454
27596
|
|
|
27455
|
-
// src/core/utils/
|
|
27597
|
+
// src/core/utils/port-check.ts
|
|
27456
27598
|
import net from "net";
|
|
27457
27599
|
import { execSync } from "child_process";
|
|
27458
27600
|
function findProcessOnPort(port) {
|
|
27459
27601
|
try {
|
|
27460
27602
|
const output = execSync(`lsof -ti :${port} 2>/dev/null`, { encoding: "utf-8" });
|
|
27461
27603
|
const pid = parseInt(output.trim().split("\n")[0] ?? "", 10);
|
|
27462
|
-
|
|
27604
|
+
if (isNaN(pid)) return null;
|
|
27605
|
+
let name = "unknown";
|
|
27606
|
+
try {
|
|
27607
|
+
name = execSync(`ps -o comm= -p ${pid} 2>/dev/null`, { encoding: "utf-8" }).trim();
|
|
27608
|
+
} catch {
|
|
27609
|
+
}
|
|
27610
|
+
return { pid, name };
|
|
27463
27611
|
} catch {
|
|
27464
27612
|
return null;
|
|
27465
27613
|
}
|
|
27466
27614
|
}
|
|
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
27615
|
async function checkPortAvailable(port, host = "0.0.0.0") {
|
|
27493
27616
|
return new Promise((resolve2, reject) => {
|
|
27494
27617
|
const server2 = net.createServer();
|
|
27495
27618
|
server2.once("error", (err) => {
|
|
27496
27619
|
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`));
|
|
27620
|
+
const proc = findProcessOnPort(port);
|
|
27621
|
+
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`;
|
|
27622
|
+
reject(new Error(msg));
|
|
27507
27623
|
} else {
|
|
27508
27624
|
reject(err);
|
|
27509
27625
|
}
|
|
@@ -27514,10 +27630,9 @@ async function checkPortAvailable(port, host = "0.0.0.0") {
|
|
|
27514
27630
|
server2.listen(port, host);
|
|
27515
27631
|
});
|
|
27516
27632
|
}
|
|
27517
|
-
var
|
|
27518
|
-
"src/core/utils/
|
|
27633
|
+
var init_port_check = __esm({
|
|
27634
|
+
"src/core/utils/port-check.ts"() {
|
|
27519
27635
|
"use strict";
|
|
27520
|
-
init_logger();
|
|
27521
27636
|
}
|
|
27522
27637
|
});
|
|
27523
27638
|
|
|
@@ -27612,6 +27727,150 @@ var init_tunnel = __esm({
|
|
|
27612
27727
|
}
|
|
27613
27728
|
});
|
|
27614
27729
|
|
|
27730
|
+
// src/db/seed-context.ts
|
|
27731
|
+
var seed_context_exports = {};
|
|
27732
|
+
__export(seed_context_exports, {
|
|
27733
|
+
createSeedContext: () => createSeedContext
|
|
27734
|
+
});
|
|
27735
|
+
function createSeedContext(deps) {
|
|
27736
|
+
const { knex: db2, generateId: generateId4, hashPassword: hashPassword2, pluginPrefixes, logger: logger2 } = deps;
|
|
27737
|
+
const permissionsMap = /* @__PURE__ */ new Map();
|
|
27738
|
+
const seedContext = {
|
|
27739
|
+
masters: {
|
|
27740
|
+
register(type2, entries, options) {
|
|
27741
|
+
deps.masterRegistry.register(type2, entries, options);
|
|
27742
|
+
}
|
|
27743
|
+
},
|
|
27744
|
+
roles: {
|
|
27745
|
+
async add(role) {
|
|
27746
|
+
const hasTable = await db2.schema.hasTable("roles");
|
|
27747
|
+
if (!hasTable) return;
|
|
27748
|
+
const existing = await db2("roles").where({ name: role.name }).first();
|
|
27749
|
+
if (!existing) {
|
|
27750
|
+
const description = role.description ? JSON.stringify(typeof role.description === "string" ? { en: role.description } : role.description) : null;
|
|
27751
|
+
await db2("roles").insert({
|
|
27752
|
+
id: generateId4(),
|
|
27753
|
+
name: role.name,
|
|
27754
|
+
description,
|
|
27755
|
+
is_system: role.is_system ?? false
|
|
27756
|
+
});
|
|
27757
|
+
logger2.info({ role: role.name }, "Seeded role");
|
|
27758
|
+
}
|
|
27759
|
+
if (role.permissions) {
|
|
27760
|
+
let rolePerms = permissionsMap.get(role.name);
|
|
27761
|
+
if (!rolePerms) {
|
|
27762
|
+
rolePerms = /* @__PURE__ */ new Map();
|
|
27763
|
+
permissionsMap.set(role.name, rolePerms);
|
|
27764
|
+
}
|
|
27765
|
+
for (const [subject2, actions] of Object.entries(role.permissions)) {
|
|
27766
|
+
const normalized = subject2.charAt(0).toUpperCase() + subject2.slice(1);
|
|
27767
|
+
rolePerms.set(normalized, actions);
|
|
27768
|
+
}
|
|
27769
|
+
}
|
|
27770
|
+
}
|
|
27771
|
+
},
|
|
27772
|
+
users: {
|
|
27773
|
+
async add(user) {
|
|
27774
|
+
const hasTable = await db2.schema.hasTable("users");
|
|
27775
|
+
if (!hasTable) return;
|
|
27776
|
+
const existing = await db2("users").where({ email: user.email }).first();
|
|
27777
|
+
if (existing) return;
|
|
27778
|
+
const userId = generateId4();
|
|
27779
|
+
await db2("users").insert({
|
|
27780
|
+
id: userId,
|
|
27781
|
+
type: user.type ?? "human",
|
|
27782
|
+
email: user.email,
|
|
27783
|
+
password: await hashPassword2(user.password),
|
|
27784
|
+
name: user.name ?? user.email
|
|
27785
|
+
});
|
|
27786
|
+
if (user.roles?.length) {
|
|
27787
|
+
for (const roleName of user.roles) {
|
|
27788
|
+
const role = await db2("roles").where({ name: roleName }).first();
|
|
27789
|
+
if (role) {
|
|
27790
|
+
await db2("user_roles").insert({
|
|
27791
|
+
id: generateId4(),
|
|
27792
|
+
user_id: userId,
|
|
27793
|
+
role_id: role.id
|
|
27794
|
+
});
|
|
27795
|
+
} else {
|
|
27796
|
+
logger2.warn({ role: roleName, user: user.email }, "Role not found, skipping assignment");
|
|
27797
|
+
}
|
|
27798
|
+
}
|
|
27799
|
+
}
|
|
27800
|
+
logger2.info({ email: user.email, roles: user.roles }, "Seeded user");
|
|
27801
|
+
}
|
|
27802
|
+
},
|
|
27803
|
+
plugin(pluginName) {
|
|
27804
|
+
return {
|
|
27805
|
+
entity(entityName) {
|
|
27806
|
+
return {
|
|
27807
|
+
async upsert(data, options) {
|
|
27808
|
+
let prefix = pluginPrefixes.get(pluginName) ?? "";
|
|
27809
|
+
if (!prefix) {
|
|
27810
|
+
for (const [key2, pfx] of pluginPrefixes) {
|
|
27811
|
+
if (pluginName === key2 || pluginName.endsWith(`-${key2}`)) {
|
|
27812
|
+
prefix = pfx;
|
|
27813
|
+
break;
|
|
27814
|
+
}
|
|
27815
|
+
}
|
|
27816
|
+
}
|
|
27817
|
+
const fullTable = `${prefix}${entityName}`;
|
|
27818
|
+
const hasTable = await db2.schema.hasTable(fullTable);
|
|
27819
|
+
if (!hasTable) {
|
|
27820
|
+
logger2.warn({ table: fullTable, plugin: pluginName }, "Table not found for plugin entity seed");
|
|
27821
|
+
return 0;
|
|
27822
|
+
}
|
|
27823
|
+
const key = options?.key ?? "id";
|
|
27824
|
+
let seeded = 0;
|
|
27825
|
+
for (const row of data) {
|
|
27826
|
+
const keyValue = row[key];
|
|
27827
|
+
if (keyValue != null) {
|
|
27828
|
+
const existing = await db2(fullTable).where({ [key]: keyValue }).first();
|
|
27829
|
+
if (existing) continue;
|
|
27830
|
+
}
|
|
27831
|
+
const insertData = { ...row };
|
|
27832
|
+
if (key === "id" && !insertData["id"]) {
|
|
27833
|
+
insertData["id"] = generateId4();
|
|
27834
|
+
}
|
|
27835
|
+
await db2(fullTable).insert(insertData);
|
|
27836
|
+
seeded++;
|
|
27837
|
+
}
|
|
27838
|
+
if (seeded > 0) {
|
|
27839
|
+
logger2.info({ table: fullTable, seeded }, "Seeded plugin entity data");
|
|
27840
|
+
}
|
|
27841
|
+
return seeded;
|
|
27842
|
+
}
|
|
27843
|
+
};
|
|
27844
|
+
}
|
|
27845
|
+
};
|
|
27846
|
+
},
|
|
27847
|
+
async raw(table, data) {
|
|
27848
|
+
logger2.warn({ table }, "Using seed.raw() \u2014 prefer typed helpers when available");
|
|
27849
|
+
const hasTable = await db2.schema.hasTable(table);
|
|
27850
|
+
if (!hasTable) {
|
|
27851
|
+
logger2.warn({ table }, "Table not found for raw seed");
|
|
27852
|
+
return 0;
|
|
27853
|
+
}
|
|
27854
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
27855
|
+
await db2(table).insert(rows);
|
|
27856
|
+
return rows.length;
|
|
27857
|
+
}
|
|
27858
|
+
};
|
|
27859
|
+
return {
|
|
27860
|
+
ctx: seedContext,
|
|
27861
|
+
flushPermissions: () => {
|
|
27862
|
+
if (permissionsMap.size > 0 && deps.onPermissionsCollected) {
|
|
27863
|
+
deps.onPermissionsCollected(permissionsMap);
|
|
27864
|
+
}
|
|
27865
|
+
}
|
|
27866
|
+
};
|
|
27867
|
+
}
|
|
27868
|
+
var init_seed_context = __esm({
|
|
27869
|
+
"src/db/seed-context.ts"() {
|
|
27870
|
+
"use strict";
|
|
27871
|
+
}
|
|
27872
|
+
});
|
|
27873
|
+
|
|
27615
27874
|
// src/core/server.ts
|
|
27616
27875
|
var server_exports = {};
|
|
27617
27876
|
__export(server_exports, {
|
|
@@ -27620,7 +27879,9 @@ __export(server_exports, {
|
|
|
27620
27879
|
start: () => start,
|
|
27621
27880
|
stop: () => stop
|
|
27622
27881
|
});
|
|
27882
|
+
import http from "http";
|
|
27623
27883
|
import { entityRoom as entityRoom6 } from "@gzl10/nexus-sdk";
|
|
27884
|
+
import { DEFAULT_LOCALES as DEFAULT_LOCALES2 } from "@gzl10/nexus-sdk";
|
|
27624
27885
|
async function runMigrationsAndSeeds(config3) {
|
|
27625
27886
|
initLoggerService(getLoggerConfig());
|
|
27626
27887
|
setLoggerInstance(getPinoLogger());
|
|
@@ -27673,7 +27934,7 @@ async function runMigrationsAndSeeds(config3) {
|
|
|
27673
27934
|
const sources = buildMigrationSources();
|
|
27674
27935
|
const migrationFiles = await loadAllMigrationFiles(sources);
|
|
27675
27936
|
if (migrationFiles.length > 0) {
|
|
27676
|
-
logger.info({
|
|
27937
|
+
logger.info({ sources: sources.length, files: migrationFiles.length }, "Running migration deploy...");
|
|
27677
27938
|
try {
|
|
27678
27939
|
await runMigrations(void 0, sources);
|
|
27679
27940
|
} catch (err) {
|
|
@@ -27682,7 +27943,7 @@ async function runMigrationsAndSeeds(config3) {
|
|
|
27682
27943
|
throw err;
|
|
27683
27944
|
}
|
|
27684
27945
|
}
|
|
27685
|
-
logger.
|
|
27946
|
+
logger.debug("Checking schema drift...");
|
|
27686
27947
|
const drift = await detectSchemaDrift();
|
|
27687
27948
|
if (drift && (drift.newTables.length > 0 || drift.alteredTables.length > 0)) {
|
|
27688
27949
|
const message = formatDriftMessage(drift);
|
|
@@ -27729,7 +27990,7 @@ ${dirs}`);
|
|
|
27729
27990
|
}
|
|
27730
27991
|
const allDefinitions = modules.flatMap((m) => m.definitions ?? []);
|
|
27731
27992
|
await createMemoryTables(allDefinitions);
|
|
27732
|
-
logger.
|
|
27993
|
+
logger.debug("Running seeds...");
|
|
27733
27994
|
for (const mod of modules) {
|
|
27734
27995
|
try {
|
|
27735
27996
|
await runModuleSeed(mod, ctx);
|
|
@@ -27737,12 +27998,39 @@ ${dirs}`);
|
|
|
27737
27998
|
logger.error({ module: mod.name, err }, "Seed failed - continuing with next module");
|
|
27738
27999
|
}
|
|
27739
28000
|
}
|
|
28001
|
+
if (config3?.onSeed) {
|
|
28002
|
+
const { getPlugins: getPlugins2 } = await Promise.resolve().then(() => (init_module_queries(), module_queries_exports));
|
|
28003
|
+
const { createMasterRegistry: createMasterRegistry2 } = await Promise.resolve().then(() => (init_registry2(), registry_exports));
|
|
28004
|
+
const masterRegistry = ctx.services.has("masters") ? ctx.services.get("masters") : createMasterRegistry2();
|
|
28005
|
+
const pluginPrefixes = /* @__PURE__ */ new Map();
|
|
28006
|
+
for (const plugin of getPlugins2()) {
|
|
28007
|
+
pluginPrefixes.set(plugin.code, `${plugin.code}_`);
|
|
28008
|
+
const shortName = plugin.name.replace(/^@[^/]+\/nexus-plugin-/, "");
|
|
28009
|
+
if (shortName !== plugin.code) {
|
|
28010
|
+
pluginPrefixes.set(shortName, `${plugin.code}_`);
|
|
28011
|
+
}
|
|
28012
|
+
}
|
|
28013
|
+
const { createSeedContext: createSeedContext2 } = await Promise.resolve().then(() => (init_seed_context(), seed_context_exports));
|
|
28014
|
+
const { ctx: seedCtx, flushPermissions } = createSeedContext2({
|
|
28015
|
+
knex: ctx.db.knex,
|
|
28016
|
+
generateId: ctx.core.generateId,
|
|
28017
|
+
hashPassword: ctx.core.crypto.hashPassword,
|
|
28018
|
+
masterRegistry,
|
|
28019
|
+
pluginPrefixes,
|
|
28020
|
+
logger: ctx.core.logger,
|
|
28021
|
+
onPermissionsCollected: (perms) => setSeedPermissions(perms)
|
|
28022
|
+
});
|
|
28023
|
+
await config3.onSeed(seedCtx);
|
|
28024
|
+
await masterRegistry.seed(ctx);
|
|
28025
|
+
flushPermissions();
|
|
28026
|
+
}
|
|
27740
28027
|
}
|
|
27741
28028
|
async function start(config3) {
|
|
27742
28029
|
if (server) {
|
|
27743
28030
|
throw new Error("Server already running. Call stop() first.");
|
|
27744
28031
|
}
|
|
27745
28032
|
currentConfig = config3;
|
|
28033
|
+
setLocales(config3?.locales ?? DEFAULT_LOCALES2);
|
|
27746
28034
|
if (env.NODE_ENV === "development" && env.FRPC_SERVER && env.FRPC_SUBDOMAIN && !env.BACKEND_URL) {
|
|
27747
28035
|
process.env["BACKEND_URL"] = getTunnelUrl(env.FRPC_SUBDOMAIN, env.FRPC_SERVER);
|
|
27748
28036
|
}
|
|
@@ -27767,13 +28055,17 @@ async function start(config3) {
|
|
|
27767
28055
|
await initTelemetry2();
|
|
27768
28056
|
await runMigrationsAndSeeds(config3);
|
|
27769
28057
|
const effectiveCorsOrigins = buildEffectiveCorsOrigins(env.CORS_ORIGIN, config3?.spas);
|
|
28058
|
+
const httpServer = http.createServer();
|
|
27770
28059
|
const app = await createApp({
|
|
27771
28060
|
beforeRoutes: config3?.beforeRoutes,
|
|
27772
28061
|
afterRoutes: config3?.afterRoutes,
|
|
27773
|
-
spas: config3?.spas
|
|
28062
|
+
spas: config3?.spas,
|
|
28063
|
+
httpServer
|
|
27774
28064
|
});
|
|
28065
|
+
httpServer.on("request", app);
|
|
27775
28066
|
return new Promise((resolve2) => {
|
|
27776
|
-
server =
|
|
28067
|
+
server = httpServer;
|
|
28068
|
+
httpServer.listen(resolved.port, resolved.host, async () => {
|
|
27777
28069
|
const timeoutMs = parseInt(process.env["REQUEST_TIMEOUT_MS"] || "30000", 10);
|
|
27778
28070
|
if (timeoutMs > 0) {
|
|
27779
28071
|
server.setTimeout(timeoutMs);
|
|
@@ -27809,12 +28101,10 @@ async function start(config3) {
|
|
|
27809
28101
|
});
|
|
27810
28102
|
}
|
|
27811
28103
|
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");
|
|
28104
|
+
logger.debug({ libPath: getLibPath(), projectPath: getProjectPath() }, "Paths");
|
|
28105
|
+
const urls = { api: `${baseUrl}/api/v1` };
|
|
28106
|
+
if (resolved.ui.enabled) urls["ui"] = baseUrl;
|
|
28107
|
+
logger.info({ port: actualPort, mode: resolved.nodeEnv, ...urls }, "Server started");
|
|
27818
28108
|
nexusEvents.emitEvent("server.started", { port: actualPort, host: resolved.host });
|
|
27819
28109
|
if (config3?.onReady) {
|
|
27820
28110
|
try {
|
|
@@ -27840,7 +28130,8 @@ async function stop() {
|
|
|
27840
28130
|
await resetSharedAdapters();
|
|
27841
28131
|
resetConfigCache();
|
|
27842
28132
|
clearCustomCaslRules();
|
|
27843
|
-
|
|
28133
|
+
clearSeedPermissions();
|
|
28134
|
+
await resetServeSPA();
|
|
27844
28135
|
return;
|
|
27845
28136
|
}
|
|
27846
28137
|
if (currentConfig?.beforeClose) {
|
|
@@ -27874,7 +28165,8 @@ async function stop() {
|
|
|
27874
28165
|
await resetSharedAdapters();
|
|
27875
28166
|
resetConfigCache();
|
|
27876
28167
|
clearCustomCaslRules();
|
|
27877
|
-
|
|
28168
|
+
clearSeedPermissions();
|
|
28169
|
+
await resetServeSPA();
|
|
27878
28170
|
currentConfig = void 0;
|
|
27879
28171
|
server = null;
|
|
27880
28172
|
nexusEvents.emitEvent("server.stopped");
|
|
@@ -27934,7 +28226,7 @@ var init_server = __esm({
|
|
|
27934
28226
|
init_cors();
|
|
27935
28227
|
init_logger();
|
|
27936
28228
|
init_error_middleware();
|
|
27937
|
-
|
|
28229
|
+
init_port_check();
|
|
27938
28230
|
init_engine();
|
|
27939
28231
|
init_context();
|
|
27940
28232
|
init_db();
|