@sascha384/tic 4.1.0 → 4.3.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 (89) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/app.js +4 -2
  3. package/dist/app.js.map +1 -1
  4. package/dist/auth/ado.js +76 -28
  5. package/dist/auth/ado.js.map +1 -1
  6. package/dist/auth/github.js +57 -24
  7. package/dist/auth/github.js.map +1 -1
  8. package/dist/auth/gitlab.js +54 -23
  9. package/dist/auth/gitlab.js.map +1 -1
  10. package/dist/auth/jira.d.ts +8 -0
  11. package/dist/auth/jira.js +24 -0
  12. package/dist/auth/jira.js.map +1 -0
  13. package/dist/backends/ado/api.d.ts +1 -0
  14. package/dist/backends/ado/api.js +66 -16
  15. package/dist/backends/ado/api.js.map +1 -1
  16. package/dist/backends/ado/index.js +4 -1
  17. package/dist/backends/ado/index.js.map +1 -1
  18. package/dist/backends/factory.js +1 -1
  19. package/dist/backends/factory.js.map +1 -1
  20. package/dist/backends/files/index.js +1 -0
  21. package/dist/backends/files/index.js.map +1 -1
  22. package/dist/backends/github/api.js +61 -17
  23. package/dist/backends/github/api.js.map +1 -1
  24. package/dist/backends/github/index.js +1 -0
  25. package/dist/backends/github/index.js.map +1 -1
  26. package/dist/backends/github/mappers.d.ts +1 -1
  27. package/dist/backends/github/mappers.js +1 -1
  28. package/dist/backends/github/mappers.js.map +1 -1
  29. package/dist/backends/gitlab/api.js +22 -8
  30. package/dist/backends/gitlab/api.js.map +1 -1
  31. package/dist/backends/gitlab/index.js +1 -0
  32. package/dist/backends/gitlab/index.js.map +1 -1
  33. package/dist/backends/jira/api.d.ts +9 -0
  34. package/dist/backends/jira/api.js +89 -0
  35. package/dist/backends/jira/api.js.map +1 -0
  36. package/dist/backends/jira/index.d.ts +10 -2
  37. package/dist/backends/jira/index.js +140 -161
  38. package/dist/backends/jira/index.js.map +1 -1
  39. package/dist/backends/jira/mappers.d.ts +8 -2
  40. package/dist/backends/jira/mappers.js +20 -5
  41. package/dist/backends/jira/mappers.js.map +1 -1
  42. package/dist/backends/shared/api-client.d.ts +1 -0
  43. package/dist/backends/shared/api-client.js +18 -3
  44. package/dist/backends/shared/api-client.js.map +1 -1
  45. package/dist/backends/types.d.ts +1 -0
  46. package/dist/backends/types.js.map +1 -1
  47. package/dist/cli/commands/auth.js +34 -2
  48. package/dist/cli/commands/auth.js.map +1 -1
  49. package/dist/cli/commands/item.js +2 -2
  50. package/dist/cli/commands/item.js.map +1 -1
  51. package/dist/components/AuthPrompt.js +36 -4
  52. package/dist/components/AuthPrompt.js.map +1 -1
  53. package/dist/components/ErrorBoundary.d.ts +14 -0
  54. package/dist/components/ErrorBoundary.js +30 -0
  55. package/dist/components/ErrorBoundary.js.map +1 -0
  56. package/dist/components/Settings.js +82 -17
  57. package/dist/components/Settings.js.map +1 -1
  58. package/dist/components/StatusScreen.js +3 -1
  59. package/dist/components/StatusScreen.js.map +1 -1
  60. package/dist/components/WorkItemForm.js +57 -14
  61. package/dist/components/WorkItemForm.js.map +1 -1
  62. package/dist/components/WorkItemList.js +141 -35
  63. package/dist/components/WorkItemList.js.map +1 -1
  64. package/dist/components/getMarkedDistribution.d.ts +6 -0
  65. package/dist/components/getMarkedDistribution.js +17 -0
  66. package/dist/components/getMarkedDistribution.js.map +1 -0
  67. package/dist/editor.js +0 -1
  68. package/dist/editor.js.map +1 -1
  69. package/dist/hooks/useFormValidation.d.ts +20 -0
  70. package/dist/hooks/useFormValidation.js +146 -0
  71. package/dist/hooks/useFormValidation.js.map +1 -0
  72. package/dist/index.js +2 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/storage/index.js +15 -12
  75. package/dist/storage/index.js.map +1 -1
  76. package/dist/stores/backendDataStore.d.ts +2 -1
  77. package/dist/stores/backendDataStore.js +78 -6
  78. package/dist/stores/backendDataStore.js.map +1 -1
  79. package/dist/stores/recentCommandsStore.js +3 -1
  80. package/dist/stores/recentCommandsStore.js.map +1 -1
  81. package/dist/sync/SyncManager.d.ts +1 -1
  82. package/dist/sync/SyncManager.js +51 -10
  83. package/dist/sync/SyncManager.js.map +1 -1
  84. package/dist/update-checker.js +5 -3
  85. package/dist/update-checker.js.map +1 -1
  86. package/package.json +1 -1
  87. package/dist/backends/jira/acli.d.ts +0 -6
  88. package/dist/backends/jira/acli.js +0 -35
  89. package/dist/backends/jira/acli.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tic",
