oauth-init 0.15.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 +221 -67
  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,7 +9581,7 @@ class GitHubAuthProvider {
9508
9581
  }
9509
9582
  }
9510
9583
 
9511
- // src/lib/discord-provider.ts
9584
+ // src/lib/providers/discord-provider.ts
9512
9585
  function logStep3(message) {
9513
9586
  if (!globalConfig.quiet)
9514
9587
  R2.step(message);
@@ -9524,14 +9597,29 @@ class DiscordAuthProvider {
9524
9597
  logStep3("Step 1: Create Discord Application");
9525
9598
  const portalUrl = "https://discord.com/developers/applications?new_app=true";
9526
9599
  logMessage3(`Opening Discord Developer Portal: ${portalUrl}`);
9600
+ Ve(`Required Redirect URI:
9601
+ ${callbackUrl}`, "Save this URL");
9527
9602
  if (!globalConfig.noOpen) {
9528
- await open_default(portalUrl);
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);
9529
9611
  }
9530
- Ve(`1. Click 'New Application' and give it a name.
9531
- ` + `2. Go to 'OAuth2' -> 'General' in the sidebar.
9532
- ` + "3. Click 'Add Redirect' and paste: " + callbackUrl + `
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
9533
9616
  4. Click 'Reset Secret' if you don't have a Client Secret`, "Action Required");
9617
+ }
9534
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
+ }
9535
9623
  const clientId = await Ze({
9536
9624
  message: "Enter your Discord Client ID:",
9537
9625
  placeholder: "123456789012345678",
@@ -9594,7 +9682,35 @@ function getCallbackUrlPattern(authLibrary) {
9594
9682
  return "/oauth/callback/[provider]";
9595
9683
  }
9596
9684
  var DEFAULT_CALLBACK_URL = "http://localhost:3000";
9597
- 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) {
9598
9714
  const authLibrary = detectAuthLibrary();
9599
9715
  const callbackPattern = getCallbackUrlPattern(authLibrary);
9600
9716
  if (authLibrary) {
@@ -9602,12 +9718,13 @@ async function setupOAuthServices(oauthServices) {
9602
9718
  } else {
9603
9719
  R2.info("No known auth library detected, using generic callback pattern");
9604
9720
  }
9721
+ const baseCallbackUrl = customCallbackUrl || DEFAULT_CALLBACK_URL;
9605
9722
  for (const service of oauthServices) {
9606
9723
  const providerCallback = callbackPattern.replace("[provider]", service);
9607
- const defaultCallback = `${DEFAULT_CALLBACK_URL}${providerCallback}`;
9724
+ const defaultCallback = `${baseCallbackUrl}${providerCallback}`;
9608
9725
  if (service === "google") {
9609
9726
  R2.step("Google OAuth Setup");
9610
- const googleOauthCallback = await Ze({
9727
+ const googleOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9611
9728
  message: "Enter the Google OAuth callback URL:",
9612
9729
  placeholder: defaultCallback,
9613
9730
  defaultValue: defaultCallback
@@ -9620,7 +9737,7 @@ async function setupOAuthServices(oauthServices) {
9620
9737
  await googleProvider.run(googleOauthCallback);
9621
9738
  } else if (service === "github") {
9622
9739
  R2.step("GitHub OAuth Setup");
9623
- const githubOauthCallback = await Ze({
9740
+ const githubOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9624
9741
  message: "Enter the GitHub OAuth callback URL:",
9625
9742
  placeholder: defaultCallback,
9626
9743
  defaultValue: defaultCallback
@@ -9633,7 +9750,7 @@ async function setupOAuthServices(oauthServices) {
9633
9750
  await githubProvider.run(githubOauthCallback);
9634
9751
  } else if (service === "discord") {
9635
9752
  R2.step("Discord OAuth Setup");
9636
- const discordOauthCallback = await Ze({
9753
+ const discordOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
9637
9754
  message: "Enter the Discord OAuth callback URL:",
9638
9755
  placeholder: defaultCallback,
9639
9756
  defaultValue: defaultCallback
@@ -9653,54 +9770,91 @@ async function main() {
9653
9770
  const flags = {
9654
9771
  help: args.includes("--help") || args.includes("-h"),
9655
9772
  quiet: args.includes("--quiet") || args.includes("-q"),
9656
- 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]
9657
9777
  };
9778
+ const providerArg = args.find((arg) => !arg.startsWith("-"));
9779
+ if (providerArg && (providerArg === "google" || providerArg === "github" || providerArg === "discord")) {
9780
+ showProviderHelp(providerArg);
9781
+ }
9658
9782
  if (flags.help) {
9659
9783
  console.log(`
9660
- Usage: oauth-init [options]
9784
+ Usage: oauth-init [options] [provider]
9661
9785
 
9662
9786
  Options:
9663
- -h, --help Show this help message
9664
- -q, --quiet Reduce output verbosity
9665
- -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)
9666
9793
 
9667
9794
  Examples:
9668
- oauth-init # Run interactive setup
9669
- oauth-init --quiet # Run with minimal output
9670
- 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
9671
9802
  `);
9672
9803
  process.exit(0);
9673
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
+ }
9674
9814
  globalConfig.quiet = flags.quiet;
9675
9815
  globalConfig.noOpen = flags.noOpen;
9816
+ globalConfig.skipPrompts = flags.skipPrompts;
9676
9817
  const projectDirectoryName = path7.basename(process.cwd());
9677
- We(`
9818
+ if (!flags.quiet) {
9819
+ We(`
9678
9820
  ▗▄▖ ▗▄▖ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▄▄▄▖▗▄▄▄▖
9679
9821
  ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ █ ▐▌ ▐▌ █ ▐▛▚▖▐▌ █ █
9680
9822
  ▐▌ ▐▌▐▛▀▜▌▐▌ ▐▌ █ ▐▛▀▜▌ █ ▐▌ ▝▜▌ █ █
9681
9823
  ▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘ █ ▐▌ ▐▌ ▗▄█▄▖▐▌ ▐▌▗▄█▄▖ █ `);
9682
- const projectName = await Ze({
9683
- message: "Enter the name of your project:",
9684
- placeholder: projectDirectoryName,
9685
- defaultValue: projectDirectoryName
9686
- });
9687
- if (Ct(projectName)) {
9688
- Ne("Operation cancelled.");
9689
- process.exit(0);
9690
9824
  }
9691
- const oauthToSetup = await je({
9692
- message: "Select OAuth services to setup:",
9693
- options: [
9694
- { value: "google", label: "Google" },
9695
- { value: "github", label: "Github" },
9696
- { value: "discord", label: "Discord" }
9697
- ]
9698
- });
9699
- if (Ct(oauthToSetup)) {
9700
- Ne("Operation cancelled.");
9701
- 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;
9702
9856
  }
9703
- await setupOAuthServices(oauthToSetup);
9857
+ await setupOAuthServices(oauthToSetup, flags.callbackUrl);
9704
9858
  process.exit(0);
9705
9859
  }
9706
9860
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oauth-init",
3
- "version": "0.15.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",