usertold 1.9.2 → 1.9.3

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/package.json +1 -1
  2. package/usertold +87 -66
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usertold",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "UserTold.ai CLI",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
package/usertold CHANGED
@@ -728,79 +728,98 @@ function generateState() {
728
728
  function base64UrlEncode(buffer) {
729
729
  return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
730
730
  }
731
- async function waitForAuthorizationCode(port, expectedState) {
732
- return new Promise((resolve, reject)=>{
733
- const server = http.createServer((req, res)=>{
734
- if (!req.url) {
735
- res.writeHead(400, {
736
- 'Content-Type': 'text/html'
737
- });
738
- res.end(getErrorPage('invalid_request', 'Invalid request'));
739
- return;
740
- }
741
- const url = new URL(req.url, `http://127.0.0.1:${port}`);
742
- if (url.pathname !== '/callback') {
743
- res.writeHead(404, {
744
- 'Content-Type': 'text/html'
745
- });
746
- res.end(getErrorPage('not_found', 'Page not found'));
747
- return;
748
- }
749
- const code = url.searchParams.get('code');
750
- const state = url.searchParams.get('state');
751
- const error = url.searchParams.get('error');
752
- const errorDescription = url.searchParams.get('error_description');
753
- // Handle OAuth error response
754
- if (error) {
755
- res.writeHead(400, {
756
- 'Content-Type': 'text/html'
757
- });
758
- res.end(getErrorPage(error, errorDescription || undefined));
759
- clearTimeout(timeout);
760
- server.close();
761
- reject(new Error(`OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ''}`));
762
- return;
763
- }
764
- if (!code) {
765
- res.writeHead(400, {
766
- 'Content-Type': 'text/html'
767
- });
768
- res.end(getErrorPage('invalid_request', 'Missing authorization code'));
769
- clearTimeout(timeout);
770
- server.close();
771
- reject(new Error('Missing authorization code'));
772
- return;
773
- }
774
- if (state !== expectedState) {
775
- res.writeHead(400, {
776
- 'Content-Type': 'text/html'
777
- });
778
- res.end(getErrorPage('invalid_request', 'State parameter mismatch - possible CSRF attack'));
779
- clearTimeout(timeout);
780
- server.close();
781
- reject(new Error('State mismatch'));
782
- return;
783
- }
784
- res.writeHead(200, {
731
+ function startAuthorizationCodeListener(port, expectedState) {
732
+ const server = http.createServer((req, res)=>{
733
+ if (!req.url) {
734
+ res.writeHead(400, {
735
+ 'Content-Type': 'text/html'
736
+ });
737
+ res.end(getErrorPage('invalid_request', 'Invalid request'));
738
+ return;
739
+ }
740
+ const url = new URL(req.url, `http://127.0.0.1:${port}`);
741
+ if (url.pathname !== '/callback') {
742
+ res.writeHead(404, {
743
+ 'Content-Type': 'text/html'
744
+ });
745
+ res.end(getErrorPage('not_found', 'Page not found'));
746
+ return;
747
+ }
748
+ const code = url.searchParams.get('code');
749
+ const state = url.searchParams.get('state');
750
+ const error = url.searchParams.get('error');
751
+ const errorDescription = url.searchParams.get('error_description');
752
+ // Handle OAuth error response
753
+ if (error) {
754
+ res.writeHead(400, {
785
755
  'Content-Type': 'text/html'
786
756
  });
787
- res.end(getSuccessPage());
757
+ res.end(getErrorPage(error, errorDescription || undefined));
788
758
  clearTimeout(timeout);
789
759
  server.close();
790
- resolve({
791
- code
760
+ rejectResult(new Error(`OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ''}`));
761
+ return;
762
+ }
763
+ if (!code) {
764
+ res.writeHead(400, {
765
+ 'Content-Type': 'text/html'
792
766
  });
767
+ res.end(getErrorPage('invalid_request', 'Missing authorization code'));
768
+ clearTimeout(timeout);
769
+ server.close();
770
+ rejectResult(new Error('Missing authorization code'));
771
+ return;
772
+ }
773
+ if (state !== expectedState) {
774
+ res.writeHead(400, {
775
+ 'Content-Type': 'text/html'
776
+ });
777
+ res.end(getErrorPage('invalid_request', 'State parameter mismatch - possible CSRF attack'));
778
+ clearTimeout(timeout);
779
+ server.close();
780
+ rejectResult(new Error('State mismatch'));
781
+ return;
782
+ }
783
+ res.writeHead(200, {
784
+ 'Content-Type': 'text/html'
785
+ });
786
+ res.end(getSuccessPage());
787
+ clearTimeout(timeout);
788
+ server.close();
789
+ resolveResult({
790
+ code
793
791
  });
794
- server.listen(port, '127.0.0.1');
795
- server.on('error', (error)=>{
792
+ });
793
+ let rejectResult = ()=>{};
794
+ let resolveResult = ()=>{};
795
+ const result = new Promise((resolve, reject)=>{
796
+ resolveResult = resolve;
797
+ rejectResult = reject;
798
+ });
799
+ const ready = new Promise((resolve, reject)=>{
800
+ const handleStartupError = (error)=>{
796
801
  clearTimeout(timeout);
802
+ rejectResult(new Error(`Failed to start local callback server: ${error.message}`));
797
803
  reject(new Error(`Failed to start local callback server: ${error.message}`));
804
+ };
805
+ server.once('error', handleStartupError);
806
+ server.listen(port, '127.0.0.1', ()=>{
807
+ server.off('error', handleStartupError);
808
+ server.on('error', (error)=>{
809
+ clearTimeout(timeout);
810
+ rejectResult(new Error(`Local callback server error: ${error.message}`));
811
+ });
812
+ resolve();
798
813
  });
799
- const timeout = setTimeout(()=>{
800
- server.close();
801
- reject(new Error('Login timed out waiting for authorization response'));
802
- }, 5 * 60 * 1000);
803
814
  });
815
+ const timeout = setTimeout(()=>{
816
+ server.close();
817
+ rejectResult(new Error('Login timed out waiting for authorization response'));
818
+ }, 5 * 60 * 1000);
819
+ return {
820
+ ready,
821
+ result
822
+ };
804
823
  }
805
824
  // =============================================================================
806
825
  // CLI Auth Page Design Tokens
@@ -1052,6 +1071,8 @@ async function handleLogin(parsed) {
1052
1071
  authUrl.searchParams.set('code_challenge_method', 'S256');
1053
1072
  authUrl.searchParams.set('state', state);
1054
1073
  authUrl.searchParams.set('access_type', 'offline');
1074
+ const authorizationCodeListener = startAuthorizationCodeListener(redirectPort, state);
1075
+ await authorizationCodeListener.ready;
1055
1076
  // Always print the URL so it works on headless/remote hosts
1056
1077
  console.log('\nOpen this URL in your browser to authenticate:\n');
1057
1078
  console.log(authUrl.toString());
@@ -1068,7 +1089,7 @@ async function handleLogin(parsed) {
1068
1089
  console.log('(Could not open browser — use the URL above)');
1069
1090
  }
1070
1091
  }
1071
- const { code } = await waitForAuthorizationCode(redirectPort, state);
1092
+ const { code } = await authorizationCodeListener.result;
1072
1093
  console.log('Received authorization code. Exchanging for access token...');
1073
1094
  const tokenResponse = await exchangeCodeForToken({
1074
1095
  baseUrl,
@@ -14713,7 +14734,7 @@ function printExtractHelp() {
14713
14734
  console.log(EXTRACT_HELP);
14714
14735
  }
14715
14736
 
14716
- const CLI_VERSION$1 = '1.9.2';
14737
+ const CLI_VERSION$1 = '1.9.3';
14717
14738
  const GLOBAL_FLAGS = [
14718
14739
  'env',
14719
14740
  'json',
@@ -15009,7 +15030,7 @@ function printCompletionsHelp() {
15009
15030
  console.log(COMPLETIONS_HELP);
15010
15031
  }
15011
15032
 
15012
- const CLI_VERSION = '1.9.2';
15033
+ const CLI_VERSION = '1.9.3';
15013
15034
  function detectJsonMode() {
15014
15035
  const argv = process$2.argv.slice(2);
15015
15036
  if (argv.includes('--json')) return true;