@mostajs/setup 2.1.0 → 2.1.2
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.
|
@@ -425,9 +425,83 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
425
425
|
}, [hydrated, persistState, currentStep, dialect, dbConfig, adminConfig, seedOptions, selectedModules]);
|
|
426
426
|
// --- Detect modules ---
|
|
427
427
|
useEffect(() => {
|
|
428
|
-
|
|
428
|
+
const declaredKeys = new Set((declaredModules ?? []).map(m => m.key));
|
|
429
|
+
// If API endpoint available → fetch full catalog, enrich with declared info
|
|
430
|
+
if (ep.detectModules) {
|
|
431
|
+
fetch(ep.detectModules)
|
|
432
|
+
.then(r => r.json())
|
|
433
|
+
.then((data) => {
|
|
434
|
+
const apiModules = data.modules || [];
|
|
435
|
+
if (data.installed)
|
|
436
|
+
setDetectedModules(data.installed);
|
|
437
|
+
// Merge: API modules as base, enrich with setup.json overrides
|
|
438
|
+
if (declaredModules && declaredModules.length > 0) {
|
|
439
|
+
const apiByKey = new Map(apiModules.map(m => [m.key, m]));
|
|
440
|
+
// Enrich API modules with declared metadata
|
|
441
|
+
for (const dm of declaredModules) {
|
|
442
|
+
const existing = apiByKey.get(dm.key);
|
|
443
|
+
if (existing) {
|
|
444
|
+
if (dm.label)
|
|
445
|
+
existing.label = dm.label;
|
|
446
|
+
if (dm.description)
|
|
447
|
+
existing.description = dm.description;
|
|
448
|
+
if (dm.icon)
|
|
449
|
+
existing.icon = dm.icon;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Module declared in setup.json but not in API catalog — add it
|
|
453
|
+
apiModules.push({
|
|
454
|
+
key: dm.key,
|
|
455
|
+
label: dm.label ?? dm.key,
|
|
456
|
+
description: dm.description ?? '',
|
|
457
|
+
icon: dm.icon ?? '📦',
|
|
458
|
+
required: dm.required,
|
|
459
|
+
default: true,
|
|
460
|
+
dependsOn: dm.dependsOn,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
setAvailableModules(apiModules);
|
|
465
|
+
// Pre-select: declared modules + required
|
|
466
|
+
const pre = new Set([
|
|
467
|
+
...declaredKeys,
|
|
468
|
+
...apiModules.filter(m => m.required).map(m => m.key),
|
|
469
|
+
]);
|
|
470
|
+
setSelectedModules(Array.from(pre));
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
setAvailableModules(apiModules);
|
|
474
|
+
if (selectedModules.length === 0) {
|
|
475
|
+
const pre = new Set([
|
|
476
|
+
...apiModules.filter(m => m.required || m.default).map(m => m.key),
|
|
477
|
+
...(data.installed || []),
|
|
478
|
+
]);
|
|
479
|
+
setSelectedModules(Array.from(pre));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
setModulesDetected(true);
|
|
483
|
+
})
|
|
484
|
+
.catch(() => {
|
|
485
|
+
// API failed — fallback to declared modules only
|
|
486
|
+
if (declaredModules && declaredModules.length > 0) {
|
|
487
|
+
setAvailableModules(declaredModules.map(m => ({
|
|
488
|
+
key: m.key,
|
|
489
|
+
label: m.label ?? m.key,
|
|
490
|
+
description: m.description ?? '',
|
|
491
|
+
icon: m.icon ?? '📦',
|
|
492
|
+
required: m.required,
|
|
493
|
+
default: true,
|
|
494
|
+
dependsOn: m.dependsOn,
|
|
495
|
+
})));
|
|
496
|
+
setSelectedModules(Array.from(declaredKeys));
|
|
497
|
+
}
|
|
498
|
+
setModulesDetected(true);
|
|
499
|
+
});
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
// No API endpoint — use declared modules only (if any)
|
|
429
503
|
if (declaredModules && declaredModules.length > 0) {
|
|
430
|
-
|
|
504
|
+
setAvailableModules(declaredModules.map(m => ({
|
|
431
505
|
key: m.key,
|
|
432
506
|
label: m.label ?? m.key,
|
|
433
507
|
description: m.description ?? '',
|
|
@@ -435,36 +509,13 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
435
509
|
required: m.required,
|
|
436
510
|
default: true,
|
|
437
511
|
dependsOn: m.dependsOn,
|
|
438
|
-
}));
|
|
439
|
-
|
|
440
|
-
setSelectedModules(declaredModules.map(m => m.key));
|
|
441
|
-
setModulesDetected(true);
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
// No modules and no endpoint → skip
|
|
445
|
-
if (!ep.detectModules) {
|
|
512
|
+
})));
|
|
513
|
+
setSelectedModules(Array.from(declaredKeys));
|
|
446
514
|
setModulesDetected(true);
|
|
447
515
|
return;
|
|
448
516
|
}
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
.then(r => r.json())
|
|
452
|
-
.then((data) => {
|
|
453
|
-
if (data.modules)
|
|
454
|
-
setAvailableModules(data.modules);
|
|
455
|
-
if (data.installed)
|
|
456
|
-
setDetectedModules(data.installed);
|
|
457
|
-
if (selectedModules.length === 0) {
|
|
458
|
-
const mods = data.modules || [];
|
|
459
|
-
const pre = new Set([
|
|
460
|
-
...mods.filter(m => m.required || m.default).map(m => m.key),
|
|
461
|
-
...(data.installed || []),
|
|
462
|
-
]);
|
|
463
|
-
setSelectedModules(Array.from(pre));
|
|
464
|
-
}
|
|
465
|
-
setModulesDetected(true);
|
|
466
|
-
})
|
|
467
|
-
.catch(() => setModulesDetected(true));
|
|
517
|
+
// No endpoint, no declared modules → skip
|
|
518
|
+
setModulesDetected(true);
|
|
468
519
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
469
520
|
}, []);
|
|
470
521
|
// --- Module toggle ---
|
|
@@ -102,6 +102,22 @@ function buildConfig(json, repoFactory) {
|
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
// ── createAdmin (generic — uses repoFactory for 'user' + 'role') ──
|
|
106
|
+
config.createAdmin = async ({ email, hashedPassword, firstName, lastName }) => {
|
|
107
|
+
const getRepo = repoFactory ?? defaultRepoFactory;
|
|
108
|
+
const userRepo = await getRepo('user');
|
|
109
|
+
const roleRepo = await getRepo('role');
|
|
110
|
+
// Resolve admin role (seeded in RBAC step just before)
|
|
111
|
+
const adminRole = await roleRepo.findOne({ name: 'admin' });
|
|
112
|
+
await userRepo.create({
|
|
113
|
+
email,
|
|
114
|
+
password: hashedPassword,
|
|
115
|
+
firstName,
|
|
116
|
+
lastName,
|
|
117
|
+
status: 'active',
|
|
118
|
+
roles: adminRole ? [adminRole.id] : [],
|
|
119
|
+
});
|
|
120
|
+
};
|
|
105
121
|
// ── optionalSeeds ──────────────────────────────────────
|
|
106
122
|
if (json.seeds?.length) {
|
|
107
123
|
config.optionalSeeds = json.seeds.map(seedDef => buildSeedDefinition(seedDef, repoFactory));
|
package/package.json
CHANGED