oauth-init 0.14.0 → 0.16.0

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.
Files changed (2) hide show
  1. package/dist/index.js +277 -60
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9176,6 +9176,15 @@ var open_default = open;
9176
9176
 
9177
9177
  // src/lib/save-credentials.ts
9178
9178
  import { writeFile, readFile, access } from "fs/promises";
9179
+
9180
+ // src/lib/config.ts
9181
+ var globalConfig = {
9182
+ quiet: false,
9183
+ noOpen: false,
9184
+ skipPrompts: false
9185
+ };
9186
+
9187
+ // src/lib/save-credentials.ts
9179
9188
  async function saveCredentials(clientId, clientSecret, provider, saveOption) {
9180
9189
  const envKeyId = `${provider.toUpperCase()}_CLIENT_ID`;
9181
9190
  const envKeySecret = `${provider.toUpperCase()}_CLIENT_SECRET`;
@@ -9189,14 +9198,38 @@ ${envKeySecret}=${clientSecret}`;
9189
9198
  if (saveOption === "json") {
9190
9199
  const jsonContent = JSON.stringify({ clientId, clientSecret }, null, 2);
9191
9200
  const jsonPath = `${provider}-credentials.json`;
9201
+ if (!globalConfig.skipPrompts) {
9202
+ R2.message("Preview:");
9203
+ R2.message(jsonContent);
9204
+ const confirmSave = await Re({
9205
+ message: `Save to ${jsonPath}?`,
9206
+ initialValue: true
9207
+ });
9208
+ if (Ct(confirmSave) || !confirmSave) {
9209
+ R2.warn("Credentials not saved.");
9210
+ return;
9211
+ }
9212
+ }
9192
9213
  await writeFile(jsonPath, jsonContent);
9193
9214
  R2.success(`Credentials saved to ${jsonPath}`);
9194
9215
  return;
9195
9216
  }
9196
9217
  const envPath = saveOption === "dot-env" ? ".env" : ".env.local";
9218
+ if (!globalConfig.skipPrompts) {
9219
+ R2.message("Preview:");
9220
+ R2.message(newEnvContent);
9221
+ const confirmSave = await Re({
9222
+ message: `Save to ${envPath}?`,
9223
+ initialValue: true
9224
+ });
9225
+ if (Ct(confirmSave) || !confirmSave) {
9226
+ R2.warn("Credentials not saved.");
9227
+ return;
9228
+ }
9229
+ }
9197
9230
  try {
9198
9231
  await access(envPath);
9199
- const shouldAppend = await Re({
9232
+ const shouldAppend = globalConfig.skipPrompts ? true : await Re({
9200
9233
  message: `${envPath} already exists. Append credentials?`,
9201
9234
  initialValue: true
9202
9235
  });
@@ -9215,6 +9248,9 @@ ${envKeySecret}=${clientSecret}`;
9215
9248
 
9216
9249
  // src/lib/ask-save-option.ts
9217
9250
  async function askSaveOption() {
9251
+ if (globalConfig.skipPrompts) {
9252
+ return "dot-env";
9253
+ }
9218
9254
  return Je({
9219
9255
  message: "Where do you want to save the credentials?",
9220
9256
  options: [
@@ -9226,13 +9262,7 @@ async function askSaveOption() {
9226
9262
  });
9227
9263
  }
9228
9264
 
9229
- // src/lib/config.ts
9230
- var globalConfig = {
9231
- quiet: false,
9232
- noOpen: false
9233
- };
9234
-
9235
- // src/lib/google-provider.ts
9265
+ // src/lib/providers/google-provider.ts
9236
9266
  function logStep(message) {
9237
9267
  if (!globalConfig.quiet)
9238
9268
  R2.step(message);
@@ -9326,34 +9356,62 @@ class GoogleAuthProvider {
9326
9356
  const brandUrl = `https://console.cloud.google.com/apis/credentials/consent?project=${projectId}`;
9327
9357
  logMessage(`Google requires manual setup for personal projects.
9328
9358
  Opening: ${brandUrl}`);
9359
+ Ve(`Required Redirect URI:
9360
+ ${_appName}`, "Save this URL");
9329
9361
  if (!globalConfig.noOpen) {
9330
- await open_default(brandUrl);
9362
+ const shouldOpen = globalConfig.skipPrompts ? true : await Re({
9363
+ message: "Open Google Cloud Console?",
9364
+ initialValue: true
9365
+ });
9366
+ if (Ct(shouldOpen))
9367
+ return Ne("Setup aborted.");
9368
+ if (shouldOpen)
9369
+ await open_default(brandUrl);
9331
9370
  }
9332
- Ve(`1. Choose 'External'
9371
+ if (!globalConfig.skipPrompts) {
9372
+ Ve(`1. Choose 'External'
9333
9373
  2. Fill App Name & Email
9334
9374
  3. Click 'Save and Continue' through to the end.`, "Action Required");
9335
- const brandDone = await Ze({
9336
- message: "Press Enter once you've saved the Consent Screen (or type 'skip' if done previously)"
9337
- });
9338
- if (Ct(brandDone))
9339
- return Ne("Setup aborted.");
9375
+ const brandDone = await Ze({
9376
+ message: "Press Enter once you've saved the Consent Screen (or type 'skip' if done previously)"
9377
+ });
9378
+ if (Ct(brandDone))
9379
+ return Ne("Setup aborted.");
9380
+ }
9340
9381
  logStep("Step 2: Create OAuth Client ID");
9341
9382
  const clientUrl = `https://console.cloud.google.com/apis/credentials/oauthclient?project=${projectId}`;
9342
9383
  logMessage(`Opening: ${clientUrl}`);
9384
+ Ve(`Required Redirect URI:
9385
+ ${_appName}`, "Save this URL");
9343
9386
  if (!globalConfig.noOpen) {
9344
- await open_default(clientUrl);
9387
+ const shouldOpen = globalConfig.skipPrompts ? true : await Re({
9388
+ message: "Open OAuth Client creation page?",
9389
+ initialValue: true
9390
+ });
9391
+ if (Ct(shouldOpen))
9392
+ return Ne("Setup aborted.");
9393
+ if (shouldOpen)
9394
+ await open_default(clientUrl);
9345
9395
  }
9346
- Ve(`1. Select 'Web Application'
9396
+ if (!globalConfig.skipPrompts) {
9397
+ Ve(`1. Select 'Web Application'
9347
9398
  2. Add your Redirect URIs
9348
9399
  3. Click 'Create'`, "Action Required");
9349
- const clientId = await Ze({
9400
+ }
9401
+ let clientId;
9402
+ let clientSecret;
9403
+ if (globalConfig.skipPrompts) {
9404
+ R2.error("Client ID and Secret required in non-interactive mode. Run without --skip-prompts");
9405
+ process.exit(1);
9406
+ }
9407
+ clientId = await Ze({
9350
9408
  message: "Paste your Client ID:",
9351
9409
  placeholder: "12345-abcde.apps.googleusercontent.com",
9352
9410
  validate: (value) => value?.includes(".apps.googleusercontent.com") ? undefined : "Invalid format"
9353
9411
  });
9354
9412
  if (Ct(clientId))
9355
9413
  return Ne("Setup aborted.");
9356
- const clientSecret = await He({
9414
+ clientSecret = await He({
9357
9415
  message: "Paste your Client Secret:"
9358
9416
  });
9359
9417
  if (Ct(clientSecret))
@@ -9370,7 +9428,7 @@ Opening: ${brandUrl}`);
9370
9428
  }
9371
9429
  }
9372
9430
 
9373
- // src/lib/github-provider.ts
9431
+ // src/lib/providers/github-provider.ts
9374
9432
  import http from "http";
9375
9433
  function logStep2(message) {
9376
9434
  if (!globalConfig.quiet)
@@ -9478,18 +9536,33 @@ class GitHubAuthProvider {
9478
9536
  logStep2("Step 1: Create OAuth App on GitHub");
9479
9537
  const oauthAppUrl = "https://github.com/settings/applications/new";
9480
9538
  logMessage2(`Opening: ${oauthAppUrl}`);
9539
+ Ve(`Required Authorization callback URL:
9540
+ ${callbackUrl}`, "Save this URL");
9481
9541
  if (!globalConfig.noOpen) {
9482
- await open_default(oauthAppUrl);
9542
+ const shouldOpen = globalConfig.skipPrompts ? true : await Re({
9543
+ message: "Open GitHub OAuth App page?",
9544
+ initialValue: true
9545
+ });
9546
+ if (Ct(shouldOpen))
9547
+ return Ne("Setup aborted.");
9548
+ if (shouldOpen)
9549
+ await open_default(oauthAppUrl);
9483
9550
  }
9484
- Ve(`1. Fill Application Name and Homepage URL
9485
- 2. Enter Authorization callback URL: ` + callbackUrl + `
9551
+ if (!globalConfig.skipPrompts) {
9552
+ Ve(`1. Fill Application Name and Homepage URL
9553
+ 2. Enter Authorization callback URL
9486
9554
  3. Click 'Register application'`, "Action Required");
9487
- const brandDone = await Ze({
9488
- message: "Press Enter once you've created the OAuth App (or type 'skip' if done previously)"
9489
- });
9490
- if (Ct(brandDone))
9491
- return Ne("Setup aborted.");
9555
+ const brandDone = await Ze({
9556
+ message: "Press Enter once you've created the OAuth App (or type 'skip' if done previously)"
9557
+ });
9558
+ if (Ct(brandDone))
9559
+ return Ne("Setup aborted.");
9560
+ }
9492
9561
  logStep2("Step 2: Save credentials");
9562
+ if (globalConfig.skipPrompts) {
9563
+ R2.error("Client ID and Secret required in non-interactive mode. Run without --skip-prompts");
9564
+ process.exit(1);
9565
+ }
9493
9566
  const clientId = await Ze({
9494
9567
  message: "Paste your Client ID:",
9495
9568
  placeholder: "Iv1.xxx"
@@ -9508,6 +9581,70 @@ class GitHubAuthProvider {
9508
9581
  }
9509
9582
  }
9510
9583
 
9584
+ // src/lib/providers/discord-provider.ts
9585
+ function logStep3(message) {
9586
+ if (!globalConfig.quiet)
9587
+ R2.step(message);
9588
+ }
9589
+ function logMessage3(message) {
9590
+ if (!globalConfig.quiet)
9591
+ R2.message(message);
9592
+ }
9593
+
9594
+ class DiscordAuthProvider {
9595
+ async run(callbackUrl) {
9596
+ try {
9597
+ logStep3("Step 1: Create Discord Application");
9598
+ const portalUrl = "https://discord.com/developers/applications?new_app=true";
9599
+ logMessage3(`Opening Discord Developer Portal: ${portalUrl}`);
9600
+ Ve(`Required Redirect URI:
9601
+ ${callbackUrl}`, "Save this URL");
9602
+ if (!globalConfig.noOpen) {
9603
+ const shouldOpen = globalConfig.skipPrompts ? true : await Re({
9604
+ message: "Open Discord Developer Portal?",
9605
+ initialValue: true
9606
+ });
9607
+ if (Ct(shouldOpen))
9608
+ return Ne("Setup aborted.");
9609
+ if (shouldOpen)
9610
+ await open_default(portalUrl);
9611
+ }
9612
+ if (!globalConfig.skipPrompts) {
9613
+ Ve(`1. Click 'New Application' and give it a name.
9614
+ ` + `2. Go to 'Overview' -> 'OAuth2' in the sidebar.
9615
+ ` + `3. Click 'Add Redirect' and paste your callback URL
9616
+ 4. Click 'Reset Secret' if you don't have a Client Secret`, "Action Required");
9617
+ }
9618
+ logStep3("Step 2: Collect Credentials");
9619
+ if (globalConfig.skipPrompts) {
9620
+ R2.error("Client ID and Secret required in non-interactive mode. Run without --skip-prompts");
9621
+ process.exit(1);
9622
+ }
9623
+ const clientId = await Ze({
9624
+ message: "Enter your Discord Client ID:",
9625
+ placeholder: "123456789012345678",
9626
+ validate: (value) => !value || !/^\d{17,19}$/.test(value) ? "Invalid Discord ID" : undefined
9627
+ });
9628
+ if (Ct(clientId))
9629
+ return Ne("Setup aborted.");
9630
+ const clientSecret = await He({
9631
+ message: "Enter your Discord Client Secret:",
9632
+ validate: (value) => !value || value.length < 10 ? "Secret too short" : undefined
9633
+ });
9634
+ if (Ct(clientSecret))
9635
+ return Ne("Setup aborted.");
9636
+ logStep3("Step 3: Save credentials");
9637
+ const saveOption = await askSaveOption();
9638
+ if (Ct(saveOption))
9639
+ return Ne("Setup aborted.");
9640
+ await saveCredentials(clientId, clientSecret, "discord", saveOption);
9641
+ } catch (err) {
9642
+ R2.error(`Setup Failed: ${err.message}`);
9643
+ process.exit(1);
9644
+ }
9645
+ }
9646
+ }
9647
+
9511
9648
  // src/index.ts
9512
9649
  var AUTH_LIBRARIES = [
9513
9650
  { name: "next-auth", callbackPattern: "/api/auth/callback/[provider]" },
@@ -9545,7 +9682,35 @@ function getCallbackUrlPattern(authLibrary) {
9545
9682
  return "/oauth/callback/[provider]";
9546
9683
  }
9547
9684
  var DEFAULT_CALLBACK_URL = "http://localhost:3000";
9548
- async function setupOAuthServices(oauthServices) {
9685
+ var PROVIDER_HELP = {
9686
+ google: `
9687
+ Google OAuth Setup:
9688
+ 1. Requires a Google Cloud project with OAuth 2.0 configured
9689
+ 2. Redirect URI: http://localhost:3000/api/auth/callback/google
9690
+ 3. Need: Client ID and Client Secret from Google Cloud Console
9691
+ 4. Run: gcloud auth login before starting`,
9692
+ github: `
9693
+ GitHub OAuth Setup:
9694
+ 1. Creates OAuth App or GitHub App in your org
9695
+ 2. Redirect URI: http://localhost:3000/api/auth/callback/github
9696
+ 3. Need: Client ID and Client Secret from GitHub Developer Settings`,
9697
+ discord: `
9698
+ Discord OAuth Setup:
9699
+ 1. Requires Discord Developer Portal setup
9700
+ 2. Redirect URI: http://localhost:3000/api/auth/callback/discord
9701
+ 3. Need: Client ID and Client Secret from Discord Developer Portal`
9702
+ };
9703
+ function showProviderHelp(provider) {
9704
+ const help = PROVIDER_HELP[provider.toLowerCase()];
9705
+ if (help) {
9706
+ console.log(help);
9707
+ process.exit(0);
9708
+ }
9709
+ console.log(`Unknown provider: ${provider}`);
9710
+ console.log(`Available: ${Object.keys(PROVIDER_HELP).join(", ")}`);
9711
+ process.exit(1);
9712
+ }
9713
+ async function setupOAuthServices(oauthServices, customCallbackUrl) {
9549
9714
  const authLibrary = detectAuthLibrary();
9550
9715
  const callbackPattern = getCallbackUrlPattern(authLibrary);
9551
9716
  if (authLibrary) {
@@ -9553,12 +9718,13 @@ async function setupOAuthServices(oauthServices) {
9553
9718
  } else {
9554
9719
  R2.info("No known auth library detected, using generic callback pattern");
9555
9720
  }
9721
+ const baseCallbackUrl = customCallbackUrl || DEFAULT_CALLBACK_URL;
9556
9722
  for (const service of oauthServices) {
9557
9723
  const providerCallback = callbackPattern.replace("[provider]", service);
9558
- const defaultCallback = `${DEFAULT_CALLBACK_URL}${providerCallback}`;
9724
+ const defaultCallback = `${baseCallbackUrl}${providerCallback}`;
9559
9725
  if (service === "google") {
9560
9726
  R2.step("Google OAuth Setup");
9561
- const googleOauthCallback = await Ze({
9727
+ const googleOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9562
9728
  message: "Enter the Google OAuth callback URL:",
9563
9729
  placeholder: defaultCallback,
9564
9730
  defaultValue: defaultCallback
@@ -9571,7 +9737,7 @@ async function setupOAuthServices(oauthServices) {
9571
9737
  await googleProvider.run(googleOauthCallback);
9572
9738
  } else if (service === "github") {
9573
9739
  R2.step("GitHub OAuth Setup");
9574
- const githubOauthCallback = await Ze({
9740
+ const githubOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9575
9741
  message: "Enter the GitHub OAuth callback URL:",
9576
9742
  placeholder: defaultCallback,
9577
9743
  defaultValue: defaultCallback
@@ -9582,6 +9748,19 @@ async function setupOAuthServices(oauthServices) {
9582
9748
  }
9583
9749
  const githubProvider = new GitHubAuthProvider;
9584
9750
  await githubProvider.run(githubOauthCallback);
9751
+ } else if (service === "discord") {
9752
+ R2.step("Discord OAuth Setup");
9753
+ const discordOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9754
+ message: "Enter the Discord OAuth callback URL:",
9755
+ placeholder: defaultCallback,
9756
+ defaultValue: defaultCallback
9757
+ });
9758
+ if (Ct(discordOauthCallback)) {
9759
+ Ne("Setup aborted.");
9760
+ return;
9761
+ }
9762
+ const discordProvider = new DiscordAuthProvider;
9763
+ await discordProvider.run(discordOauthCallback);
9585
9764
  }
9586
9765
  }
9587
9766
  Le("OAuth setup completed! Thank you for using oauth-init!");
@@ -9591,53 +9770,91 @@ async function main() {
9591
9770
  const flags = {
9592
9771
  help: args.includes("--help") || args.includes("-h"),
9593
9772
  quiet: args.includes("--quiet") || args.includes("-q"),
9594
- noOpen: args.includes("--no-open") || args.includes("-n")
9773
+ noOpen: args.includes("--no-open") || args.includes("-n"),
9774
+ skipPrompts: args.includes("--skip-prompts") || args.includes("-y"),
9775
+ provider: args.find((arg) => arg.startsWith("--provider="))?.split("=")[1] || args.find((arg) => arg.startsWith("-p="))?.split("=")[1],
9776
+ callbackUrl: args.find((arg) => arg.startsWith("--callback-url="))?.split("=")[1] || args.find((arg) => arg.startsWith("-c="))?.split("=")[1]
9595
9777
  };
9778
+ const providerArg = args.find((arg) => !arg.startsWith("-"));
9779
+ if (providerArg && (providerArg === "google" || providerArg === "github" || providerArg === "discord")) {
9780
+ showProviderHelp(providerArg);
9781
+ }
9596
9782
  if (flags.help) {
9597
9783
  console.log(`
9598
- Usage: oauth-init [options]
9784
+ Usage: oauth-init [options] [provider]
9599
9785
 
9600
9786
  Options:
9601
- -h, --help Show this help message
9602
- -q, --quiet Reduce output verbosity
9603
- -n, --no-open Don't open browser URLs automatically
9787
+ -h, --help Show this help message
9788
+ -q, --quiet Reduce output verbosity
9789
+ -n, --no-open Don't open browser URLs automatically
9790
+ -y, --skip-prompts Use default options (for CI/CD)
9791
+ -p, --provider= Specify providers (comma-separated): google,github,discord
9792
+ -c, --callback-url= Base callback URL (default: http://localhost:3000)
9604
9793
 
9605
9794
  Examples:
9606
- oauth-init # Run interactive setup
9607
- oauth-init --quiet # Run with minimal output
9608
- oauth-init --no-open # Get URLs but don't open them
9795
+ oauth-init # Run interactive setup
9796
+ oauth-init --provider=google # Setup only Google
9797
+ oauth-init --provider=google,github # Setup Google and GitHub
9798
+ oauth-init --no-open # Get URLs but don't open them
9799
+ oauth-init --quiet -y # Minimal output, use defaults
9800
+ oauth-init -y -p google -c https://myapp.com # CI/CD mode
9801
+ oauth-init google # Show Google-specific help
9609
9802
  `);
9610
9803
  process.exit(0);
9611
9804
  }
9805
+ if (flags.provider) {
9806
+ const validProviders = ["google", "github", "discord"];
9807
+ const providers = flags.provider.split(",").map((p) => p.trim().toLowerCase());
9808
+ const invalid = providers.filter((p) => !validProviders.includes(p));
9809
+ if (invalid.length > 0) {
9810
+ console.error(`Invalid providers: ${invalid.join(", ")}. Valid: ${validProviders.join(", ")}`);
9811
+ process.exit(1);
9812
+ }
9813
+ }
9612
9814
  globalConfig.quiet = flags.quiet;
9613
9815
  globalConfig.noOpen = flags.noOpen;
9816
+ globalConfig.skipPrompts = flags.skipPrompts;
9614
9817
  const projectDirectoryName = path7.basename(process.cwd());
9615
- We(`
9818
+ if (!flags.quiet) {
9819
+ We(`
9616
9820
  ▗▄▖ ▗▄▖ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▄▄▄▖▗▄▄▄▖
9617
9821
  ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ █ ▐▌ ▐▌ █ ▐▛▚▖▐▌ █ █
9618
9822
  ▐▌ ▐▌▐▛▀▜▌▐▌ ▐▌ █ ▐▛▀▜▌ █ ▐▌ ▝▜▌ █ █
9619
9823
  ▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘ █ ▐▌ ▐▌ ▗▄█▄▖▐▌ ▐▌▗▄█▄▖ █ `);
9620
- const projectName = await Ze({
9621
- message: "Enter the name of your project:",
9622
- placeholder: projectDirectoryName,
9623
- defaultValue: projectDirectoryName
9624
- });
9625
- if (Ct(projectName)) {
9626
- Ne("Operation cancelled.");
9627
- process.exit(0);
9628
9824
  }
9629
- const oauthToSetup = await je({
9630
- message: "Select OAuth services to setup:",
9631
- options: [
9632
- { value: "google", label: "Google" },
9633
- { value: "github", label: "Github" }
9634
- ]
9635
- });
9636
- if (Ct(oauthToSetup)) {
9637
- Ne("Operation cancelled.");
9638
- process.exit(0);
9825
+ let projectName;
9826
+ if (flags.skipPrompts) {
9827
+ projectName = projectDirectoryName;
9828
+ } else {
9829
+ projectName = await Ze({
9830
+ message: "Enter the name of your project:",
9831
+ placeholder: projectDirectoryName,
9832
+ defaultValue: projectDirectoryName
9833
+ });
9834
+ if (Ct(projectName)) {
9835
+ Ne("Operation cancelled.");
9836
+ process.exit(0);
9837
+ }
9838
+ }
9839
+ let oauthToSetup;
9840
+ if (flags.provider) {
9841
+ oauthToSetup = flags.provider.split(",").map((p) => p.trim().toLowerCase());
9842
+ } else {
9843
+ oauthToSetup = await je({
9844
+ message: "Select OAuth services to setup:",
9845
+ options: [
9846
+ { value: "google", label: "Google" },
9847
+ { value: "github", label: "Github" },
9848
+ { value: "discord", label: "Discord" }
9849
+ ]
9850
+ });
9851
+ if (Ct(oauthToSetup)) {
9852
+ Ne("Operation cancelled.");
9853
+ process.exit(0);
9854
+ }
9855
+ oauthToSetup = oauthToSetup;
9639
9856
  }
9640
- await setupOAuthServices(oauthToSetup);
9857
+ await setupOAuthServices(oauthToSetup, flags.callbackUrl);
9641
9858
  process.exit(0);
9642
9859
  }
9643
9860
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oauth-init",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "CLI for setting up OAuth providers for your project",
5
5
  "license": "MIT",
6
6
  "type": "module",