oauth.do 0.1.13 → 0.1.15

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/node.js CHANGED
@@ -26,9 +26,9 @@ function getEnv2(key) {
26
26
  if (typeof process !== "undefined" && process.env?.[key]) return process.env[key];
27
27
  return void 0;
28
28
  }
29
- function createSecureStorage() {
29
+ function createSecureStorage(storagePath) {
30
30
  if (isNode()) {
31
- return new SecureFileTokenStorage();
31
+ return new SecureFileTokenStorage(storagePath);
32
32
  }
33
33
  if (typeof localStorage !== "undefined") {
34
34
  return new LocalStorageTokenStorage();
@@ -133,6 +133,10 @@ var init_storage = __esm({
133
133
  tokenPath = null;
134
134
  configDir = null;
135
135
  initialized = false;
136
+ customPath;
137
+ constructor(customPath) {
138
+ this.customPath = customPath;
139
+ }
136
140
  async init() {
137
141
  if (this.initialized) return this.tokenPath !== null;
138
142
  this.initialized = true;
@@ -140,8 +144,14 @@ var init_storage = __esm({
140
144
  try {
141
145
  const os = await import('os');
142
146
  const path = await import('path');
143
- this.configDir = path.join(os.homedir(), ".oauth.do");
144
- this.tokenPath = path.join(this.configDir, "token");
147
+ if (this.customPath) {
148
+ const expandedPath = this.customPath.startsWith("~/") ? path.join(os.homedir(), this.customPath.slice(2)) : this.customPath;
149
+ this.tokenPath = expandedPath;
150
+ this.configDir = path.dirname(expandedPath);
151
+ } else {
152
+ this.configDir = path.join(os.homedir(), ".oauth.do");
153
+ this.tokenPath = path.join(this.configDir, "token");
154
+ }
145
155
  return true;
146
156
  } catch {
147
157
  return false;
@@ -376,7 +386,8 @@ var globalConfig = {
376
386
  apiUrl: getEnv("OAUTH_API_URL") || getEnv("API_URL") || "https://apis.do",
377
387
  clientId: getEnv("OAUTH_CLIENT_ID") || "client_01JQYTRXK9ZPD8JPJTKDCRB656",
378
388
  authKitDomain: getEnv("OAUTH_AUTHKIT_DOMAIN") || "login.oauth.do",
379
- fetch: globalThis.fetch
389
+ fetch: globalThis.fetch,
390
+ storagePath: getEnv("OAUTH_STORAGE_PATH")
380
391
  };
381
392
  function configure(config) {
382
393
  globalConfig = {
@@ -470,6 +481,11 @@ async function logout(token) {
470
481
  console.error("Logout error:", error);
471
482
  }
472
483
  }
484
+ var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
485
+ function isTokenExpired(expiresAt) {
486
+ if (!expiresAt) return false;
487
+ return Date.now() >= expiresAt - REFRESH_BUFFER_MS;
488
+ }
473
489
  async function getToken() {
474
490
  const adminToken = getEnv3("DO_ADMIN_TOKEN");
475
491
  if (adminToken) return adminToken;
@@ -485,7 +501,34 @@ async function getToken() {
485
501
  }
486
502
  try {
487
503
  const { createSecureStorage: createSecureStorage2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
488
- const storage = createSecureStorage2();
504
+ const config = getConfig();
505
+ const storage = createSecureStorage2(config.storagePath);
506
+ const tokenData = storage.getTokenData ? await storage.getTokenData() : null;
507
+ if (tokenData) {
508
+ if (!isTokenExpired(tokenData.expiresAt)) {
509
+ return tokenData.accessToken;
510
+ }
511
+ if (tokenData.refreshToken) {
512
+ try {
513
+ const newTokens = await refreshAccessToken(tokenData.refreshToken);
514
+ const expiresAt = newTokens.expires_in ? Date.now() + newTokens.expires_in * 1e3 : void 0;
515
+ const newData = {
516
+ accessToken: newTokens.access_token,
517
+ refreshToken: newTokens.refresh_token || tokenData.refreshToken,
518
+ expiresAt
519
+ };
520
+ if (storage.setTokenData) {
521
+ await storage.setTokenData(newData);
522
+ } else {
523
+ await storage.setToken(newTokens.access_token);
524
+ }
525
+ return newTokens.access_token;
526
+ } catch {
527
+ return null;
528
+ }
529
+ }
530
+ return null;
531
+ }
489
532
  return await storage.getToken();
490
533
  } catch {
491
534
  return null;
@@ -512,7 +555,7 @@ async function refreshAccessToken(refreshToken) {
512
555
  grant_type: "refresh_token",
513
556
  refresh_token: refreshToken,
514
557
  client_id: config.clientId
515
- })
558
+ }).toString()
516
559
  });
517
560
  if (!response.ok) {
518
561
  const errorText = await response.text();
@@ -556,7 +599,7 @@ async function authorizeDevice(options = {}) {
556
599
  headers: {
557
600
  "Content-Type": "application/x-www-form-urlencoded"
558
601
  },
559
- body
602
+ body: body.toString()
560
603
  });
561
604
  if (!response.ok) {
562
605
  const errorText = await response.text();
@@ -592,7 +635,7 @@ async function pollForTokens(deviceCode, interval = 5, expiresIn = 600) {
592
635
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
593
636
  device_code: deviceCode,
594
637
  client_id: config.clientId
595
- })
638
+ }).toString()
596
639
  });
597
640
  if (response.ok) {
598
641
  const data = await response.json();
@@ -622,64 +665,178 @@ async function pollForTokens(deviceCode, interval = 5, expiresIn = 600) {
622
665
  }
623
666
  }
624
667
 
668
+ // src/github-device.ts
669
+ async function startGitHubDeviceFlow(options) {
670
+ const { clientId, scope = "user:email read:user" } = options;
671
+ const fetchImpl = options.fetch || globalThis.fetch;
672
+ if (!clientId) {
673
+ throw new Error("GitHub client ID is required for device authorization");
674
+ }
675
+ try {
676
+ const url = "https://github.com/login/device/code";
677
+ const body = new URLSearchParams({
678
+ client_id: clientId,
679
+ scope
680
+ });
681
+ const response = await fetchImpl(url, {
682
+ method: "POST",
683
+ headers: {
684
+ "Content-Type": "application/x-www-form-urlencoded",
685
+ "Accept": "application/json"
686
+ },
687
+ body
688
+ });
689
+ if (!response.ok) {
690
+ const errorText = await response.text();
691
+ throw new Error(`GitHub device authorization failed: ${response.statusText} - ${errorText}`);
692
+ }
693
+ const data = await response.json();
694
+ return {
695
+ deviceCode: data.device_code,
696
+ userCode: data.user_code,
697
+ verificationUri: data.verification_uri,
698
+ expiresIn: data.expires_in,
699
+ interval: data.interval
700
+ };
701
+ } catch (error) {
702
+ console.error("GitHub device authorization error:", error);
703
+ throw error;
704
+ }
705
+ }
706
+ async function pollGitHubDeviceFlow(deviceCode, options) {
707
+ const { clientId, interval = 5, expiresIn = 900 } = options;
708
+ const fetchImpl = options.fetch || globalThis.fetch;
709
+ if (!clientId) {
710
+ throw new Error("GitHub client ID is required for token polling");
711
+ }
712
+ const startTime = Date.now();
713
+ const timeout = expiresIn * 1e3;
714
+ let currentInterval = interval * 1e3;
715
+ while (true) {
716
+ if (Date.now() - startTime > timeout) {
717
+ throw new Error("GitHub device authorization expired. Please try again.");
718
+ }
719
+ await new Promise((resolve) => setTimeout(resolve, currentInterval));
720
+ try {
721
+ const url = "https://github.com/login/oauth/access_token";
722
+ const body = new URLSearchParams({
723
+ client_id: clientId,
724
+ device_code: deviceCode,
725
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
726
+ });
727
+ const response = await fetchImpl(url, {
728
+ method: "POST",
729
+ headers: {
730
+ "Content-Type": "application/x-www-form-urlencoded",
731
+ "Accept": "application/json"
732
+ },
733
+ body
734
+ });
735
+ const data = await response.json();
736
+ if ("access_token" in data) {
737
+ return {
738
+ accessToken: data.access_token,
739
+ tokenType: data.token_type,
740
+ scope: data.scope
741
+ };
742
+ }
743
+ const error = data.error || "unknown";
744
+ switch (error) {
745
+ case "authorization_pending":
746
+ continue;
747
+ case "slow_down":
748
+ currentInterval += 5e3;
749
+ continue;
750
+ case "access_denied":
751
+ throw new Error("Access denied by user");
752
+ case "expired_token":
753
+ throw new Error("Device code expired");
754
+ default:
755
+ throw new Error(`GitHub token polling failed: ${error}`);
756
+ }
757
+ } catch (error) {
758
+ if (error instanceof Error) {
759
+ throw error;
760
+ }
761
+ continue;
762
+ }
763
+ }
764
+ }
765
+ async function getGitHubUser(accessToken, options = {}) {
766
+ const fetchImpl = options.fetch || globalThis.fetch;
767
+ if (!accessToken) {
768
+ throw new Error("GitHub access token is required");
769
+ }
770
+ try {
771
+ const response = await fetchImpl("https://api.github.com/user", {
772
+ method: "GET",
773
+ headers: {
774
+ "Authorization": `Bearer ${accessToken}`,
775
+ "Accept": "application/vnd.github+json",
776
+ "X-GitHub-Api-Version": "2022-11-28"
777
+ }
778
+ });
779
+ if (!response.ok) {
780
+ const errorText = await response.text();
781
+ throw new Error(`GitHub user fetch failed: ${response.statusText} - ${errorText}`);
782
+ }
783
+ const data = await response.json();
784
+ return {
785
+ id: data.id,
786
+ login: data.login,
787
+ email: data.email,
788
+ name: data.name,
789
+ avatarUrl: data.avatar_url
790
+ };
791
+ } catch (error) {
792
+ console.error("GitHub user fetch error:", error);
793
+ throw error;
794
+ }
795
+ }
796
+
625
797
  // src/index.ts
626
798
  init_storage();
627
799
 
628
800
  // src/login.ts
629
801
  init_storage();
630
- var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
631
- function isTokenExpired(expiresAt) {
802
+ var REFRESH_BUFFER_MS2 = 5 * 60 * 1e3;
803
+ function isTokenExpired2(expiresAt) {
632
804
  if (!expiresAt) return false;
633
- return Date.now() >= expiresAt - REFRESH_BUFFER_MS;
805
+ return Date.now() >= expiresAt - REFRESH_BUFFER_MS2;
634
806
  }
635
807
  async function ensureLoggedIn(options = {}) {
636
- const { openBrowser = true, print = console.log, provider, storage = createSecureStorage() } = options;
808
+ const config = getConfig();
809
+ const { openBrowser = true, print = console.log, provider, storage = createSecureStorage(config.storagePath) } = options;
637
810
  const tokenData = storage.getTokenData ? await storage.getTokenData() : null;
638
811
  const existingToken = tokenData?.accessToken || await storage.getToken();
639
812
  if (existingToken) {
640
- if (tokenData && isTokenExpired(tokenData.expiresAt)) {
641
- if (tokenData.refreshToken) {
642
- try {
643
- const newTokens = await refreshAccessToken(tokenData.refreshToken);
644
- const expiresAt2 = newTokens.expires_in ? Date.now() + newTokens.expires_in * 1e3 : void 0;
645
- const newData2 = {
646
- accessToken: newTokens.access_token,
647
- refreshToken: newTokens.refresh_token || tokenData.refreshToken,
648
- expiresAt: expiresAt2
649
- };
650
- if (storage.setTokenData) {
651
- await storage.setTokenData(newData2);
652
- } else {
653
- await storage.setToken(newTokens.access_token);
654
- }
655
- return { token: newTokens.access_token, isNewLogin: false };
656
- } catch (error) {
657
- console.warn("Token refresh failed:", error);
813
+ if (tokenData?.expiresAt && !isTokenExpired2(tokenData.expiresAt)) {
814
+ return { token: existingToken, isNewLogin: false };
815
+ }
816
+ if (tokenData?.refreshToken) {
817
+ try {
818
+ const newTokens = await refreshAccessToken(tokenData.refreshToken);
819
+ const expiresAt2 = newTokens.expires_in ? Date.now() + newTokens.expires_in * 1e3 : void 0;
820
+ const newData2 = {
821
+ accessToken: newTokens.access_token,
822
+ refreshToken: newTokens.refresh_token || tokenData.refreshToken,
823
+ expiresAt: expiresAt2
824
+ };
825
+ if (storage.setTokenData) {
826
+ await storage.setTokenData(newData2);
827
+ } else {
828
+ await storage.setToken(newTokens.access_token);
658
829
  }
830
+ return { token: newTokens.access_token, isNewLogin: false };
831
+ } catch (error) {
832
+ console.warn("Token refresh failed:", error);
659
833
  }
660
- } else {
834
+ }
835
+ if (!tokenData?.expiresAt && !tokenData?.refreshToken) {
661
836
  const { user } = await getUser(existingToken);
662
837
  if (user) {
663
838
  return { token: existingToken, isNewLogin: false };
664
839
  }
665
- if (tokenData?.refreshToken) {
666
- try {
667
- const newTokens = await refreshAccessToken(tokenData.refreshToken);
668
- const expiresAt2 = newTokens.expires_in ? Date.now() + newTokens.expires_in * 1e3 : void 0;
669
- const newData2 = {
670
- accessToken: newTokens.access_token,
671
- refreshToken: newTokens.refresh_token || tokenData.refreshToken,
672
- expiresAt: expiresAt2
673
- };
674
- if (storage.setTokenData) {
675
- await storage.setTokenData(newData2);
676
- } else {
677
- await storage.setToken(newTokens.access_token);
678
- }
679
- return { token: newTokens.access_token, isNewLogin: false };
680
- } catch {
681
- }
682
- }
683
840
  }
684
841
  }
685
842
  print("\nLogging in...\n");
@@ -719,16 +876,18 @@ async function ensureLoggedIn(options = {}) {
719
876
  return { token: tokenResponse.access_token, isNewLogin: true };
720
877
  }
721
878
  async function forceLogin(options = {}) {
722
- const { storage = createSecureStorage() } = options;
879
+ const config = getConfig();
880
+ const { storage = createSecureStorage(config.storagePath) } = options;
723
881
  await storage.removeToken();
724
882
  return ensureLoggedIn(options);
725
883
  }
726
884
  async function ensureLoggedOut(options = {}) {
727
- const { print = console.log, storage = createSecureStorage() } = options;
885
+ const config = getConfig();
886
+ const { print = console.log, storage = createSecureStorage(config.storagePath) } = options;
728
887
  await storage.removeToken();
729
888
  print("Logged out successfully\n");
730
889
  }
731
890
 
732
- export { CompositeTokenStorage, FileTokenStorage, KeychainTokenStorage, LocalStorageTokenStorage, MemoryTokenStorage, SecureFileTokenStorage, auth, authorizeDevice, buildAuthUrl, configure, createSecureStorage, ensureLoggedIn, ensureLoggedOut, forceLogin, getConfig, getToken, getUser, isAuthenticated, login, logout, pollForTokens };
891
+ export { CompositeTokenStorage, FileTokenStorage, KeychainTokenStorage, LocalStorageTokenStorage, MemoryTokenStorage, SecureFileTokenStorage, auth, authorizeDevice, buildAuthUrl, configure, createSecureStorage, ensureLoggedIn, ensureLoggedOut, forceLogin, getConfig, getGitHubUser, getToken, getUser, isAuthenticated, login, logout, pollForTokens, pollGitHubDeviceFlow, startGitHubDeviceFlow };
733
892
  //# sourceMappingURL=node.js.map
734
893
  //# sourceMappingURL=node.js.map