@authrim/setup 0.1.47 → 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/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  > CLI and Web UI for setting up Authrim OIDC Provider on Cloudflare Workers
4
4
 
5
+ > ⚠️ **WARNING: This project is still under active development and does not work correctly yet!**
6
+ >
7
+ > The Admin UI is incomplete and does not support login functionality. Please wait for a stable release before using in production.
8
+
5
9
  [![npm version](https://img.shields.io/npm/v/@authrim/setup.svg)](https://www.npmjs.com/package/@authrim/setup)
6
10
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/sgrastar/authrim/blob/main/LICENSE)
7
11
 
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkDH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAuYD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuErE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkDH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4YD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuErE"}
@@ -24,12 +24,17 @@ function printBanner() {
24
24
  console.log('');
25
25
  console.log(chalk.blue('╔═══════════════════════════════════════════════════════════╗'));
26
26
  console.log(chalk.blue('║') +
27
- chalk.bold.white(' 🔐 Authrim Setup v0.1.47 ') +
27
+ chalk.bold.white(' 🔐 Authrim Setup v0.1.49 ') +
28
28
  chalk.blue('║'));
29
29
  console.log(chalk.blue('║') +
30
30
  chalk.gray(' OIDC Provider on Cloudflare Workers ') +
31
31
  chalk.blue('║'));
32
32
  console.log(chalk.blue('╚═══════════════════════════════════════════════════════════╝'));
33
+ console.log('');
34
+ console.log(chalk.bgYellow.black(' ⚠️ WARNING: Under Development! '));
35
+ console.log(chalk.yellow(' This project does not work correctly yet.'));
36
+ console.log(chalk.yellow(' Admin UI is incomplete and does not support login.'));
37
+ console.log('');
33
38
  console.log(chalk.gray(' Press Ctrl+C at any time to exit'));
34
39
  console.log('');
35
40
  }
@@ -714,8 +719,112 @@ async function runQuickSetup(options) {
714
719
  default: '',
715
720
  });
716
721
  }
722
+ // Database Configuration
723
+ console.log('');
724
+ console.log(chalk.blue('━━━ Database Configuration ━━━'));
725
+ console.log(chalk.yellow('⚠️ Database region cannot be changed after creation.'));
726
+ console.log('');
727
+ const locationChoices = [
728
+ { name: 'Automatic (nearest to you)', value: 'auto' },
729
+ { name: '── Location Hints ──', value: '__separator1__', disabled: true },
730
+ { name: 'North America (West)', value: 'wnam' },
731
+ { name: 'North America (East)', value: 'enam' },
732
+ { name: 'Europe (West)', value: 'weur' },
733
+ { name: 'Europe (East)', value: 'eeur' },
734
+ { name: 'Asia Pacific', value: 'apac' },
735
+ { name: 'Oceania', value: 'oc' },
736
+ { name: '── Jurisdiction (Compliance) ──', value: '__separator2__', disabled: true },
737
+ { name: 'EU Jurisdiction (GDPR compliance)', value: 'eu' },
738
+ ];
739
+ console.log(chalk.gray(' Core DB: Stores OAuth clients, tokens, sessions, audit logs'));
740
+ const coreDbLocation = await select({
741
+ message: 'Core Database region',
742
+ choices: locationChoices,
743
+ default: 'auto',
744
+ });
745
+ console.log('');
746
+ console.log(chalk.gray(' PII DB: Stores user profiles, credentials, personal data'));
747
+ const piiDbLocation = await select({
748
+ message: 'PII Database region',
749
+ choices: locationChoices,
750
+ default: 'auto',
751
+ });
752
+ // Parse location vs jurisdiction
753
+ function parseDbLocation(value) {
754
+ if (value === 'eu') {
755
+ return { location: 'auto', jurisdiction: 'eu' };
756
+ }
757
+ return {
758
+ location: value,
759
+ jurisdiction: 'none',
760
+ };
761
+ }
762
+ // Email Provider Configuration
763
+ console.log('');
764
+ console.log(chalk.blue('━━━ Email Provider ━━━'));
765
+ console.log(chalk.gray('Configure email sending for magic links and verification codes.'));
766
+ console.log('');
767
+ const configureEmail = await confirm({
768
+ message: 'Configure email provider now?',
769
+ default: false,
770
+ });
771
+ let emailConfig = { provider: 'none' };
772
+ if (configureEmail) {
773
+ console.log('');
774
+ console.log(chalk.gray('Resend is the supported email provider.'));
775
+ console.log(chalk.gray('Get your API key at: https://resend.com/api-keys'));
776
+ console.log(chalk.gray('Set up domain at: https://resend.com/domains'));
777
+ console.log('');
778
+ const resendApiKey = await password({
779
+ message: 'Resend API key',
780
+ mask: '*',
781
+ validate: (value) => {
782
+ if (!value.trim())
783
+ return 'API key is required';
784
+ if (!value.startsWith('re_')) {
785
+ return 'Warning: Resend API keys typically start with "re_"';
786
+ }
787
+ return true;
788
+ },
789
+ });
790
+ const fromAddress = await input({
791
+ message: 'From email address',
792
+ default: 'noreply@yourdomain.com',
793
+ validate: (value) => {
794
+ if (!value.includes('@'))
795
+ return 'Please enter a valid email address';
796
+ return true;
797
+ },
798
+ });
799
+ const fromName = await input({
800
+ message: 'From display name (optional)',
801
+ default: 'Authrim',
802
+ });
803
+ emailConfig = {
804
+ provider: 'resend',
805
+ fromAddress,
806
+ fromName: fromName || undefined,
807
+ apiKey: resendApiKey,
808
+ };
809
+ console.log('');
810
+ console.log(chalk.yellow('⚠️ Domain verification required for sending from your own domain.'));
811
+ console.log(chalk.gray(' See: https://resend.com/docs/dashboard/domains/introduction'));
812
+ }
717
813
  // Create configuration
