@mostajs/setup 2.1.20 → 2.1.22
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/components/SetupWizard.js +124 -2
- package/dist/lib/setup.js +17 -4
- package/package.json +1 -1
|
@@ -367,6 +367,8 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
367
367
|
const [netApiKey, setNetApiKey] = useState('');
|
|
368
368
|
const [netTestResult, setNetTestResult] = useState(null);
|
|
369
369
|
const [netTesting, setNetTesting] = useState(false);
|
|
370
|
+
const [schemaUploadStatus, setSchemaUploadStatus] = useState(null);
|
|
371
|
+
const [schemasReady, setSchemasReady] = useState(false);
|
|
370
372
|
const [currentStep, setCurrentStep] = useState(0);
|
|
371
373
|
const [dialect, setDialect] = useState('mongodb');
|
|
372
374
|
const [dbConfig, setDbConfig] = useState({ ...DIALECT_DEFAULTS.mongodb, name: `${dbNamePrefix}_prod` });
|
|
@@ -771,7 +773,8 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
771
773
|
return dbConfig.name.trim() !== '';
|
|
772
774
|
return dbTestResult?.ok === true;
|
|
773
775
|
case 'net-config':
|
|
774
|
-
|
|
776
|
+
// OK si serveur connecté ET (schemas déjà chargés OU uploadés)
|
|
777
|
+
return netTestResult?.ok === true && ((netTestResult.entities?.length ?? 0) > 0 || schemasReady);
|
|
775
778
|
case 'admin':
|
|
776
779
|
return adminConfig.firstName.trim() !== '' && adminConfig.lastName.trim() !== '' &&
|
|
777
780
|
adminConfig.email.trim() !== '' && adminConfig.password.length >= 6 &&
|
|
@@ -843,7 +846,126 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
843
846
|
padding: 12, borderRadius: 8, marginBottom: 16,
|
|
844
847
|
backgroundColor: netTestResult.ok ? '#f0fdf4' : '#fef2f2',
|
|
845
848
|
border: `1px solid ${netTestResult.ok ? '#bbf7d0' : '#fecaca'}`,
|
|
846
|
-
}, children: netTestResult.ok ? (_jsxs("div", { children: [_jsx("div", { style: { fontWeight: 600, color: '#166534', marginBottom: 4 }, children: "\u2705 Serveur connecte" }), netTestResult.entities && (_jsxs("div", { style: { fontSize: 13, color: '#374151' }, children: [_jsx("strong", { children: netTestResult.entities.length }), " entites : ", netTestResult.entities.join(', ')] })), netTestResult.transports && (_jsxs("div", { style: { fontSize: 13, color: '#6b7280', marginTop: 4 }, children: ["Transports : ", netTestResult.transports.join(', ')] }))] })) : (_jsxs("div", { style: { color: '#991b1b' }, children: ["\u274C ", netTestResult.error || 'Connexion echouee'] })) })),
|
|
849
|
+
}, children: netTestResult.ok ? (_jsxs("div", { children: [_jsx("div", { style: { fontWeight: 600, color: '#166534', marginBottom: 4 }, children: "\u2705 Serveur connecte" }), netTestResult.entities && (_jsxs("div", { style: { fontSize: 13, color: '#374151' }, children: [_jsx("strong", { children: netTestResult.entities.length }), " entites : ", netTestResult.entities.join(', ')] })), netTestResult.transports && (_jsxs("div", { style: { fontSize: 13, color: '#6b7280', marginTop: 4 }, children: ["Transports : ", netTestResult.transports.join(', ')] }))] })) : (_jsxs("div", { style: { color: '#991b1b' }, children: ["\u274C ", netTestResult.error || 'Connexion echouee'] })) })), netTestResult?.ok && netTestResult.entities?.length === 0 && !schemasReady && (_jsxs("div", { style: {
|
|
850
|
+
padding: 16, borderRadius: 8, marginBottom: 16,
|
|
851
|
+
backgroundColor: '#fffbeb', border: '1px solid #fde68a',
|
|
852
|
+
}, children: [_jsx("div", { style: { fontWeight: 600, color: '#92400e', marginBottom: 8 }, children: "\u26A0\uFE0F Le serveur n'a aucun schema \u2014 envoyez les schemas pour continuer" }), _jsxs("div", { style: { display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 8 }, children: [_jsx("button", { style: { ...S.btn('primary'), fontSize: 13 }, onClick: () => document.getElementById('schemaFileInput')?.click(), children: "\uD83D\uDCC4 Envoyer schemas.json" }), _jsx("input", { id: "schemaFileInput", type: "file", accept: ".json", style: { display: 'none' }, onChange: async (e) => {
|
|
853
|
+
const file = e.target.files?.[0];
|
|
854
|
+
if (!file)
|
|
855
|
+
return;
|
|
856
|
+
setSchemaUploadStatus({ phase: '📤 Envoi du fichier...', color: '#2563eb' });
|
|
857
|
+
try {
|
|
858
|
+
const text = await file.text();
|
|
859
|
+
const schemas = JSON.parse(text);
|
|
860
|
+
const res = await fetch(netUrl + '/api/upload-schemas-json', {
|
|
861
|
+
method: 'POST',
|
|
862
|
+
headers: { 'Content-Type': 'application/json' },
|
|
863
|
+
body: JSON.stringify({ schemas }),
|
|
864
|
+
});
|
|
865
|
+
const data = await res.json();
|
|
866
|
+
if (data.ok) {
|
|
867
|
+
if (data.needsRestart) {
|
|
868
|
+
setSchemaUploadStatus({ phase: '⏳ Serveur redémarre...', color: '#d97706' });
|
|
869
|
+
// Poll health
|
|
870
|
+
for (let i = 0; i < 30; i++) {
|
|
871
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
872
|
+
setSchemaUploadStatus({ phase: `⏳ En attente du serveur... (${i + 1}/30)`, color: '#d97706' });
|
|
873
|
+
try {
|
|
874
|
+
const h = await fetch(netUrl + '/health');
|
|
875
|
+
if (h.ok) {
|
|
876
|
+
const hd = await h.json();
|
|
877
|
+
if (hd.entities?.length > 0) {
|
|
878
|
+
setSchemaUploadStatus({ phase: `✅ Serveur prêt — ${hd.entities.length} entités`, color: '#16a34a' });
|
|
879
|
+
setSchemasReady(true);
|
|
880
|
+
setNetTestResult({ ...netTestResult, entities: hd.entities });
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
catch { }
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
setSchemaUploadStatus({ phase: `✅ ${data.count} schemas chargés`, color: '#16a34a' });
|
|
890
|
+
setSchemasReady(true);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
setSchemaUploadStatus({ phase: `❌ ${data.error}`, color: '#dc2626' });
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
catch (err) {
|
|
898
|
+
setSchemaUploadStatus({ phase: `❌ ${err.message}`, color: '#dc2626' });
|
|
899
|
+
}
|
|
900
|
+
e.target.value = '';
|
|
901
|
+
} }), _jsx("button", { style: { ...S.btn('outline'), fontSize: 13 }, onClick: () => document.getElementById('schemaZipInput')?.click(), children: "\uD83D\uDCE6 Envoyer ZIP de schemas" }), _jsx("input", { id: "schemaZipInput", type: "file", accept: ".zip", style: { display: 'none' }, onChange: async (e) => {
|
|
902
|
+
const file = e.target.files?.[0];
|
|
903
|
+
if (!file)
|
|
904
|
+
return;
|
|
905
|
+
setSchemaUploadStatus({ phase: '📤 Envoi du ZIP...', color: '#2563eb' });
|
|
906
|
+
try {
|
|
907
|
+
const formData = new FormData();
|
|
908
|
+
formData.append('file', file);
|
|
909
|
+
const res = await fetch(netUrl + '/api/upload-schemas', {
|
|
910
|
+
method: 'POST',
|
|
911
|
+
body: formData,
|
|
912
|
+
});
|
|
913
|
+
const data = await res.json();
|
|
914
|
+
if (data.ok) {
|
|
915
|
+
setSchemaUploadStatus({ phase: `✅ ${data.count} schemas importés depuis ZIP`, color: '#16a34a' });
|
|
916
|
+
setSchemasReady(true);
|
|
917
|
+
// Refresh test result
|
|
918
|
+
const h = await fetch(netUrl + '/health').then(r => r.json());
|
|
919
|
+
if (h.entities)
|
|
920
|
+
setNetTestResult({ ...netTestResult, entities: h.entities });
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
setSchemaUploadStatus({ phase: `❌ ${data.error}`, color: '#dc2626' });
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
catch (err) {
|
|
927
|
+
setSchemaUploadStatus({ phase: `❌ ${err.message}`, color: '#dc2626' });
|
|
928
|
+
}
|
|
929
|
+
e.target.value = '';
|
|
930
|
+
} }), _jsx("button", { style: { ...S.btn('outline'), fontSize: 13 }, onClick: async () => {
|
|
931
|
+
const schemasPath = prompt('Chemin vers le répertoire des schemas (*.schema.ts) :', './src/dal/schemas');
|
|
932
|
+
if (!schemasPath)
|
|
933
|
+
return;
|
|
934
|
+
setSchemaUploadStatus({ phase: '🔍 Scan en cours...', color: '#2563eb' });
|
|
935
|
+
try {
|
|
936
|
+
const res = await fetch(netUrl + '/api/scan-schemas', {
|
|
937
|
+
method: 'POST',
|
|
938
|
+
headers: { 'Content-Type': 'application/json' },
|
|
939
|
+
body: JSON.stringify({ path: schemasPath }),
|
|
940
|
+
});
|
|
941
|
+
const data = await res.json();
|
|
942
|
+
if (data.ok && data.count > 0) {
|
|
943
|
+
// Générer et appliquer
|
|
944
|
+
const genRes = await fetch(netUrl + '/api/generate-schemas', {
|
|
945
|
+
method: 'POST',
|
|
946
|
+
headers: { 'Content-Type': 'application/json' },
|
|
947
|
+
body: JSON.stringify({ path: schemasPath }),
|
|
948
|
+
});
|
|
949
|
+
const genData = await genRes.json();
|
|
950
|
+
if (genData.ok) {
|
|
951
|
+
setSchemaUploadStatus({ phase: `✅ ${genData.count} schemas scannés et générés`, color: '#16a34a' });
|
|
952
|
+
setSchemasReady(true);
|
|
953
|
+
const h = await fetch(netUrl + '/health').then(r => r.json());
|
|
954
|
+
if (h.entities)
|
|
955
|
+
setNetTestResult({ ...netTestResult, entities: h.entities });
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
setSchemaUploadStatus({ phase: `❌ Aucun schema trouvé dans ${schemasPath}`, color: '#dc2626' });
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
catch (err) {
|
|
963
|
+
setSchemaUploadStatus({ phase: `❌ ${err.message}`, color: '#dc2626' });
|
|
964
|
+
}
|
|
965
|
+
}, children: "\uD83D\uDCC1 Scanner un r\u00E9pertoire" })] }), schemaUploadStatus && (_jsx("div", { style: { fontSize: 13, fontWeight: 500, color: schemaUploadStatus.color }, children: schemaUploadStatus.phase }))] })), netTestResult?.ok && (netTestResult.entities?.length ?? 0) > 0 && (_jsx("div", { style: {
|
|
966
|
+
padding: 12, borderRadius: 8, marginBottom: 16,
|
|
967
|
+
backgroundColor: '#f0fdf4', border: '1px solid #bbf7d0',
|
|
968
|
+
}, children: _jsxs("div", { style: { fontWeight: 600, color: '#166534' }, children: ["\u2705 Serveur pr\u00EAt \u2014 ", netTestResult.entities?.length, " entit\u00E9s charg\u00E9es"] }) })), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'admin' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDC64" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.admin.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.admin.description') })] })] }), _jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.firstName') }), _jsx("input", { style: S.input, value: adminConfig.firstName, onChange: e => setAdminConfig({ ...adminConfig, firstName: e.target.value }) })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.lastName') }), _jsx("input", { style: S.input, value: adminConfig.lastName, onChange: e => setAdminConfig({ ...adminConfig, lastName: e.target.value }) })] })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.email') }), _jsx("input", { style: S.input, type: "email", value: adminConfig.email, onChange: e => setAdminConfig({ ...adminConfig, email: e.target.value }), placeholder: "admin@example.com" })] }), _jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.password') }), _jsx("input", { style: S.input, type: "password", value: adminConfig.password, onChange: e => setAdminConfig({ ...adminConfig, password: e.target.value }) })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.confirmPassword') }), _jsx("input", { style: S.input, type: "password", value: adminConfig.confirmPassword, onChange: e => setAdminConfig({ ...adminConfig, confirmPassword: e.target.value }) })] })] }), adminConfig.password && adminConfig.confirmPassword && adminConfig.password !== adminConfig.confirmPassword && (_jsx("p", { style: { fontSize: 13, color: '#dc2626' }, children: t('setup.admin.passwordMismatch') })), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'summary' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\u2699\uFE0F" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.summary.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.summary.description') })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: setupMode === 'net' ? 'Serveur @mostajs/net' : t('setup.summary.dbConfig') }), _jsxs("div", { style: S.summaryText, children: [_jsx("span", { style: { fontFamily: 'monospace' }, children: dbSummaryLabel() }), setupMode === 'net' && netTransport && _jsxs("span", { style: { display: 'block', marginTop: 4 }, children: ["Transport: ", netTransport] }), setupMode !== 'net' && dialect !== 'sqlite' && dbConfig.user && _jsxs("span", { style: { display: 'block', marginTop: 4 }, children: ["Utilisateur: ", dbConfig.user] })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.summary.adminConfig') }), _jsxs("div", { style: S.summaryText, children: [_jsxs("div", { children: [adminConfig.firstName, " ", adminConfig.lastName] }), _jsx("div", { children: adminConfig.email })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.modules.title') }), _jsx("div", { style: S.flexWrap, children: selectedModules.map(key => {
|
|
847
969
|
const mod = availableModules.find(m => m.key === key);
|
|
848
970
|
return mod ? (_jsxs("span", { style: {
|
|
849
971
|
display: 'inline-flex', alignItems: 'center', gap: 4,
|
package/dist/lib/setup.js
CHANGED
|
@@ -142,8 +142,20 @@ async function runNetInstall(installConfig, setupConfig) {
|
|
|
142
142
|
extraVars['MOSTAJS_MODULES'] = installConfig.modules.join(',');
|
|
143
143
|
}
|
|
144
144
|
const seeded = [];
|
|
145
|
-
// 2. Verify NET server is reachable
|
|
146
|
-
|
|
145
|
+
// 2. Verify NET server is reachable (retry up to 10s if just restarted)
|
|
146
|
+
let health = null;
|
|
147
|
+
for (let i = 0; i < 10; i++) {
|
|
148
|
+
try {
|
|
149
|
+
health = await net.health();
|
|
150
|
+
if (health.entities?.length > 0)
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
catch { }
|
|
154
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
155
|
+
}
|
|
156
|
+
if (!health) {
|
|
157
|
+
return { ok: false, error: 'Serveur NET non joignable', needsRestart: false };
|
|
158
|
+
}
|
|
147
159
|
// 3. Read setup.json for RBAC definitions
|
|
148
160
|
const fs = await import('fs');
|
|
149
161
|
const path = await import('path');
|
|
@@ -155,8 +167,8 @@ async function runNetInstall(installConfig, setupConfig) {
|
|
|
155
167
|
}
|
|
156
168
|
catch { }
|
|
157
169
|
}
|
|
158
|
-
// 4. If server has no entities, try sending
|
|
159
|
-
if (!health
|
|
170
|
+
// 4. If server has no entities (schemas not yet uploaded), try sending them
|
|
171
|
+
if (!health?.entities?.length) {
|
|
160
172
|
let schemasToSend = [];
|
|
161
173
|
// Try schemas.json local
|
|
162
174
|
const schemasJsonPath = path.resolve(process.cwd(), 'schemas.json');
|
|
@@ -217,6 +229,7 @@ async function runNetInstall(installConfig, setupConfig) {
|
|
|
217
229
|
}
|
|
218
230
|
}
|
|
219
231
|
await net.loadCollectionMap();
|
|
232
|
+
console.log(`[Setup NET] Serveur prêt — ${health?.entities?.length ?? 0} entités, collectionMap chargée`);
|
|
220
233
|
if (setupJson?.rbac) {
|
|
221
234
|
const rbac = setupJson.rbac;
|
|
222
235
|
// 3a. Upsert categories
|
package/package.json
CHANGED