@mostajs/setup 2.1.19 → 2.1.21

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.
@@ -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
- return netTestResult?.ok === true;
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'] })) })), _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 => {
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
@@ -60,12 +60,16 @@ export async function runInstall(installConfig, setupConfig) {
60
60
  port: setupConfig.defaultPort,
61
61
  });
62
62
  }
63
- // 3. Set process.env in-memory
63
+ // 3. Set process.env in-memory (force ORM mode even if app started as NET)
64
+ process.env.MOSTA_DATA = 'orm';
64
65
  process.env.DB_DIALECT = installConfig.dialect;
65
66
  process.env.SGBD_URI = uri;
66
67
  if (installConfig.dialect !== 'mongodb') {
67
68
  process.env.DB_SCHEMA_STRATEGY = 'update';
68
69
  }
70
+ // Clear NET vars to avoid confusion
71
+ delete process.env.MOSTA_NET_URL;
72
+ delete process.env.MOSTA_NET_TRANSPORT;
69
73
  // 4. Disconnect existing dialect singleton
70
74
  const { disconnectDialect } = await import('@mostajs/orm');
71
75
  await disconnectDialect();
@@ -118,6 +122,9 @@ export async function runInstall(installConfig, setupConfig) {
118
122
  */
119
123
  async function runNetInstall(installConfig, setupConfig) {
120
124
  try {
125
+ // Force NET mode in-memory (even if app started as ORM)
126
+ process.env.MOSTA_DATA = 'net';
127
+ process.env.MOSTA_NET_URL = installConfig.net.url;
121
128
  const net = new NetClient({
122
129
  url: installConfig.net.url,
123
130
  apiKey: installConfig.net.apiKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/setup",
3
- "version": "2.1.19",
3
+ "version": "2.1.21",
4
4
  "description": "Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "MIT",