718
814
  const config = createDefaultConfig(envPrefix);
815
+ config.database = {
816
+ core: parseDbLocation(coreDbLocation),
817
+ pii: parseDbLocation(piiDbLocation),
818
+ };
819
+ config.features = {
820
+ ...config.features,
821
+ email: {
822
+ provider: emailConfig.provider,
823
+ fromAddress: emailConfig.fromAddress,
824
+ fromName: emailConfig.fromName,
825
+ configured: emailConfig.provider === 'resend',
826
+ },
827
+ };
719
828
  config.urls = {
720
829
  api: {
721
830
  custom: apiDomain || null,
@@ -745,6 +854,18 @@ async function runQuickSetup(options) {
745
854
  console.log(` Login UI: ${chalk.cyan(config.urls.loginUi.custom || config.urls.loginUi.auto)}`);
746
855
  console.log(` Admin UI: ${chalk.cyan(config.urls.adminUi.custom || config.urls.adminUi.auto)}`);
747
856
  console.log('');
857
+ console.log(chalk.bold('Email:'));
858
+ if (emailConfig.provider === 'resend') {
859
+ console.log(` Provider: ${chalk.cyan('Resend')}`);
860
+ console.log(` From Address: ${chalk.cyan(emailConfig.fromAddress)}`);
861
+ if (emailConfig.fromName) {
862
+ console.log(` From Name: ${chalk.cyan(emailConfig.fromName)}`);
863
+ }
864
+ }
865
+ else {
866
+ console.log(` Provider: ${chalk.gray('Not configured (configure later)')}`);
867
+ }
868
+ console.log('');
748
869
  const proceed = await confirm({
749
870
  message: 'Start setup with this configuration?',
750
871
  default: true,
@@ -753,6 +874,19 @@ async function runQuickSetup(options) {
753
874
  console.log(chalk.yellow('Setup cancelled.'));
754
875
  return;
755
876
  }
877
+ // Save email secrets if configured
878
+ if (emailConfig.provider === 'resend' && emailConfig.apiKey) {
879
+ const keysDir = `.keys/${envPrefix}`;
880
+ await import('node:fs/promises').then(async (fs) => {
881
+ await fs.mkdir(keysDir, { recursive: true });
882
+ await fs.writeFile(`${keysDir}/resend_api_key.txt`, emailConfig.apiKey.trim());
883
+ await fs.writeFile(`${keysDir}/email_from.txt`, emailConfig.fromAddress.trim());
884
+ if (emailConfig.fromName) {
885
+ await fs.writeFile(`${keysDir}/email_from_name.txt`, emailConfig.fromName.trim());
886
+ }
887
+ });
888
+ console.log(chalk.gray(`📧 Email secrets saved to ${keysDir}/`));
889
+ }
756
890
  // Run setup
757
891
  await executeSetup(config, cfApiToken, options.keep);
758
892
  }
@@ -995,16 +1129,59 @@ async function runNormalSetup(options) {
995
1129
  message: 'Enable Cloudflare R2? (for avatars)',
996
1130
  default: false,
997
1131
  });
998
- const emailProvider = await select({
1132
+ const emailProviderChoice = await select({
999
1133
  message: 'Select email provider',
1000
1134
  choices: [
1001
- { value: 'none', name: 'None (email disabled)' },
1135
+ { value: 'none', name: 'None (configure later)' },
1002
1136
  { value: 'resend', name: 'Resend' },
1003
- { value: 'sendgrid', name: 'SendGrid' },
1004
- { value: 'ses', name: 'AWS SES' },
1137
+ { value: 'sendgrid', name: 'SendGrid (coming soon)', disabled: true },
1138
+ { value: 'ses', name: 'AWS SES (coming soon)', disabled: true },
1005
1139
  ],
1006
1140
  default: 'none',
1007
1141
  });
1142
+ // Email configuration details
1143
+ let emailConfigNormal = { provider: 'none' };
1144
+ if (emailProviderChoice === 'resend') {
1145
+ console.log('');
1146
+ console.log(chalk.blue('━━━ Resend Configuration ━━━'));
1147
+ console.log(chalk.gray('Get your API key at: https://resend.com/api-keys'));
1148
+ console.log(chalk.gray('Set up domain at: https://resend.com/domains'));
1149
+ console.log('');
1150
+ const resendApiKey = await password({
1151
+ message: 'Resend API key',
1152
+ mask: '*',
1153
+ validate: (value) => {
1154
+ if (!value.trim())
1155
+ return 'API key is required';
1156
+ if (!value.startsWith('re_')) {
1157
+ return 'Warning: Resend API keys typically start with "re_"';
1158
+ }
1159
+ return true;
1160
+ },
1161
+ });
1162
+ const fromAddress = await input({
1163
+ message: 'From email address',
1164
+ default: 'noreply@yourdomain.com',
1165
+ validate: (value) => {
1166
+ if (!value.includes('@'))
1167
+ return 'Please enter a valid email address';
1168
+ return true;
1169
+ },
1170
+ });
1171
+ const fromName = await input({
1172
+ message: 'From display name (optional)',
1173
+ default: 'Authrim',
1174
+ });
1175
+ emailConfigNormal = {
1176
+ provider: 'resend',
1177
+ fromAddress,
1178
+ fromName: fromName || undefined,
1179
+ apiKey: resendApiKey,
1180
+ };
1181
+ console.log('');
1182
+ console.log(chalk.yellow('⚠️ Domain verification required for sending from your own domain.'));
1183
+ console.log(chalk.gray(' See: https://resend.com/docs/dashboard/domains/introduction'));
1184
+ }
1008
1185
  // Step 7: Advanced OIDC settings
1009
1186
  const configureOidc = await confirm({
1010
1187
  message: 'Configure OIDC settings? (token TTL, etc.)',
@@ -1091,9 +1268,54 @@ async function runNormalSetup(options) {
1091
1268
  });
1092
1269
  refreshTokenShards = parseInt(refreshTokenShardsStr, 10);
1093
1270
  }
1271
+ // Step 9: Database Configuration
1272
+ console.log('');
1273
+ console.log(chalk.blue('━━━ Database Configuration ━━━'));
1274
+ console.log(chalk.yellow('⚠️ Database region cannot be changed after creation.'));
1275
+ console.log('');
1276
+ const dbLocationChoices = [
1277
+ { name: 'Automatic (nearest to you)', value: 'auto' },
1278
+ { name: '── Location Hints ──', value: '__separator1__', disabled: true },
1279
+ { name: 'North America (West)', value: 'wnam' },
1280
+ { name: 'North America (East)', value: 'enam' },
1281
+ { name: 'Europe (West)', value: 'weur' },
1282
+ { name: 'Europe (East)', value: 'eeur' },
1283
+ { name: 'Asia Pacific', value: 'apac' },
1284
+ { name: 'Oceania', value: 'oc' },
1285
+ { name: '── Jurisdiction (Compliance) ──', value: '__separator2__', disabled: true },
1286
+ { name: 'EU Jurisdiction (GDPR compliance)', value: 'eu' },
1287
+ ];
1288
+ console.log(chalk.gray(' Core DB: Stores OAuth clients, tokens, sessions, audit logs'));
1289
+ const coreDbLocation = await select({
1290
+ message: 'Core Database region',
1291
+ choices: dbLocationChoices,
1292
+ default: 'auto',
1293
+ });
1294
+ console.log('');
1295
+ console.log(chalk.gray(' PII DB: Stores user profiles, credentials, personal data'));
1296
+ console.log(chalk.gray(' Consider your data protection requirements.'));
1297
+ const piiDbLocation = await select({
1298
+ message: 'PII Database region',
1299
+ choices: dbLocationChoices,
1300
+ default: 'auto',
1301
+ });
1302
+ // Parse location vs jurisdiction
1303
+ function parseDbLocationNormal(value) {
1304
+ if (value === 'eu') {
1305
+ return { location: 'auto', jurisdiction: 'eu' };
1306
+ }
1307
+ return {
1308
+ location: value,
1309
+ jurisdiction: 'none',
1310
+ };
1311
+ }
1094
1312
  // Create configuration
1095
1313
  const config = createDefaultConfig(envPrefix);
1096
1314
  config.profile = profile;
1315
+ config.database = {
1316
+ core: parseDbLocationNormal(coreDbLocation),
1317
+ pii: parseDbLocationNormal(piiDbLocation),
1318
+ };
1097
1319
  config.tenant = {
1098
1320
  name: tenantName,
1099
1321
  displayName: tenantDisplayName,
@@ -1136,7 +1358,12 @@ async function runNormalSetup(options) {
1136
1358
  config.features = {
1137
1359
  queue: { enabled: enableQueue },
1138
1360
  r2: { enabled: enableR2 },
1139
- email: { provider: emailProvider },
1361
+ email: {
1362
+ provider: emailConfigNormal.provider,
1363
+ fromAddress: emailConfigNormal.fromAddress,
1364
+ fromName: emailConfigNormal.fromName,
1365
+ configured: emailConfigNormal.provider === 'resend',
1366
+ },
1140
1367
  };
1141
1368
  // Show summary
1142
1369
  console.log('');
@@ -1185,7 +1412,18 @@ async function runNormalSetup(options) {
1185
1412
  console.log(chalk.bold('Feature Flags:'));
1186
1413
  console.log(` Queue: ${enableQueue ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1187
1414
  console.log(` R2: ${enableR2 ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1188
- console.log(` Email: ${chalk.cyan(emailProvider)}`);
1415
+ console.log('');
1416
+ console.log(chalk.bold('Email:'));
1417
+ if (emailConfigNormal.provider === 'resend') {
1418
+ console.log(` Provider: ${chalk.cyan('Resend')}`);
1419
+ console.log(` From Address: ${chalk.cyan(emailConfigNormal.fromAddress)}`);
1420
+ if (emailConfigNormal.fromName) {
1421
+ console.log(` From Name: ${chalk.cyan(emailConfigNormal.fromName)}`);
1422
+ }
1423
+ }
1424
+ else {
1425
+ console.log(` Provider: ${chalk.gray('Not configured (configure later)')}`);
1426
+ }
1189
1427
  console.log('');
1190
1428
  console.log(chalk.bold('OIDC Settings:'));
1191
1429
  console.log(` Access TTL: ${chalk.cyan(accessTokenTtl + 'sec')}`);
@@ -1197,6 +1435,20 @@ async function runNormalSetup(options) {
1197
1435
  console.log(` Auth Code: ${chalk.cyan(authCodeShards)} shards`);
1198
1436
  console.log(` Refresh Token: ${chalk.cyan(refreshTokenShards)} shards`);
1199
1437
  console.log('');
1438
+ console.log(chalk.bold('Database:'));
1439
+ const coreDbDisplay = coreDbLocation === 'eu'
1440
+ ? 'EU Jurisdiction'
1441
+ : coreDbLocation === 'auto'
1442
+ ? 'Automatic'
1443
+ : coreDbLocation.toUpperCase();
1444
+ const piiDbDisplay = piiDbLocation === 'eu'
1445
+ ? 'EU Jurisdiction'
1446
+ : piiDbLocation === 'auto'
1447
+ ? 'Automatic'
1448
+ : piiDbLocation.toUpperCase();
1449
+ console.log(` Core DB: ${chalk.cyan(coreDbDisplay)}`);
1450
+ console.log(` PII DB: ${chalk.cyan(piiDbDisplay)}`);
1451
+ console.log('');
1200
1452
  const proceed = await confirm({
1201
1453
  message: 'Start setup with this configuration?',
1202
1454
  default: true,
@@ -1205,6 +1457,19 @@ async function runNormalSetup(options) {
1205
1457
  console.log(chalk.yellow('Setup cancelled.'));
1206
1458
  return;
1207
1459
  }
1460
+ // Save email secrets if configured
1461
+ if (emailConfigNormal.provider === 'resend' && emailConfigNormal.apiKey) {
1462
+ const keysDir = `.keys/${envPrefix}`;
1463
+ await import('node:fs/promises').then(async (fs) => {
1464
+ await fs.mkdir(keysDir, { recursive: true });
1465
+ await fs.writeFile(`${keysDir}/resend_api_key.txt`, emailConfigNormal.apiKey.trim());
1466
+ await fs.writeFile(`${keysDir}/email_from.txt`, emailConfigNormal.fromAddress.trim());
1467
+ if (emailConfigNormal.fromName) {
1468
+ await fs.writeFile(`${keysDir}/email_from_name.txt`, emailConfigNormal.fromName.trim());
1469
+ }
1470
+ });
1471
+ console.log(chalk.gray(`📧 Email secrets saved to ${keysDir}/`));
1472
+ }
1208
1473
  await executeSetup(config, cfApiToken, options.keep);
1209
1474
  }
1210
1475
  // =============================================================================
@@ -1295,6 +1560,7 @@ async function executeSetup(config, cfApiToken, keepPath) {
1295
1560
  createKV: true,
1296
1561
  createQueues: config.features.queue?.enabled,
1297
1562
  createR2: config.features.r2?.enabled,
1563
+ databaseConfig: config.database,
1298
1564
  onProgress: (msg) => console.log(` ${msg}`),
1299
1565
  });
1300
1566
  }
@@ -1526,6 +1792,7 @@ async function handleRedeploy(config, configPath) {
1526
1792
  createKV: true,
1527
1793
  createQueues: config.features.queue?.enabled,
1528
1794
  createR2: config.features.r2?.enabled,
1795
+ databaseConfig: config.database,
1529
1796
  onProgress: (msg) => console.log(` ${msg}`),
1530
1797
  });
1531
1798
  // Create and save lock file
@@ -1843,7 +2110,12 @@ async function editFeatures(config) {
1843
2110
  });
1844
2111
  config.features.queue = { enabled: queueEnabled };
1845
2112
  config.features.r2 = { enabled: r2Enabled };
1846
- config.features.email = { provider: emailProvider };
2113
+ config.features.email = {
2114
+ provider: emailProvider,
2115
+ configured: config.features.email?.configured || false,
2116
+ fromAddress: config.features.email?.fromAddress,
2117
+ fromName: config.features.email?.fromName,
2118
+ };
1847
2119
  return true;
1848
2120
  }
1849
2121
  // =============================================================================