3
3
  "description": "Issue tracking skills for Claude Code",
4
- "version": "4.1.0",
4
+ "version": "4.3.0",
5
5
  "author": {
6
6
  "name": "Sascha Krug"
7
7
  },
package/dist/app.js CHANGED
@@ -31,10 +31,12 @@ export function App() {
31
31
  // Update check on mount
32
32
  useEffect(() => {
33
33
  if (autoUpdate !== false) {
34
- void import('./update-checker.js').then(({ checkForUpdate }) => checkForUpdate().then((info) => {
34
+ void import('./update-checker.js')
35
+ .then(({ checkForUpdate }) => checkForUpdate().then((info) => {
35
36
  if (info)
36
37
  navigationStore.getState().setUpdateInfo(info);
37
- }));
38
+ }))
39
+ .catch(() => { });
38
40
  }
39
41
  }, [autoUpdate]);
40
42
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, {}), authPrompt ? (_jsx(Suspense, { fallback: null, children: _jsx(AuthPrompt, {}) })) : (_jsxs(_Fragment, { children: [screen === 'list' && _jsx(WorkItemList, {}), _jsxs(Suspense, { fallback: null, children: [screen === 'form' && _jsx(WorkItemForm, {}), screen === 'iteration-picker' && _jsx(IterationPicker, {}), screen === 'settings' && _jsx(Settings, {}), screen === 'status' && _jsx(StatusScreen, {}), screen === 'help' && _jsx(HelpScreen, { sourceScreen: previousScreen })] })] }))] }));
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"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"}
package/dist/auth/ado.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getToken, setToken, deleteToken } from './keychain.js';
2
+ import { DEFAULT_TIMEOUT_MS } from '../backends/shared/api-client.js';
2
3
  export const ADO_ACCOUNT = 'dev.azure.com';
3
4
  export const ADO_REFRESH_ACCOUNT = 'dev.azure.com:refresh';
4
5
  export const ADO_PAT_ACCOUNT = 'dev.azure.com:pat';
