@authrim/setup 0.1.49 → 0.1.51
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/commands/init.js +274 -7
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/core/cloudflare.d.ts +16 -4
- package/dist/core/cloudflare.d.ts.map +1 -1
- package/dist/core/cloudflare.js +45 -4
- package/dist/core/cloudflare.js.map +1 -1
- package/dist/core/config.d.ts +225 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +42 -0
- package/dist/core/config.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +101 -4
- package/dist/web/api.js.map +1 -1
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +590 -28
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/web/ui.js
CHANGED
|
@@ -746,6 +746,94 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
746
746
|
color: var(--text-muted);
|
|
747
747
|
font-size: 0.8rem;
|
|
748
748
|
}
|
|
749
|
+
|
|
750
|
+
/* Database configuration styles */
|
|
751
|
+
.database-config-grid {
|
|
752
|
+
display: grid;
|
|
753
|
+
grid-template-columns: 1fr 1fr;
|
|
754
|
+
gap: 1.5rem;
|
|
755
|
+
margin-bottom: 1.5rem;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.database-card {
|
|
759
|
+
background: var(--bg);
|
|
760
|
+
border: 1px solid var(--border);
|
|
761
|
+
border-radius: 0.5rem;
|
|
762
|
+
padding: 1.25rem;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.database-card h3 {
|
|
766
|
+
margin: 0 0 1rem 0;
|
|
767
|
+
font-size: 1.1rem;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.db-description {
|
|
771
|
+
font-size: 0.875rem;
|
|
772
|
+
color: var(--text-muted);
|
|
773
|
+
margin-bottom: 1rem;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.db-description p {
|
|
777
|
+
margin: 0 0 0.5rem 0;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.db-description ul {
|
|
781
|
+
margin: 0.5rem 0;
|
|
782
|
+
padding-left: 1.25rem;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
.db-description li {
|
|
786
|
+
margin-bottom: 0.25rem;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.db-hint {
|
|
790
|
+
font-style: italic;
|
|
791
|
+
margin-top: 0.75rem;
|
|
792
|
+
padding: 0.5rem;
|
|
793
|
+
background: #f0f9ff;
|
|
794
|
+
border-radius: 4px;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.region-selection h4 {
|
|
798
|
+
margin: 0 0 0.75rem 0;
|
|
799
|
+
font-size: 0.95rem;
|
|
800
|
+
font-weight: 600;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.radio-group {
|
|
804
|
+
display: flex;
|
|
805
|
+
flex-direction: column;
|
|
806
|
+
gap: 0.5rem;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.radio-item {
|
|
810
|
+
display: flex;
|
|
811
|
+
align-items: center;
|
|
812
|
+
gap: 0.5rem;
|
|
813
|
+
cursor: pointer;
|
|
814
|
+
padding: 0.25rem 0;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.radio-item input[type="radio"] {
|
|
818
|
+
margin: 0;
|
|
819
|
+
width: 16px;
|
|
820
|
+
height: 16px;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.radio-separator {
|
|
824
|
+
font-size: 0.75rem;
|
|
825
|
+
color: var(--text-muted);
|
|
826
|
+
margin: 0.5rem 0 0.25rem 0;
|
|
827
|
+
font-weight: 500;
|
|
828
|
+
text-transform: uppercase;
|
|
829
|
+
letter-spacing: 0.05em;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
@media (max-width: 768px) {
|
|
833
|
+
.database-config-grid {
|
|
834
|
+
grid-template-columns: 1fr;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
749
837
|
</style>
|
|
750
838
|
</head>
|
|
751
839
|
<body>
|
|
@@ -772,6 +860,14 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
772
860
|
<div class="step step-pending" id="step-3">3</div>
|
|
773
861
|
<div class="step-connector"></div>
|
|
774
862
|
<div class="step step-pending" id="step-4">4</div>
|
|
863
|
+
<div class="step-connector"></div>
|
|
864
|
+
<div class="step step-pending" id="step-5">5</div>
|
|
865
|
+
<div class="step-connector"></div>
|
|
866
|
+
<div class="step step-pending" id="step-6">6</div>
|
|
867
|
+
<div class="step-connector"></div>
|
|
868
|
+
<div class="step step-pending" id="step-7">7</div>
|
|
869
|
+
<div class="step-connector"></div>
|
|
870
|
+
<div class="step step-pending" id="step-8">8</div>
|
|
775
871
|
</div>
|
|
776
872
|
|
|
777
873
|
<!-- Step 1: Prerequisites -->
|
|
@@ -1035,7 +1131,206 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1035
1131
|
</div>
|
|
1036
1132
|
</div>
|
|
1037
1133
|
|
|
1038
|
-
<!-- Step 3:
|
|
1134
|
+
<!-- Step 3: Database Configuration -->
|
|
1135
|
+
<div id="section-database" class="card hidden">
|
|
1136
|
+
<h2 class="card-title">🗄️ Database Configuration</h2>
|
|
1137
|
+
|
|
1138
|
+
<div class="warning-box" style="background: #fef3c7; border-left: 4px solid #f59e0b; padding: 0.75rem 1rem; margin-bottom: 1.5rem; border-radius: 0.375rem;">
|
|
1139
|
+
⚠️ Database region cannot be changed after creation.
|
|
1140
|
+
</div>
|
|
1141
|
+
|
|
1142
|
+
<div class="database-config-grid">
|
|
1143
|
+
<!-- Core Database -->
|
|
1144
|
+
<div class="database-card">
|
|
1145
|
+
<h3>🗄️ Core Database</h3>
|
|
1146
|
+
<div class="db-description">
|
|
1147
|
+
<p>Stores application data including:</p>
|
|
1148
|
+
<ul>
|
|
1149
|
+
<li>OAuth clients and their configurations</li>
|
|
1150
|
+
<li>Authorization codes and access tokens</li>
|
|
1151
|
+
<li>User sessions and login state</li>
|
|
1152
|
+
<li>Tenant settings and configurations</li>
|
|
1153
|
+
<li>Audit logs and security events</li>
|
|
1154
|
+
</ul>
|
|
1155
|
+
<p class="db-hint">This database handles all authentication flows and should be placed close to your primary user base.</p>
|
|
1156
|
+
</div>
|
|
1157
|
+
|
|
1158
|
+
<div class="region-selection">
|
|
1159
|
+
<h4>Region</h4>
|
|
1160
|
+
<div class="radio-group">
|
|
1161
|
+
<label class="radio-item">
|
|
1162
|
+
<input type="radio" name="db-core-location" value="auto" checked>
|
|
1163
|
+
<span>Automatic (nearest to you)</span>
|
|
1164
|
+
</label>
|
|
1165
|
+
<div class="radio-separator">Location Hints</div>
|
|
1166
|
+
<label class="radio-item">
|
|
1167
|
+
<input type="radio" name="db-core-location" value="wnam">
|
|
1168
|
+
<span>North America (West)</span>
|
|
1169
|
+
</label>
|
|
1170
|
+
<label class="radio-item">
|
|
1171
|
+
<input type="radio" name="db-core-location" value="enam">
|
|
1172
|
+
<span>North America (East)</span>
|
|
1173
|
+
</label>
|
|
1174
|
+
<label class="radio-item">
|
|
1175
|
+
<input type="radio" name="db-core-location" value="weur">
|
|
1176
|
+
<span>Europe (West)</span>
|
|
1177
|
+
</label>
|
|
1178
|
+
<label class="radio-item">
|
|
1179
|
+
<input type="radio" name="db-core-location" value="eeur">
|
|
1180
|
+
<span>Europe (East)</span>
|
|
1181
|
+
</label>
|
|
1182
|
+
<label class="radio-item">
|
|
1183
|
+
<input type="radio" name="db-core-location" value="apac">
|
|
1184
|
+
<span>Asia Pacific</span>
|
|
1185
|
+
</label>
|
|
1186
|
+
<label class="radio-item">
|
|
1187
|
+
<input type="radio" name="db-core-location" value="oc">
|
|
1188
|
+
<span>Oceania</span>
|
|
1189
|
+
</label>
|
|
1190
|
+
<div class="radio-separator">Jurisdiction (Compliance)</div>
|
|
1191
|
+
<label class="radio-item">
|
|
1192
|
+
<input type="radio" name="db-core-location" value="eu">
|
|
1193
|
+
<span>EU Jurisdiction (GDPR compliance)</span>
|
|
1194
|
+
</label>
|
|
1195
|
+
</div>
|
|
1196
|
+
</div>
|
|
1197
|
+
</div>
|
|
1198
|
+
|
|
1199
|
+
<!-- PII Database -->
|
|
1200
|
+
<div class="database-card">
|
|
1201
|
+
<h3>🔒 PII Database</h3>
|
|
1202
|
+
<div class="db-description">
|
|
1203
|
+
<p>Stores personal user data including:</p>
|
|
1204
|
+
<ul>
|
|
1205
|
+
<li>User profiles (name, email, phone)</li>
|
|
1206
|
+
<li>Passkey/WebAuthn credentials</li>
|
|
1207
|
+
<li>User preferences and settings</li>
|
|
1208
|
+
<li>Any custom user attributes</li>
|
|
1209
|
+
</ul>
|
|
1210
|
+
<p class="db-hint">This database contains personal data. Consider placing it in a region that complies with your data protection requirements.</p>
|
|
1211
|
+
</div>
|
|
1212
|
+
|
|
1213
|
+
<div class="region-selection">
|
|
1214
|
+
<h4>Region</h4>
|
|
1215
|
+
<div class="radio-group">
|
|
1216
|
+
<label class="radio-item">
|
|
1217
|
+
<input type="radio" name="db-pii-location" value="auto" checked>
|
|
1218
|
+
<span>Automatic (nearest to you)</span>
|
|
1219
|
+
</label>
|
|
1220
|
+
<div class="radio-separator">Location Hints</div>
|
|
1221
|
+
<label class="radio-item">
|
|
1222
|
+
<input type="radio" name="db-pii-location" value="wnam">
|
|
1223
|
+
<span>North America (West)</span>
|
|
1224
|
+
</label>
|
|
1225
|
+
<label class="radio-item">
|
|
1226
|
+
<input type="radio" name="db-pii-location" value="enam">
|
|
1227
|
+
<span>North America (East)</span>
|
|
1228
|
+
</label>
|
|
1229
|
+
<label class="radio-item">
|
|
1230
|
+
<input type="radio" name="db-pii-location" value="weur">
|
|
1231
|
+
<span>Europe (West)</span>
|
|
1232
|
+
</label>
|
|
1233
|
+
<label class="radio-item">
|
|
1234
|
+
<input type="radio" name="db-pii-location" value="eeur">
|
|
1235
|
+
<span>Europe (East)</span>
|
|
1236
|
+
</label>
|
|
1237
|
+
<label class="radio-item">
|
|
1238
|
+
<input type="radio" name="db-pii-location" value="apac">
|
|
1239
|
+
<span>Asia Pacific</span>
|
|
1240
|
+
</label>
|
|
1241
|
+
<label class="radio-item">
|
|
1242
|
+
<input type="radio" name="db-pii-location" value="oc">
|
|
1243
|
+
<span>Oceania</span>
|
|
1244
|
+
</label>
|
|
1245
|
+
<div class="radio-separator">Jurisdiction (Compliance)</div>
|
|
1246
|
+
<label class="radio-item">
|
|
1247
|
+
<input type="radio" name="db-pii-location" value="eu">
|
|
1248
|
+
<span>EU Jurisdiction (GDPR compliance)</span>
|
|
1249
|
+
</label>
|
|
1250
|
+
</div>
|
|
1251
|
+
</div>
|
|
1252
|
+
</div>
|
|
1253
|
+
</div>
|
|
1254
|
+
|
|
1255
|
+
<div class="button-group">
|
|
1256
|
+
<button class="btn-secondary" id="btn-back-database">Back</button>
|
|
1257
|
+
<button class="btn-primary" id="btn-continue-database">Continue</button>
|
|
1258
|
+
</div>
|
|
1259
|
+
</div>
|
|
1260
|
+
|
|
1261
|
+
<!-- Step 4: Email Provider Configuration -->
|
|
1262
|
+
<div id="section-email" class="card hidden">
|
|
1263
|
+
<h2 class="card-title">📧 Email Provider</h2>
|
|
1264
|
+
|
|
1265
|
+
<p style="margin-bottom: 1rem; color: var(--text-muted);">
|
|
1266
|
+
Configure email sending for magic links and verification codes.
|
|
1267
|
+
You can configure this later if you prefer.
|
|
1268
|
+
</p>
|
|
1269
|
+
|
|
1270
|
+
<div class="radio-group" style="margin-bottom: 1.5rem;">
|
|
1271
|
+
<label class="radio-item" style="padding: 0.75rem; border: 1px solid var(--border); border-radius: 8px;">
|
|
1272
|
+
<input type="radio" name="email-setup-choice" value="later" checked>
|
|
1273
|
+
<span style="display: flex; flex-direction: column; gap: 0.25rem;">
|
|
1274
|
+
<strong>Configure later</strong>
|
|
1275
|
+
<small style="color: var(--text-muted);">Skip for now. Magic links will return URLs instead of sending emails.</small>
|
|
1276
|
+
</span>
|
|
1277
|
+
</label>
|
|
1278
|
+
<label class="radio-item" style="padding: 0.75rem; border: 1px solid var(--border); border-radius: 8px; margin-top: 0.5rem;">
|
|
1279
|
+
<input type="radio" name="email-setup-choice" value="configure">
|
|
1280
|
+
<span style="display: flex; flex-direction: column; gap: 0.25rem;">
|
|
1281
|
+
<strong>Configure Resend</strong>
|
|
1282
|
+
<small style="color: var(--text-muted);">Set up email sending with Resend (recommended for production).</small>
|
|
1283
|
+
</span>
|
|
1284
|
+
</label>
|
|
1285
|
+
</div>
|
|
1286
|
+
|
|
1287
|
+
<!-- Resend Configuration Form (hidden by default) -->
|
|
1288
|
+
<div id="resend-config-form" class="hidden" style="background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem;">
|
|
1289
|
+
<h3 style="margin: 0 0 1rem 0; font-size: 1rem;">🔑 Resend Configuration</h3>
|
|
1290
|
+
|
|
1291
|
+
<div class="alert alert-info" style="margin-bottom: 1rem;">
|
|
1292
|
+
<strong>📋 Before you begin:</strong>
|
|
1293
|
+
<ol style="margin: 0.5rem 0 0 1rem; padding: 0;">
|
|
1294
|
+
<li>Create a Resend account at <a href="https://resend.com" target="_blank" style="color: var(--primary);">resend.com</a></li>
|
|
1295
|
+
<li>Add and verify your domain at <a href="https://resend.com/domains" target="_blank" style="color: var(--primary);">Domains Dashboard</a></li>
|
|
1296
|
+
<li>Create an API key at <a href="https://resend.com/api-keys" target="_blank" style="color: var(--primary);">API Keys</a></li>
|
|
1297
|
+
</ol>
|
|
1298
|
+
</div>
|
|
1299
|
+
|
|
1300
|
+
<div class="form-group">
|
|
1301
|
+
<label for="resend-api-key">Resend API Key</label>
|
|
1302
|
+
<input type="password" id="resend-api-key" placeholder="re_xxxxxxxxxx" autocomplete="off">
|
|
1303
|
+
<small style="color: var(--text-muted);">Your API key starts with "re_"</small>
|
|
1304
|
+
</div>
|
|
1305
|
+
|
|
1306
|
+
<div class="form-group">
|
|
1307
|
+
<label for="email-from-address">From Email Address</label>
|
|
1308
|
+
<input type="email" id="email-from-address" placeholder="noreply@yourdomain.com" autocomplete="off">
|
|
1309
|
+
<small style="color: var(--text-muted);">Must be from a verified domain in your Resend account</small>
|
|
1310
|
+
</div>
|
|
1311
|
+
|
|
1312
|
+
<div class="form-group">
|
|
1313
|
+
<label for="email-from-name">From Display Name (optional)</label>
|
|
1314
|
+
<input type="text" id="email-from-name" placeholder="Authrim" autocomplete="off">
|
|
1315
|
+
<small style="color: var(--text-muted);">Displayed as the sender name in email clients</small>
|
|
1316
|
+
</div>
|
|
1317
|
+
|
|
1318
|
+
<div class="alert alert-warning" style="margin-top: 1rem;">
|
|
1319
|
+
<strong>⚠️ Domain Verification Required</strong>
|
|
1320
|
+
<p style="margin: 0.25rem 0 0 0; font-size: 0.875rem;">
|
|
1321
|
+
Before your domain is verified, emails can only be sent from <code>onboarding@resend.dev</code> (for testing).
|
|
1322
|
+
<a href="https://resend.com/docs/dashboard/domains/introduction" target="_blank" style="color: var(--primary);">Learn more about domain verification →</a>
|
|
1323
|
+
</p>
|
|
1324
|
+
</div>
|
|
1325
|
+
</div>
|
|
1326
|
+
|
|
1327
|
+
<div class="button-group">
|
|
1328
|
+
<button class="btn-secondary" id="btn-back-email">Back</button>
|
|
1329
|
+
<button class="btn-primary" id="btn-continue-email">Continue</button>
|
|
1330
|
+
</div>
|
|
1331
|
+
</div>
|
|
1332
|
+
|
|
1333
|
+
<!-- Step 5: Provisioning -->
|
|
1039
1334
|
<div id="section-provision" class="card hidden">
|
|
1040
1335
|
<h2 class="card-title">
|
|
1041
1336
|
Resource Provisioning
|
|
@@ -1307,6 +1602,10 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1307
1602
|
2: document.getElementById('step-2'),
|
|
1308
1603
|
3: document.getElementById('step-3'),
|
|
1309
1604
|
4: document.getElementById('step-4'),
|
|
1605
|
+
5: document.getElementById('step-5'),
|
|
1606
|
+
6: document.getElementById('step-6'),
|
|
1607
|
+
7: document.getElementById('step-7'),
|
|
1608
|
+
8: document.getElementById('step-8'),
|
|
1310
1609
|
};
|
|
1311
1610
|
|
|
1312
1611
|
const sections = {
|
|
@@ -1315,6 +1614,8 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1315
1614
|
mode: document.getElementById('section-mode'),
|
|
1316
1615
|
loadConfig: document.getElementById('section-load-config'),
|
|
1317
1616
|
config: document.getElementById('section-config'),
|
|
1617
|
+
database: document.getElementById('section-database'),
|
|
1618
|
+
email: document.getElementById('section-email'),
|
|
1318
1619
|
provision: document.getElementById('section-provision'),
|
|
1319
1620
|
deploy: document.getElementById('section-deploy'),
|
|
1320
1621
|
complete: document.getElementById('section-complete'),
|
|
@@ -1346,7 +1647,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1346
1647
|
// Step navigation
|
|
1347
1648
|
function setStep(step) {
|
|
1348
1649
|
currentStep = step;
|
|
1349
|
-
for (let i = 1; i <=
|
|
1650
|
+
for (let i = 1; i <= 7; i++) {
|
|
1350
1651
|
const el = steps[i];
|
|
1351
1652
|
el.className = 'step ' + (i < step ? 'step-complete' : i === step ? 'step-active' : 'step-pending');
|
|
1352
1653
|
}
|
|
@@ -1577,28 +1878,80 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1577
1878
|
document.getElementById('btn-load-config').addEventListener('click', async () => {
|
|
1578
1879
|
if (!loadedConfig) return;
|
|
1579
1880
|
|
|
1580
|
-
//
|
|
1881
|
+
// Support both new format (v1.0.0) and old format (v0.1.x)
|
|
1882
|
+
const isNewFormat = loadedConfig.version === '1.0.0' || loadedConfig.environment?.prefix;
|
|
1883
|
+
|
|
1884
|
+
// Extract values (with fallback for old format)
|
|
1885
|
+
const env = isNewFormat
|
|
1886
|
+
? loadedConfig.environment?.prefix
|
|
1887
|
+
: loadedConfig.env || 'prod';
|
|
1888
|
+
|
|
1889
|
+
const apiDomain = isNewFormat
|
|
1890
|
+
? loadedConfig.urls?.api?.custom
|
|
1891
|
+
: loadedConfig.apiDomain;
|
|
1892
|
+
|
|
1893
|
+
const loginUiDomain = isNewFormat
|
|
1894
|
+
? loadedConfig.urls?.loginUi?.custom
|
|
1895
|
+
: loadedConfig.loginUiDomain;
|
|
1896
|
+
|
|
1897
|
+
const adminUiDomain = isNewFormat
|
|
1898
|
+
? loadedConfig.urls?.adminUi?.custom
|
|
1899
|
+
: loadedConfig.adminUiDomain;
|
|
1900
|
+
|
|
1901
|
+
const tenant = loadedConfig.tenant || {
|
|
1902
|
+
name: 'default',
|
|
1903
|
+
displayName: 'Default Tenant',
|
|
1904
|
+
multiTenant: false,
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
const components = loadedConfig.components || {
|
|
1908
|
+
api: true,
|
|
1909
|
+
loginUi: true,
|
|
1910
|
+
adminUi: true,
|
|
1911
|
+
saml: false,
|
|
1912
|
+
async: false,
|
|
1913
|
+
vc: false,
|
|
1914
|
+
bridge: true,
|
|
1915
|
+
policy: true,
|
|
1916
|
+
};
|
|
1917
|
+
|
|
1918
|
+
// Build internal config
|
|
1581
1919
|
config = {
|
|
1582
|
-
env
|
|
1583
|
-
apiDomain:
|
|
1584
|
-
loginUiDomain:
|
|
1585
|
-
adminUiDomain:
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
loginUi: true,
|
|
1589
|
-
adminUi: true,
|
|
1590
|
-
saml: false,
|
|
1591
|
-
async: false,
|
|
1592
|
-
vc: false,
|
|
1593
|
-
},
|
|
1920
|
+
env,
|
|
1921
|
+
apiDomain: apiDomain || null,
|
|
1922
|
+
loginUiDomain: loginUiDomain || null,
|
|
1923
|
+
adminUiDomain: adminUiDomain || null,
|
|
1924
|
+
tenant,
|
|
1925
|
+
components,
|
|
1594
1926
|
};
|
|
1595
1927
|
|
|
1596
1928
|
// Set form values
|
|
1597
1929
|
document.getElementById('env').value = config.env;
|
|
1598
|
-
document.getElementById('
|
|
1930
|
+
document.getElementById('base-domain').value = config.tenant?.baseDomain || config.apiDomain || '';
|
|
1599
1931
|
document.getElementById('login-domain').value = config.loginUiDomain || '';
|
|
1600
1932
|
document.getElementById('admin-domain').value = config.adminUiDomain || '';
|
|
1601
|
-
|
|
1933
|
+
document.getElementById('tenant-name').value = config.tenant?.name || 'default';
|
|
1934
|
+
document.getElementById('tenant-display').value = config.tenant?.displayName || 'Default Tenant';
|
|
1935
|
+
document.getElementById('naked-domain').checked = config.tenant?.nakedDomain || false;
|
|
1936
|
+
|
|
1937
|
+
// Set component checkboxes
|
|
1938
|
+
if (document.getElementById('comp-login-ui')) {
|
|
1939
|
+
document.getElementById('comp-login-ui').checked = components.loginUi !== false;
|
|
1940
|
+
}
|
|
1941
|
+
if (document.getElementById('comp-admin-ui')) {
|
|
1942
|
+
document.getElementById('comp-admin-ui').checked = components.adminUi !== false;
|
|
1943
|
+
}
|
|
1944
|
+
if (document.getElementById('comp-saml')) {
|
|
1945
|
+
document.getElementById('comp-saml').checked = components.saml === true;
|
|
1946
|
+
}
|
|
1947
|
+
if (document.getElementById('comp-async')) {
|
|
1948
|
+
document.getElementById('comp-async').checked = components.async === true;
|
|
1949
|
+
}
|
|
1950
|
+
if (document.getElementById('comp-vc')) {
|
|
1951
|
+
document.getElementById('comp-vc').checked = components.vc === true;
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
// Trigger env input to update preview/default labels
|
|
1602
1955
|
document.getElementById('env').dispatchEvent(new Event('input'));
|
|
1603
1956
|
|
|
1604
1957
|
// Skip to provisioning if resources already exist
|
|
@@ -1873,15 +2226,145 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1873
2226
|
updateResourcePreview(env);
|
|
1874
2227
|
updateProvisionButtons();
|
|
1875
2228
|
|
|
1876
|
-
|
|
1877
|
-
|
|
2229
|
+
// Go to database configuration step
|
|
2230
|
+
setStep(4);
|
|
2231
|
+
showSection('database');
|
|
1878
2232
|
});
|
|
1879
2233
|
|
|
1880
2234
|
document.getElementById('btn-back-config').addEventListener('click', () => {
|
|
1881
|
-
|
|
2235
|
+
// Go back to email configuration (previous step in the flow)
|
|
2236
|
+
setStep(5);
|
|
2237
|
+
showSection('email');
|
|
2238
|
+
});
|
|
2239
|
+
|
|
2240
|
+
// Database configuration handlers
|
|
2241
|
+
document.getElementById('btn-back-database').addEventListener('click', () => {
|
|
2242
|
+
setStep(3);
|
|
1882
2243
|
showSection('config');
|
|
1883
2244
|
});
|
|
1884
2245
|
|
|
2246
|
+
document.getElementById('btn-continue-database').addEventListener('click', () => {
|
|
2247
|
+
// Get selected values
|
|
2248
|
+
const coreLocation = document.querySelector('input[name="db-core-location"]:checked').value;
|
|
2249
|
+
const piiLocation = document.querySelector('input[name="db-pii-location"]:checked').value;
|
|
2250
|
+
|
|
2251
|
+
// Parse location vs jurisdiction
|
|
2252
|
+
function parseDbLocation(value) {
|
|
2253
|
+
if (value === 'eu') {
|
|
2254
|
+
return { location: 'auto', jurisdiction: 'eu' };
|
|
2255
|
+
}
|
|
2256
|
+
return { location: value, jurisdiction: 'none' };
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
// Add database config to config object
|
|
2260
|
+
config.database = {
|
|
2261
|
+
core: parseDbLocation(coreLocation),
|
|
2262
|
+
pii: parseDbLocation(piiLocation),
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
// Proceed to email configuration
|
|
2266
|
+
setStep(5);
|
|
2267
|
+
showSection('email');
|
|
2268
|
+
});
|
|
2269
|
+
|
|
2270
|
+
// Email configuration handlers
|
|
2271
|
+
// Toggle resend config form visibility
|
|
2272
|
+
document.querySelectorAll('input[name="email-setup-choice"]').forEach(radio => {
|
|
2273
|
+
radio.addEventListener('change', () => {
|
|
2274
|
+
const resendForm = document.getElementById('resend-config-form');
|
|
2275
|
+
const choice = document.querySelector('input[name="email-setup-choice"]:checked').value;
|
|
2276
|
+
if (choice === 'configure') {
|
|
2277
|
+
resendForm.classList.remove('hidden');
|
|
2278
|
+
} else {
|
|
2279
|
+
resendForm.classList.add('hidden');
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
2282
|
+
});
|
|
2283
|
+
|
|
2284
|
+
document.getElementById('btn-back-email').addEventListener('click', () => {
|
|
2285
|
+
setStep(4);
|
|
2286
|
+
showSection('database');
|
|
2287
|
+
});
|
|
2288
|
+
|
|
2289
|
+
document.getElementById('btn-continue-email').addEventListener('click', async () => {
|
|
2290
|
+
const choice = document.querySelector('input[name="email-setup-choice"]:checked').value;
|
|
2291
|
+
const btn = document.getElementById('btn-continue-email');
|
|
2292
|
+
|
|
2293
|
+
if (choice === 'configure') {
|
|
2294
|
+
// Validate and store email configuration
|
|
2295
|
+
const apiKey = document.getElementById('resend-api-key').value.trim();
|
|
2296
|
+
const fromAddress = document.getElementById('email-from-address').value.trim();
|
|
2297
|
+
const fromName = document.getElementById('email-from-name').value.trim();
|
|
2298
|
+
|
|
2299
|
+
// Validate API key format
|
|
2300
|
+
if (!apiKey) {
|
|
2301
|
+
alert('Please enter your Resend API key');
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
if (!apiKey.startsWith('re_')) {
|
|
2305
|
+
if (!confirm('API key does not start with "re_". This may not be a valid Resend API key. Continue anyway?')) {
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// Validate email address
|
|
2311
|
+
if (!fromAddress) {
|
|
2312
|
+
alert('Please enter a From email address');
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
if (!fromAddress.includes('@')) {
|
|
2316
|
+
alert('Please enter a valid email address');
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
// Save email configuration to server
|
|
2321
|
+
btn.disabled = true;
|
|
2322
|
+
btn.textContent = 'Saving...';
|
|
2323
|
+
|
|
2324
|
+
try {
|
|
2325
|
+
const result = await api('/email/configure', {
|
|
2326
|
+
method: 'POST',
|
|
2327
|
+
body: {
|
|
2328
|
+
env: config.env,
|
|
2329
|
+
provider: 'resend',
|
|
2330
|
+
apiKey: apiKey,
|
|
2331
|
+
fromAddress: fromAddress,
|
|
2332
|
+
fromName: fromName || undefined,
|
|
2333
|
+
},
|
|
2334
|
+
});
|
|
2335
|
+
|
|
2336
|
+
if (!result.success) {
|
|
2337
|
+
throw new Error(result.error || 'Failed to save email configuration');
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
// Store email configuration (without apiKey for config file)
|
|
2341
|
+
config.email = {
|
|
2342
|
+
provider: 'resend',
|
|
2343
|
+
fromAddress: fromAddress,
|
|
2344
|
+
fromName: fromName || undefined,
|
|
2345
|
+
configured: true,
|
|
2346
|
+
};
|
|
2347
|
+
} catch (error) {
|
|
2348
|
+
alert('Failed to save email configuration: ' + error.message);
|
|
2349
|
+
btn.disabled = false;
|
|
2350
|
+
btn.textContent = 'Continue';
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
btn.disabled = false;
|
|
2355
|
+
btn.textContent = 'Continue';
|
|
2356
|
+
} else {
|
|
2357
|
+
// Configure later - no email provider
|
|
2358
|
+
config.email = {
|
|
2359
|
+
provider: 'none',
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
// Proceed to provision
|
|
2364
|
+
setStep(6);
|
|
2365
|
+
showSection('provision');
|
|
2366
|
+
});
|
|
2367
|
+
|
|
1885
2368
|
// Provision
|
|
1886
2369
|
document.getElementById('btn-provision').addEventListener('click', async () => {
|
|
1887
2370
|
const btn = document.getElementById('btn-provision');
|
|
@@ -1953,7 +2436,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1953
2436
|
|
|
1954
2437
|
const result = await api('/provision', {
|
|
1955
2438
|
method: 'POST',
|
|
1956
|
-
body: { env: config.env },
|
|
2439
|
+
body: { env: config.env, databaseConfig: config.database },
|
|
1957
2440
|
});
|
|
1958
2441
|
|
|
1959
2442
|
// Stop polling
|
|
@@ -1999,12 +2482,12 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
1999
2482
|
|
|
2000
2483
|
// Continue to Deploy button
|
|
2001
2484
|
document.getElementById('btn-goto-deploy').addEventListener('click', () => {
|
|
2002
|
-
setStep(
|
|
2485
|
+
setStep(7);
|
|
2003
2486
|
showSection('deploy');
|
|
2004
2487
|
});
|
|
2005
2488
|
|
|
2006
2489
|
document.getElementById('btn-back-provision').addEventListener('click', () => {
|
|
2007
|
-
setStep(
|
|
2490
|
+
setStep(6);
|
|
2008
2491
|
// Update buttons based on provisioning status
|
|
2009
2492
|
updateProvisionButtons();
|
|
2010
2493
|
// Show resource preview if not completed
|
|
@@ -2211,6 +2694,7 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2211
2694
|
urlsEl.appendChild(debugDiv);
|
|
2212
2695
|
}
|
|
2213
2696
|
|
|
2697
|
+
setStep(8);
|
|
2214
2698
|
showSection('complete');
|
|
2215
2699
|
}
|
|
2216
2700
|
|
|
@@ -2293,19 +2777,97 @@ export function getHtmlTemplate(sessionToken, manageOnly) {
|
|
|
2293
2777
|
}
|
|
2294
2778
|
}
|
|
2295
2779
|
|
|
2296
|
-
// Save configuration to file
|
|
2780
|
+
// Save configuration to file (AuthrimConfigSchema format)
|
|
2297
2781
|
function saveConfigToFile() {
|
|
2298
|
-
if (!config) {
|
|
2782
|
+
if (!config || !config.env) {
|
|
2299
2783
|
alert('No configuration to save');
|
|
2300
2784
|
return;
|
|
2301
2785
|
}
|
|
2302
2786
|
|
|
2787
|
+
const now = new Date().toISOString();
|
|
2788
|
+
const env = config.env;
|
|
2789
|
+
|
|
2790
|
+
// Calculate auto-generated URLs
|
|
2791
|
+
const workersDomain = env + '-ar-router.workers.dev';
|
|
2792
|
+
const pagesDomain = env + '-ar-ui.pages.dev';
|
|
2793
|
+
|
|
2794
|
+
// Build issuer URL based on tenant settings
|
|
2795
|
+
let issuerAutoUrl = 'https://' + workersDomain;
|
|
2796
|
+
if (config.tenant && config.tenant.baseDomain) {
|
|
2797
|
+
if (config.tenant.nakedDomain) {
|
|
2798
|
+
issuerAutoUrl = 'https://' + config.tenant.baseDomain;
|
|
2799
|
+
} else {
|
|
2800
|
+
const tenantName = config.tenant.name || 'default';
|
|
2801
|
+
issuerAutoUrl = 'https://' + tenantName + '.' + config.tenant.baseDomain;
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
// Build config in AuthrimConfigSchema format
|
|
2303
2806
|
const configToSave = {
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2807
|
+
version: '1.0.0',
|
|
2808
|
+
createdAt: now,
|
|
2809
|
+
updatedAt: now,
|
|
2810
|
+
environment: {
|
|
2811
|
+
prefix: env,
|
|
2812
|
+
},
|
|
2813
|
+
urls: {
|
|
2814
|
+
api: {
|
|
2815
|
+
custom: config.apiDomain || null,
|
|
2816
|
+
auto: config.apiDomain ? issuerAutoUrl : 'https://' + workersDomain,
|
|
2817
|
+
},
|
|
2818
|
+
loginUi: {
|
|
2819
|
+
custom: config.loginUiDomain || null,
|
|
2820
|
+
auto: 'https://' + pagesDomain,
|
|
2821
|
+
},
|
|
2822
|
+
adminUi: {
|
|
2823
|
+
custom: config.adminUiDomain || null,
|
|
2824
|
+
auto: 'https://' + pagesDomain + '/admin',
|
|
2825
|
+
},
|
|
2826
|
+
},
|
|
2827
|
+
tenant: {
|
|
2828
|
+
name: config.tenant?.name || 'default',
|
|
2829
|
+
displayName: config.tenant?.displayName || 'Default Tenant',
|
|
2830
|
+
multiTenant: config.tenant?.multiTenant || false,
|
|
2831
|
+
baseDomain: config.tenant?.baseDomain || undefined,
|
|
2832
|
+
},
|
|
2833
|
+
components: config.components || {
|
|
2834
|
+
api: true,
|
|
2835
|
+
loginUi: true,
|
|
2836
|
+
adminUi: true,
|
|
2837
|
+
saml: false,
|
|
2838
|
+
async: false,
|
|
2839
|
+
vc: false,
|
|
2840
|
+
bridge: true,
|
|
2841
|
+
policy: true,
|
|
2842
|
+
},
|
|
2843
|
+
keys: {
|
|
2844
|
+
secretsPath: './.keys/',
|
|
2845
|
+
},
|
|
2846
|
+
database: config.database || {
|
|
2847
|
+
core: { location: 'auto', jurisdiction: 'none' },
|
|
2848
|
+
pii: { location: 'auto', jurisdiction: 'none' },
|
|
2849
|
+
},
|
|
2850
|
+
features: {
|
|
2851
|
+
email: {
|
|
2852
|
+
provider: config.email?.provider || 'none',
|
|
2853
|
+
fromAddress: config.email?.fromAddress || undefined,
|
|
2854
|
+
fromName: config.email?.fromName || undefined,
|
|
2855
|
+
configured: config.email?.provider === 'resend' && config.email?.apiKey ? true : false,
|
|
2856
|
+
},
|
|
2857
|
+
},
|
|
2307
2858
|
};
|
|
2308
2859
|
|
|
2860
|
+
// Remove undefined values for cleaner output
|
|
2861
|
+
if (!configToSave.tenant.baseDomain) {
|
|
2862
|
+
delete configToSave.tenant.baseDomain;
|
|
2863
|
+
}
|
|
2864
|
+
if (!configToSave.features.email.fromAddress) {
|
|
2865
|
+
delete configToSave.features.email.fromAddress;
|
|
2866
|
+
}
|
|
2867
|
+
if (!configToSave.features.email.fromName) {
|
|
2868
|
+
delete configToSave.features.email.fromName;
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2309
2871
|
const blob = new Blob([JSON.stringify(configToSave, null, 2)], { type: 'application/json' });
|
|
2310
2872
|
const url = URL.createObjectURL(blob);
|
|
2311
2873
|
const a = document.createElement('a');
|