@@ -40,16 +41,31 @@ function urlEncode(params) {
40
41
  */
41
42
  export async function refreshAdoToken(refreshToken) {
42
43
  try {
43
- const response = await fetch(`${AUTHORITY}/oauth2/v2.0/token`, {
44
- method: 'POST',
45
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
46
- body: urlEncode({
47
- client_id: AZURE_CLI_CLIENT_ID,
48
- grant_type: 'refresh_token',
49
- refresh_token: refreshToken,
50
- scope: ADO_SCOPE,
51
- }),
52
- });
44
+ const controller = new AbortController();
45
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
46
+ let response;
47
+ try {
48
+ response = await fetch(`${AUTHORITY}/oauth2/v2.0/token`, {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
51
+ body: urlEncode({
52
+ client_id: AZURE_CLI_CLIENT_ID,
53
+ grant_type: 'refresh_token',
54
+ refresh_token: refreshToken,
55
+ scope: ADO_SCOPE,
56
+ }),
57
+ signal: controller.signal,
58
+ });
59
+ }
60
+ catch (error) {
61
+ if (error instanceof DOMException && error.name === 'AbortError') {
62
+ throw new Error('Request timed out');
63
+ }
64
+ throw error;
65
+ }
66
+ finally {
67
+ clearTimeout(timeout);
68
+ }
53
69
  if (!response.ok)
54
70
  return null;
55
71
  const data = (await response.json());
@@ -80,14 +96,29 @@ export async function refreshAdoToken(refreshToken) {
80
96
  */
81
97
  export async function authenticateAdo(options) {
82
98
  // Step 1: Request device code
83
- const codeResponse = await fetch(`${AUTHORITY}/oauth2/v2.0/devicecode`, {
84
- method: 'POST',
85
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
86
- body: urlEncode({
87
- client_id: AZURE_CLI_CLIENT_ID,
88
- scope: ADO_SCOPE,
89
- }),
90
- });
99
+ const codeController = new AbortController();
100
+ const codeTimeout = setTimeout(() => codeController.abort(), DEFAULT_TIMEOUT_MS);
101
+ let codeResponse;
102
+ try {
103
+ codeResponse = await fetch(`${AUTHORITY}/oauth2/v2.0/devicecode`, {
104
+ method: 'POST',
105
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
106
+ body: urlEncode({
107
+ client_id: AZURE_CLI_CLIENT_ID,
108
+ scope: ADO_SCOPE,
109
+ }),
110
+ signal: codeController.signal,
111
+ });
112
+ }
113
+ catch (error) {
114
+ if (error instanceof DOMException && error.name === 'AbortError') {
115
+ throw new Error('Request timed out');
116
+ }
117
+ throw error;
118
+ }
119
+ finally {
120
+ clearTimeout(codeTimeout);
121
+ }
91
122
  if (!codeResponse.ok) {
92
123
  throw new Error(`Failed to request device code: ${codeResponse.status} ${codeResponse.statusText}`);
93
124
  }
@@ -96,17 +127,33 @@ export async function authenticateAdo(options) {
96
127
  options?.onCode?.(deviceCode.user_code, deviceCode.verification_uri);
97
128
  // Step 3: Poll for access token
98
129
  let interval = deviceCode.interval * 1000;
99
- while (true) {
130
+ const deadline = Date.now() + deviceCode.expires_in * 1000;
131
+ while (Date.now() < deadline) {
100
132
  await sleep(interval);
101
- const tokenResponse = await fetch(`${AUTHORITY}/oauth2/v2.0/token`, {
102
- method: 'POST',
103
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
104
- body: urlEncode({
105
- client_id: AZURE_CLI_CLIENT_ID,
106
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
107
- device_code: deviceCode.device_code,
108
- }),
109
- });
133
+ const tokenController = new AbortController();
134
+ const tokenTimeout = setTimeout(() => tokenController.abort(), DEFAULT_TIMEOUT_MS);
135
+ let tokenResponse;
136
+ try {
137
+ tokenResponse = await fetch(`${AUTHORITY}/oauth2/v2.0/token`, {
138
+ method: 'POST',
139
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
140
+ body: urlEncode({
141
+ client_id: AZURE_CLI_CLIENT_ID,
142
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
143
+ device_code: deviceCode.device_code,
144
+ }),
145
+ signal: tokenController.signal,
146
+ });
147
+ }
148
+ catch (error) {
149
+ if (error instanceof DOMException && error.name === 'AbortError') {
150
+ throw new Error('Request timed out');
151
+ }
152
+ throw error;
153
+ }
154
+ finally {
155
+ clearTimeout(tokenTimeout);
156
+ }
110
157
  // Entra ID returns 400 for pending/slow_down/declined/expired errors
111
158
  if (!tokenResponse.ok) {
112
159
  const data = (await tokenResponse.json());
@@ -132,5 +179,6 @@ export async function authenticateAdo(options) {
132
179
  }
133
180
  return data.access_token;
134
181
  }
182
+ throw new Error('Device code has expired. Please restart the authentication flow.');
135
183
  }
136
184
  //# sourceMappingURL=ado.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ado.js","sourceRoot":"","sources":["../../src/auth/ado.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ado.js","sourceRoot":"","sources":["../../src/auth/ado.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { getToken, setToken, deleteToken } from './keychain.js';
2
+ import { DEFAULT_TIMEOUT_MS } from '../backends/shared/api-client.js';
2
3
  export const GITHUB_ACCOUNT = 'github.com';
3
4
  export const DEFAULT_CLIENT_ID = 'Ov23lizRXsY0iSURg1he';
4
5
  /**
@@ -34,28 +35,11 @@ function sleep(ms) {
34
35
  export async function authenticateGitHub(options) {
35
36
  const clientId = options?.clientId ?? DEFAULT_CLIENT_ID;
36
37
  // Step 1: Request device code
37
- const codeResponse = await fetch('https://github.com/login/device/code', {
38
- method: 'POST',
39
- headers: {
40
- Accept: 'application/json',
41
- 'Content-Type': 'application/json',
42
- },
43
- body: JSON.stringify({
44
- client_id: clientId,
45
- scope: 'repo',
46
- }),
47
- });
48
- if (!codeResponse.ok) {
49
- throw new Error(`Failed to request device code: ${codeResponse.status} ${codeResponse.statusText}`);
50
- }
51
- const deviceCode = (await codeResponse.json());
52
- // Step 2: Notify caller with user code and verification URL
53
- options?.onCode?.(deviceCode.user_code, deviceCode.verification_uri);
54
- // Step 3: Poll for access token
55
- let interval = deviceCode.interval * 1000; // Convert to ms
56
- while (true) {
57
- await sleep(interval);
58
- const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
38
+ const codeController = new AbortController();
39
+ const codeTimeout = setTimeout(() => codeController.abort(), DEFAULT_TIMEOUT_MS);
40
+ let codeResponse;
41
+ try {
42
+ codeResponse = await fetch('https://github.com/login/device/code', {
59
43
  method: 'POST',
60
44
  headers: {
61
45
  Accept: 'application/json',
@@ -63,10 +47,58 @@ export async function authenticateGitHub(options) {
63
47
  },
64
48
  body: JSON.stringify({
65
49
  client_id: clientId,
66
- device_code: deviceCode.device_code,
67
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
50
+ scope: 'repo',
68
51
  }),
52
+ signal: codeController.signal,
69
53
  });
54
+ }
55
+ catch (error) {
56
+ if (error instanceof DOMException && error.name === 'AbortError') {
57
+ throw new Error('Request timed out');
58
+ }
59
+ throw error;
60
+ }
61
+ finally {
62
+ clearTimeout(codeTimeout);
63
+ }
64
+ if (!codeResponse.ok) {
65
+ throw new Error(`Failed to request device code: ${codeResponse.status} ${codeResponse.statusText}`);
66
+ }
67
+ const deviceCode = (await codeResponse.json());
68
+ // Step 2: Notify caller with user code and verification URL
69
+ options?.onCode?.(deviceCode.user_code, deviceCode.verification_uri);
70
+ // Step 3: Poll for access token
71
+ let interval = deviceCode.interval * 1000; // Convert to ms
72
+ const deadline = Date.now() + deviceCode.expires_in * 1000;
73
+ while (Date.now() < deadline) {
74
+ await sleep(interval);
75
+ const tokenController = new AbortController();
76
+ const tokenTimeout = setTimeout(() => tokenController.abort(), DEFAULT_TIMEOUT_MS);
77
+ let tokenResponse;
78
+ try {
79
+ tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
80
+ method: 'POST',
81
+ headers: {
82
+ Accept: 'application/json',
83
+ 'Content-Type': 'application/json',
84
+ },
85
+ body: JSON.stringify({
86
+ client_id: clientId,
87
+ device_code: deviceCode.device_code,
88
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
89
+ }),
90
+ signal: tokenController.signal,
91
+ });
92
+ }
93
+ catch (error) {
94
+ if (error instanceof DOMException && error.name === 'AbortError') {
95
+ throw new Error('Request timed out');
96
+ }
97
+ throw error;
98
+ }
99
+ finally {
100
+ clearTimeout(tokenTimeout);
101
+ }
70
102
  if (!tokenResponse.ok) {
71
103
  throw new Error(`Failed to poll for token: ${tokenResponse.status} ${tokenResponse.statusText}`);
72
104
  }
@@ -92,5 +124,6 @@ export async function authenticateGitHub(options) {
92
124
  setToken(GITHUB_ACCOUNT, data.access_token);
93
125
  return data.access_token;
94
126
  }
127
+ throw new Error('Device code has expired. Please restart the authentication flow.');
95
128
  }
96
129
  //# sourceMappingURL=github.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/auth/github.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/auth/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,CAAC,cAAc,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,WAAW,CAAC,cAAc,CAAC,CAAC;AAC9B,CAAC;AA4BD,SAAS,YAAY,CACnB,QAA2B;IAE3B,OAAO,OAAO,IAAI,QAAQ,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAmC;IAEnC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,iBAAiB,CAAC;IAExD,8BAA8B;IAC9B,MAAM,cAAc,GAAG,IAAI,eAAe,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAG,UAAU,CAC5B,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,EAC5B,kBAAkB,CACnB,CAAC;IAEF,IAAI,YAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;YACjE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,SAAS,EAAE,QAAQ;gBACnB,KAAK,EAAE,MAAM;aACd,CAAC;YACF,MAAM,EAAE,cAAc,CAAC,MAAM;SAC9B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,kCAAkC,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,MAAM,YAAY,CAAC,IAAI,EAAE,CAAuB,CAAC;IAErE,4DAA4D;IAC5D,OAAO,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAErE,gCAAgC;IAChC,IAAI,QAAQ,GAAG,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,gBAAgB;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC;IAE3D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEtB,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,MAAM,YAAY,GAAG,UAAU,CAC7B,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,EAC7B,kBAAkB,CACnB,CAAC;QAEF,IAAI,aAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,aAAa,GAAG,MAAM,KAAK,CACzB,6CAA6C,EAC7C;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,MAAM,EAAE,kBAAkB;oBAC1B,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,SAAS,EAAE,QAAQ;oBACnB,WAAW,EAAE,UAAU,CAAC,WAAW;oBACnC,UAAU,EAAE,8CAA8C;iBAC3D,CAAC;gBACF,MAAM,EAAE,eAAe,CAAC,MAAM;aAC/B,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACjE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,6BAA6B,aAAa,CAAC,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,CAChF,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAAsB,CAAC;QAE/D,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;gBACnB,KAAK,uBAAuB;oBAC1B,2CAA2C;oBAC3C,SAAS;gBACX,KAAK,WAAW;oBACd,gEAAgE;oBAChE,QAAQ,IAAI,IAAI,CAAC;oBACjB,SAAS;gBACX,KAAK,eAAe;oBAClB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;gBAC1D,KAAK,eAAe;oBAClB,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;gBACJ;oBACE,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACtG,CAAC;YACN,CAAC;QACH,CAAC;QAED,mCAAmC;QACnC,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;AACJ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { getToken, setToken, deleteToken } from './keychain.js';
2
+ import { DEFAULT_TIMEOUT_MS } from '../backends/shared/api-client.js';
2
3
  export const GITLAB_ACCOUNT = 'gitlab.com';
3
4
  export const GITLAB_PAT_ACCOUNT = 'gitlab.com:pat';
4
5
  export const DEFAULT_GITLAB_CLIENT_ID = 'cdcaceeece0df785f6df0e8b94fce6669ec8521787844faed02a5605b29e05bd';
@@ -49,17 +50,32 @@ function sleep(ms) {
49
50
  export async function authenticateGitLab(options) {
50
51
  const clientId = options?.clientId ?? DEFAULT_GITLAB_CLIENT_ID;
51
52
  // Step 1: Request device code
52
- const codeResponse = await fetch('https://gitlab.com/oauth/authorize_device', {
53
- method: 'POST',
54
- headers: {
55
- Accept: 'application/json',
56
- 'Content-Type': 'application/json',
57
- },
58
- body: JSON.stringify({
59
- client_id: clientId,
60
- scope: 'api',
61
- }),
62
- });
53
+ const codeController = new AbortController();
54
+ const codeTimeout = setTimeout(() => codeController.abort(), DEFAULT_TIMEOUT_MS);
55
+ let codeResponse;
56
+ try {
57
+ codeResponse = await fetch('https://gitlab.com/oauth/authorize_device', {
58
+ method: 'POST',
59
+ headers: {
60
+ Accept: 'application/json',
61
+ 'Content-Type': 'application/json',
62
+ },
63
+ body: JSON.stringify({
64
+ client_id: clientId,
65
+ scope: 'api',
66
+ }),
67
+ signal: codeController.signal,
68
+ });
69
+ }
70
+ catch (error) {
71
+ if (error instanceof DOMException && error.name === 'AbortError') {
72
+ throw new Error('Request timed out');
73
+ }
74
+ throw error;
75
+ }
76
+ finally {
77
+ clearTimeout(codeTimeout);
78
+ }
63
79
  if (!codeResponse.ok) {
64
80
  throw new Error(`Failed to request device code: ${codeResponse.status} ${codeResponse.statusText}`);
65
81
  }
@@ -70,18 +86,33 @@ export async function authenticateGitLab(options) {
70
86
  let interval = deviceCode.interval * 1000; // Convert to ms
71
87
  while (true) {
72
88
  await sleep(interval);
73
- const tokenResponse = await fetch('https://gitlab.com/oauth/token', {
74
- method: 'POST',
75
- headers: {
76
- Accept: 'application/json',
77
- 'Content-Type': 'application/json',
78
- },
79
- body: JSON.stringify({
80
- client_id: clientId,
81
- device_code: deviceCode.device_code,
82
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
83
- }),
84
- });
89
+ const tokenController = new AbortController();
90
+ const tokenTimeout = setTimeout(() => tokenController.abort(), DEFAULT_TIMEOUT_MS);
91
+ let tokenResponse;
92
+ try {
93
+ tokenResponse = await fetch('https://gitlab.com/oauth/token', {
94
+ method: 'POST',
95
+ headers: {
96
+ Accept: 'application/json',
97
+ 'Content-Type': 'application/json',
98
+ },
99
+ body: JSON.stringify({
100
+ client_id: clientId,
101
+ device_code: deviceCode.device_code,
102
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
103
+ }),
104
+ signal: tokenController.signal,
105
+ });
106
+ }
107
+ catch (error) {
108
+ if (error instanceof DOMException && error.name === 'AbortError') {
109
+ throw new Error('Request timed out');
110
+ }
111
+ throw error;
112
+ }
113
+ finally {
114
+ clearTimeout(tokenTimeout);
115
+ }
85
116
  if (!tokenResponse.ok) {
86
117
  throw new Error(`Failed to poll for token: ${tokenResponse.status} ${tokenResponse.statusText}`);
87
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/auth/gitlab.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/auth/gitlab.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare const JIRA_ACCOUNT_PREFIX = "jira:";
2
+ export interface JiraCredentials {
3
+ email: string;
4
+ token: string;
5
+ }
6
+ export declare function getJiraCredentials(site: string): JiraCredentials | null;
7
+ export declare function setJiraCredentials(site: string, email: string, token: string): void;
8
+ export declare function removeJiraCredentials(site: string): void;
@@ -0,0 +1,24 @@
1
+ import { getToken, setToken, deleteToken } from './keychain.js';
2
+ export const JIRA_ACCOUNT_PREFIX = 'jira:';
3
+ export function getJiraCredentials(site) {
4
+ const stored = getToken(`${JIRA_ACCOUNT_PREFIX}${site}`);
5
+ if (!stored)
6
+ return null;
7
+ let idx = stored.indexOf('\0');
8
+ if (idx < 0) {
9
+ idx = stored.indexOf(':');
10
+ }
11
+ if (idx < 0)
12
+ return null;
13
+ return {
14
+ email: stored.slice(0, idx),
15
+ token: stored.slice(idx + 1),
16
+ };
17
+ }
18
+ export function setJiraCredentials(site, email, token) {
19
+ setToken(`${JIRA_ACCOUNT_PREFIX}${site}`, `${email}\0${token}`);
20
+ }
21
+ export function removeJiraCredentials(site) {
22
+ deleteToken(`${JIRA_ACCOUNT_PREFIX}${site}`);
23
+ }
24
+ //# sourceMappingURL=jira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../src/auth/jira.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAO3C,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,mBAAmB,GAAG,IAAI,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzB,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,KAAa,EACb,KAAa;IAEb,QAAQ,CAAC,GAAG,mBAAmB,GAAG,IAAI,EAAE,EAAE,GAAG,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,WAAW,CAAC,GAAG,mBAAmB,GAAG,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC"}
@@ -8,6 +8,7 @@ export type AdoAuth = {
8
8
  };
9
9
  export declare class AdoApiClient extends BaseApiClient {
10
10
  private auth;
11
+ private refreshPromise;
11
12
  constructor(auth: AdoAuth, org: string);
12
13
  private getAuthHeader;
13
14
  private appendApiVersion;
@@ -1,8 +1,9 @@
1
- import { BaseApiClient, AuthError } from '../shared/api-client.js';
1
+ import { BaseApiClient, AuthError, DEFAULT_TIMEOUT_MS, } from '../shared/api-client.js';
2
2
  import { getAdoRefreshToken, refreshAdoToken } from '../../auth/ado.js';
3
3
  const ADO_API_VERSION = '7.1';
4
4
  export class AdoApiClient extends BaseApiClient {
5
5
  auth;
6
+ refreshPromise = null;
6
7
  constructor(auth, org) {
7
8
  const token = auth.type === 'bearer' ? auth.token : auth.pat;
8
9
  super(token, `https://dev.azure.com/${org}`);
@@ -29,22 +30,58 @@ export class AdoApiClient extends BaseApiClient {
29
30
  headers['Content-Type'] = contentType ?? 'application/json';
30
31
  init.body = JSON.stringify(body);
31
32
  }
32
- let response = await globalThis.fetch(url, init);
33
+ const controller = new AbortController();
34
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
35
+ let response;
36
+ try {
37
+ response = await globalThis.fetch(url, {
38
+ ...init,
39
+ signal: controller.signal,
40
+ });
41
+ }
42
+ catch (error) {
43
+ if (error instanceof DOMException && error.name === 'AbortError') {
44
+ throw new Error('Request timed out');
45
+ }
46
+ throw error;
47
+ }
48
+ finally {
49
+ clearTimeout(timeout);
50
+ }
33
51
  this.checkRateLimit(response.headers);
34
52
  // Try token refresh on 401 for OAuth auth
35
53
  if (response.status === 401 && this.auth.type === 'bearer') {
36
54
  const refreshToken = getAdoRefreshToken();
37
55
  if (refreshToken) {
38
- const newToken = await refreshAdoToken(refreshToken);
56
+ if (!this.refreshPromise) {
57
+ this.refreshPromise = refreshAdoToken(refreshToken).finally(() => {
58
+ this.refreshPromise = null;
59
+ });
60
+ }
61
+ const newToken = await this.refreshPromise;
39
62
  if (newToken) {
40
63
  this.auth = { type: 'bearer', token: newToken };
41
64
  this.token = newToken;
42
65
  headers['Authorization'] = `Bearer ${newToken}`;
43
- response = await globalThis.fetch(url, {
44
- method,
45
- headers,
46
- body: init.body,
47
- });
66
+ const retryController = new AbortController();
67
+ const retryTimeout = setTimeout(() => retryController.abort(), DEFAULT_TIMEOUT_MS);
68
+ try {
69
+ response = await globalThis.fetch(url, {
70
+ method,
71
+ headers,
72
+ body: init.body,
73
+ signal: retryController.signal,
74
+ });
75
+ }
76
+ catch (error) {
77
+ if (error instanceof DOMException && error.name === 'AbortError') {
78
+ throw new Error('Request timed out');
79
+ }
80
+ throw error;
81
+ }
82
+ finally {
83
+ clearTimeout(retryTimeout);
84
+ }
48
85
  }
49
86
  }
50
87
  }
@@ -52,8 +89,7 @@ export class AdoApiClient extends BaseApiClient {
52
89
  throw new AuthError();
53
90
  }
54
91
  if (!response.ok) {
55
- const text = await response.text();
56
- throw new Error(`HTTP ${response.status}: ${text}`);
92
+ throw new Error(`HTTP ${response.status}: Request failed`);
57
93
  }
58
94
  return (await response.json());
59
95
  }
@@ -80,17 +116,31 @@ export class AdoApiClient extends BaseApiClient {
80
116
  Authorization: this.getAuthHeader(),
81
117
  Accept: 'application/json',
82
118
  };
83
- const response = await globalThis.fetch(url, {
84
- method: 'GET',
85
- headers,
86
- });
119
+ const controller = new AbortController();
120
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
121
+ let response;
122
+ try {
123
+ response = await globalThis.fetch(url, {
124
+ method: 'GET',
125
+ headers,
126
+ signal: controller.signal,
127
+ });
128
+ }
129
+ catch (error) {
130
+ if (error instanceof DOMException && error.name === 'AbortError') {
131
+ throw new Error('Request timed out');
132
+ }
133
+ throw error;
134
+ }
135
+ finally {
136
+ clearTimeout(timeout);
137
+ }
87
138
  this.checkRateLimit(response.headers);
88
139
  if (response.status === 401) {
89
140
  throw new AuthError();
90
141
  }
91
142
  if (!response.ok) {
92
- const text = await response.text();
93
- throw new Error(`HTTP ${response.status}: ${text}`);
143
+ throw new Error(`HTTP ${response.status}: Request failed`);
94
144
  }
95
145
  const json = (await response.json());
96
146
  yield json.value;