@zhafron/opencode-kiro-auth 1.0.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 (110) hide show
  1. package/README.md +85 -0
  2. package/dist/constants.d.ts +26 -0
  3. package/dist/constants.js +60 -0
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.js +1 -0
  6. package/dist/kiro/auth.d.ts +5 -0
  7. package/dist/kiro/auth.js +24 -0
  8. package/dist/kiro/oauth-idc.d.ts +24 -0
  9. package/dist/kiro/oauth-idc.js +132 -0
  10. package/dist/kiro/oauth-social.d.ts +17 -0
  11. package/dist/kiro/oauth-social.js +51 -0
  12. package/dist/plugin/accounts.d.ts +28 -0
  13. package/dist/plugin/accounts.js +156 -0
  14. package/dist/plugin/auth-page.d.ts +3 -0
  15. package/dist/plugin/auth-page.js +568 -0
  16. package/dist/plugin/cli.d.ts +6 -0
  17. package/dist/plugin/cli.js +98 -0
  18. package/dist/plugin/config/index.d.ts +3 -0
  19. package/dist/plugin/config/index.js +2 -0
  20. package/dist/plugin/config/loader.d.ts +6 -0
  21. package/dist/plugin/config/loader.js +125 -0
  22. package/dist/plugin/config/schema.d.ts +44 -0
  23. package/dist/plugin/config/schema.js +28 -0
  24. package/dist/plugin/debug.d.ts +2 -0
  25. package/dist/plugin/debug.js +9 -0
  26. package/dist/plugin/errors.d.ts +17 -0
  27. package/dist/plugin/errors.js +34 -0
  28. package/dist/plugin/logger.d.ts +4 -0
  29. package/dist/plugin/logger.js +37 -0
  30. package/dist/plugin/models.d.ts +3 -0
  31. package/dist/plugin/models.js +14 -0
  32. package/dist/plugin/oauth-parser.d.ts +5 -0
  33. package/dist/plugin/oauth-parser.js +23 -0
  34. package/dist/plugin/quota.d.ts +15 -0
  35. package/dist/plugin/quota.js +68 -0
  36. package/dist/plugin/recovery.d.ts +19 -0
  37. package/dist/plugin/recovery.js +302 -0
  38. package/dist/plugin/refresh-queue.d.ts +14 -0
  39. package/dist/plugin/refresh-queue.js +69 -0
  40. package/dist/plugin/request.d.ts +4 -0
  41. package/dist/plugin/request.js +240 -0
  42. package/dist/plugin/response.d.ts +6 -0
  43. package/dist/plugin/response.js +246 -0
  44. package/dist/plugin/server.d.ts +24 -0
  45. package/dist/plugin/server.js +96 -0
  46. package/dist/plugin/storage.d.ts +7 -0
  47. package/dist/plugin/storage.js +75 -0
  48. package/dist/plugin/streaming.d.ts +3 -0
  49. package/dist/plugin/streaming.js +503 -0
  50. package/dist/plugin/token.d.ts +2 -0
  51. package/dist/plugin/token.js +56 -0
  52. package/dist/plugin/types.d.ts +148 -0
  53. package/dist/plugin/types.js +0 -0
  54. package/dist/plugin/usage.d.ts +3 -0
  55. package/dist/plugin/usage.js +36 -0
  56. package/dist/plugin.d.ts +32 -0
  57. package/dist/plugin.js +222 -0
  58. package/dist/src/constants.d.ts +22 -0
  59. package/dist/src/constants.js +35 -0
  60. package/dist/src/kiro/auth.d.ts +5 -0
  61. package/dist/src/kiro/auth.js +69 -0
  62. package/dist/src/kiro/oauth-idc.d.ts +22 -0
  63. package/dist/src/kiro/oauth-idc.js +99 -0
  64. package/dist/src/kiro/oauth-social.d.ts +17 -0
  65. package/dist/src/kiro/oauth-social.js +69 -0
  66. package/dist/src/plugin/accounts.d.ts +23 -0
  67. package/dist/src/plugin/accounts.js +265 -0
  68. package/dist/src/plugin/cli.d.ts +6 -0
  69. package/dist/src/plugin/cli.js +98 -0
  70. package/dist/src/plugin/config/index.d.ts +3 -0
  71. package/dist/src/plugin/config/index.js +2 -0
  72. package/dist/src/plugin/config/loader.d.ts +7 -0
  73. package/dist/src/plugin/config/loader.js +143 -0
  74. package/dist/src/plugin/config/schema.d.ts +68 -0
  75. package/dist/src/plugin/config/schema.js +44 -0
  76. package/dist/src/plugin/debug.d.ts +2 -0
  77. package/dist/src/plugin/debug.js +9 -0
  78. package/dist/src/plugin/errors.d.ts +17 -0
  79. package/dist/src/plugin/errors.js +34 -0
  80. package/dist/src/plugin/logger.d.ts +4 -0
  81. package/dist/src/plugin/logger.js +17 -0
  82. package/dist/src/plugin/models.d.ts +3 -0
  83. package/dist/src/plugin/models.js +14 -0
  84. package/dist/src/plugin/oauth-parser.d.ts +5 -0
  85. package/dist/src/plugin/oauth-parser.js +23 -0
  86. package/dist/src/plugin/quota.d.ts +25 -0
  87. package/dist/src/plugin/quota.js +175 -0
  88. package/dist/src/plugin/recovery.d.ts +19 -0
  89. package/dist/src/plugin/recovery.js +302 -0
  90. package/dist/src/plugin/refresh-queue.d.ts +14 -0
  91. package/dist/src/plugin/refresh-queue.js +69 -0
  92. package/dist/src/plugin/request.d.ts +35 -0
  93. package/dist/src/plugin/request.js +411 -0
  94. package/dist/src/plugin/response.d.ts +6 -0
  95. package/dist/src/plugin/response.js +246 -0
  96. package/dist/src/plugin/server.d.ts +10 -0
  97. package/dist/src/plugin/server.js +203 -0
  98. package/dist/src/plugin/storage.d.ts +5 -0
  99. package/dist/src/plugin/storage.js +106 -0
  100. package/dist/src/plugin/streaming.d.ts +12 -0
  101. package/dist/src/plugin/streaming.js +444 -0
  102. package/dist/src/plugin/token.d.ts +8 -0
  103. package/dist/src/plugin/token.js +130 -0
  104. package/dist/src/plugin/types.d.ts +144 -0
  105. package/dist/src/plugin/types.js +0 -0
  106. package/dist/src/plugin/usage.d.ts +28 -0
  107. package/dist/src/plugin/usage.js +159 -0
  108. package/dist/src/plugin.d.ts +2 -0
  109. package/dist/src/plugin.js +341 -0
  110. package/package.json +57 -0
@@ -0,0 +1,444 @@
1
+ import { parseBracketToolCalls, parseEventLine } from './response';
2
+ const THINKING_START_TAG = '<thinking>';
3
+ const THINKING_END_TAG = '</thinking>';
4
+ export async function* transformKiroStream(response, model, conversationId) {
5
+ const thinkingRequested = true;
6
+ const streamState = {
7
+ thinkingRequested,
8
+ buffer: '',
9
+ inThinking: false,
10
+ thinkingExtracted: false,
11
+ thinkingBlockIndex: null,
12
+ textBlockIndex: null,
13
+ nextBlockIndex: 0,
14
+ stoppedBlocks: new Set()
15
+ };
16
+ yield {
17
+ type: 'message_start',
18
+ message: {
19
+ id: conversationId,
20
+ type: 'message',
21
+ role: 'assistant',
22
+ model: model,
23
+ usage: {
24
+ input_tokens: 0,
25
+ output_tokens: 0,
26
+ cache_creation_input_tokens: 0,
27
+ cache_read_input_tokens: 0
28
+ },
29
+ content: []
30
+ }
31
+ };
32
+ if (!response.body) {
33
+ throw new Error('Response body is null');
34
+ }
35
+ const reader = response.body.getReader();
36
+ const decoder = new TextDecoder();
37
+ let rawBuffer = '';
38
+ let totalContent = '';
39
+ let outputTokens = 0;
40
+ let inputTokens = 0;
41
+ let contextUsagePercentage = null;
42
+ const toolCalls = [];
43
+ let currentToolCall = null;
44
+ try {
45
+ while (true) {
46
+ const { done, value } = await reader.read();
47
+ if (done)
48
+ break;
49
+ const chunk = decoder.decode(value, { stream: true });
50
+ rawBuffer += chunk;
51
+ const events = parseStreamBuffer(rawBuffer);
52
+ rawBuffer = events.remaining;
53
+ for (const event of events.events) {
54
+ if (event.type === 'contextUsage' && event.data.contextUsagePercentage) {
55
+ contextUsagePercentage = event.data.contextUsagePercentage;
56
+ }
57
+ else if (event.type === 'content' && event.data) {
58
+ totalContent += event.data;
59
+ if (!thinkingRequested) {
60
+ yield* createTextDeltaEvents(event.data, streamState);
61
+ continue;
62
+ }
63
+ streamState.buffer += event.data;
64
+ const deltaEvents = [];
65
+ while (streamState.buffer.length > 0) {
66
+ if (!streamState.inThinking && !streamState.thinkingExtracted) {
67
+ const startPos = findRealTag(streamState.buffer, THINKING_START_TAG);
68
+ if (startPos !== -1) {
69
+ const before = streamState.buffer.slice(0, startPos);
70
+ if (before) {
71
+ deltaEvents.push(...createTextDeltaEvents(before, streamState));
72
+ }
73
+ streamState.buffer = streamState.buffer.slice(startPos + THINKING_START_TAG.length);
74
+ streamState.inThinking = true;
75
+ continue;
76
+ }
77
+ const safeLen = Math.max(0, streamState.buffer.length - THINKING_START_TAG.length);
78
+ if (safeLen > 0) {
79
+ const safeText = streamState.buffer.slice(0, safeLen);
80
+ if (safeText) {
81
+ deltaEvents.push(...createTextDeltaEvents(safeText, streamState));
82
+ }
83
+ streamState.buffer = streamState.buffer.slice(safeLen);
84
+ }
85
+ break;
86
+ }
87
+ if (streamState.inThinking) {
88
+ const endPos = findRealTag(streamState.buffer, THINKING_END_TAG);
89
+ if (endPos !== -1) {
90
+ const thinkingPart = streamState.buffer.slice(0, endPos);
91
+ if (thinkingPart) {
92
+ deltaEvents.push(...createThinkingDeltaEvents(thinkingPart, streamState));
93
+ }
94
+ streamState.buffer = streamState.buffer.slice(endPos + THINKING_END_TAG.length);
95
+ streamState.inThinking = false;
96
+ streamState.thinkingExtracted = true;
97
+ deltaEvents.push(...createThinkingDeltaEvents('', streamState));
98
+ deltaEvents.push(...stopBlock(streamState.thinkingBlockIndex, streamState));
99
+ if (streamState.buffer.startsWith('\n\n')) {
100
+ streamState.buffer = streamState.buffer.slice(2);
101
+ }
102
+ continue;
103
+ }
104
+ const safeLen = Math.max(0, streamState.buffer.length - THINKING_END_TAG.length);
105
+ if (safeLen > 0) {
106
+ const safeThinking = streamState.buffer.slice(0, safeLen);
107
+ if (safeThinking) {
108
+ deltaEvents.push(...createThinkingDeltaEvents(safeThinking, streamState));
109
+ }
110
+ streamState.buffer = streamState.buffer.slice(safeLen);
111
+ }
112
+ break;
113
+ }
114
+ if (streamState.thinkingExtracted) {
115
+ const rest = streamState.buffer;
116
+ streamState.buffer = '';
117
+ if (rest) {
118
+ deltaEvents.push(...createTextDeltaEvents(rest, streamState));
119
+ }
120
+ break;
121
+ }
122
+ }
123
+ for (const ev of deltaEvents) {
124
+ yield ev;
125
+ }
126
+ }
127
+ else if (event.type === 'toolUse') {
128
+ const tc = event.data;
129
+ if (tc.name) {
130
+ totalContent += tc.name;
131
+ }
132
+ if (tc.input) {
133
+ totalContent += tc.input;
134
+ }
135
+ if (tc.name && tc.toolUseId) {
136
+ if (currentToolCall && currentToolCall.toolUseId === tc.toolUseId) {
137
+ currentToolCall.input += tc.input || '';
138
+ }
139
+ else {
140
+ if (currentToolCall) {
141
+ toolCalls.push(currentToolCall);
142
+ }
143
+ currentToolCall = {
144
+ toolUseId: tc.toolUseId,
145
+ name: tc.name,
146
+ input: tc.input || ''
147
+ };
148
+ }
149
+ if (tc.stop && currentToolCall) {
150
+ toolCalls.push(currentToolCall);
151
+ currentToolCall = null;
152
+ }
153
+ }
154
+ }
155
+ else if (event.type === 'toolUseInput') {
156
+ if (event.data.input) {
157
+ totalContent += event.data.input;
158
+ }
159
+ if (currentToolCall) {
160
+ currentToolCall.input += event.data.input || '';
161
+ }
162
+ }
163
+ else if (event.type === 'toolUseStop') {
164
+ if (currentToolCall && event.data.stop) {
165
+ toolCalls.push(currentToolCall);
166
+ currentToolCall = null;
167
+ }
168
+ }
169
+ }
170
+ }
171
+ if (currentToolCall) {
172
+ toolCalls.push(currentToolCall);
173
+ currentToolCall = null;
174
+ }
175
+ if (thinkingRequested && streamState.buffer) {
176
+ if (streamState.inThinking) {
177
+ yield* createThinkingDeltaEvents(streamState.buffer, streamState);
178
+ streamState.buffer = '';
179
+ yield* createThinkingDeltaEvents('', streamState);
180
+ yield* stopBlock(streamState.thinkingBlockIndex, streamState);
181
+ }
182
+ else if (!streamState.thinkingExtracted) {
183
+ yield* createTextDeltaEvents(streamState.buffer, streamState);
184
+ streamState.buffer = '';
185
+ }
186
+ else {
187
+ yield* createTextDeltaEvents(streamState.buffer, streamState);
188
+ streamState.buffer = '';
189
+ }
190
+ }
191
+ yield* stopBlock(streamState.textBlockIndex, streamState);
192
+ const bracketToolCalls = parseBracketToolCalls(totalContent);
193
+ if (bracketToolCalls.length > 0) {
194
+ for (const btc of bracketToolCalls) {
195
+ toolCalls.push({
196
+ toolUseId: btc.toolUseId,
197
+ name: btc.name,
198
+ input: typeof btc.input === 'string' ? btc.input : JSON.stringify(btc.input)
199
+ });
200
+ }
201
+ }
202
+ if (toolCalls.length > 0) {
203
+ const baseIndex = streamState.nextBlockIndex;
204
+ for (let i = 0; i < toolCalls.length; i++) {
205
+ const tc = toolCalls[i];
206
+ if (!tc)
207
+ continue;
208
+ const blockIndex = baseIndex + i;
209
+ yield {
210
+ type: 'content_block_start',
211
+ index: blockIndex,
212
+ content_block: {
213
+ type: 'tool_use',
214
+ id: tc.toolUseId,
215
+ name: tc.name,
216
+ input: {}
217
+ }
218
+ };
219
+ let inputJson;
220
+ try {
221
+ const parsed = JSON.parse(tc.input);
222
+ inputJson = JSON.stringify(parsed);
223
+ }
224
+ catch (e) {
225
+ inputJson = tc.input;
226
+ }
227
+ yield {
228
+ type: 'content_block_delta',
229
+ index: blockIndex,
230
+ delta: {
231
+ type: 'input_json_delta',
232
+ partial_json: inputJson
233
+ }
234
+ };
235
+ yield { type: 'content_block_stop', index: blockIndex };
236
+ }
237
+ }
238
+ outputTokens = estimateTokens(totalContent);
239
+ if (contextUsagePercentage !== null && contextUsagePercentage > 0) {
240
+ const totalTokens = Math.round(200000 * contextUsagePercentage / 100);
241
+ inputTokens = Math.max(0, totalTokens - outputTokens);
242
+ }
243
+ yield {
244
+ type: 'message_delta',
245
+ delta: { stop_reason: toolCalls.length > 0 ? 'tool_use' : 'end_turn' },
246
+ usage: {
247
+ input_tokens: inputTokens,
248
+ output_tokens: outputTokens,
249
+ cache_creation_input_tokens: 0,
250
+ cache_read_input_tokens: 0
251
+ }
252
+ };
253
+ yield { type: 'message_stop' };
254
+ }
255
+ finally {
256
+ reader.releaseLock();
257
+ }
258
+ }
259
+ function parseStreamBuffer(buffer) {
260
+ const events = [];
261
+ let remaining = buffer;
262
+ let searchStart = 0;
263
+ while (true) {
264
+ const contentStart = remaining.indexOf('{"content":', searchStart);
265
+ const nameStart = remaining.indexOf('{"name":', searchStart);
266
+ const followupStart = remaining.indexOf('{"followupPrompt":', searchStart);
267
+ const inputStart = remaining.indexOf('{"input":', searchStart);
268
+ const stopStart = remaining.indexOf('{"stop":', searchStart);
269
+ const contextUsageStart = remaining.indexOf('{"contextUsagePercentage":', searchStart);
270
+ const candidates = [contentStart, nameStart, followupStart, inputStart, stopStart, contextUsageStart].filter(pos => pos >= 0);
271
+ if (candidates.length === 0)
272
+ break;
273
+ const jsonStart = Math.min(...candidates);
274
+ if (jsonStart < 0)
275
+ break;
276
+ let braceCount = 0;
277
+ let jsonEnd = -1;
278
+ let inString = false;
279
+ let escapeNext = false;
280
+ for (let i = jsonStart; i < remaining.length; i++) {
281
+ const char = remaining[i];
282
+ if (escapeNext) {
283
+ escapeNext = false;
284
+ continue;
285
+ }
286
+ if (char === '\\') {
287
+ escapeNext = true;
288
+ continue;
289
+ }
290
+ if (char === '"') {
291
+ inString = !inString;
292
+ continue;
293
+ }
294
+ if (!inString) {
295
+ if (char === '{') {
296
+ braceCount++;
297
+ }
298
+ else if (char === '}') {
299
+ braceCount--;
300
+ if (braceCount === 0) {
301
+ jsonEnd = i;
302
+ break;
303
+ }
304
+ }
305
+ }
306
+ }
307
+ if (jsonEnd < 0) {
308
+ remaining = remaining.substring(jsonStart);
309
+ break;
310
+ }
311
+ const jsonStr = remaining.substring(jsonStart, jsonEnd + 1);
312
+ const parsed = parseEventLine(jsonStr);
313
+ if (parsed) {
314
+ if (parsed.content !== undefined && !parsed.followupPrompt) {
315
+ events.push({ type: 'content', data: parsed.content });
316
+ }
317
+ else if (parsed.name && parsed.toolUseId) {
318
+ events.push({
319
+ type: 'toolUse',
320
+ data: {
321
+ name: parsed.name,
322
+ toolUseId: parsed.toolUseId,
323
+ input: parsed.input || '',
324
+ stop: parsed.stop || false
325
+ }
326
+ });
327
+ }
328
+ else if (parsed.input !== undefined && !parsed.name) {
329
+ events.push({
330
+ type: 'toolUseInput',
331
+ data: {
332
+ input: parsed.input
333
+ }
334
+ });
335
+ }
336
+ else if (parsed.stop !== undefined && parsed.contextUsagePercentage === undefined) {
337
+ events.push({
338
+ type: 'toolUseStop',
339
+ data: {
340
+ stop: parsed.stop
341
+ }
342
+ });
343
+ }
344
+ else if (parsed.contextUsagePercentage !== undefined) {
345
+ events.push({
346
+ type: 'contextUsage',
347
+ data: {
348
+ contextUsagePercentage: parsed.contextUsagePercentage
349
+ }
350
+ });
351
+ }
352
+ }
353
+ searchStart = jsonEnd + 1;
354
+ if (searchStart >= remaining.length) {
355
+ remaining = '';
356
+ break;
357
+ }
358
+ }
359
+ if (searchStart > 0 && remaining.length > 0) {
360
+ remaining = remaining.substring(searchStart);
361
+ }
362
+ return { events, remaining };
363
+ }
364
+ function ensureBlockStart(blockType, streamState) {
365
+ if (blockType === 'thinking') {
366
+ if (streamState.thinkingBlockIndex != null)
367
+ return [];
368
+ const idx = streamState.nextBlockIndex++;
369
+ streamState.thinkingBlockIndex = idx;
370
+ return [{
371
+ type: 'content_block_start',
372
+ index: idx,
373
+ content_block: { type: 'thinking', thinking: '' }
374
+ }];
375
+ }
376
+ if (blockType === 'text') {
377
+ if (streamState.textBlockIndex != null)
378
+ return [];
379
+ const idx = streamState.nextBlockIndex++;
380
+ streamState.textBlockIndex = idx;
381
+ return [{
382
+ type: 'content_block_start',
383
+ index: idx,
384
+ content_block: { type: 'text', text: '' }
385
+ }];
386
+ }
387
+ return [];
388
+ }
389
+ function stopBlock(index, streamState) {
390
+ if (index == null)
391
+ return [];
392
+ if (streamState.stoppedBlocks.has(index))
393
+ return [];
394
+ streamState.stoppedBlocks.add(index);
395
+ return [{ type: 'content_block_stop', index }];
396
+ }
397
+ function createTextDeltaEvents(text, streamState) {
398
+ if (!text)
399
+ return [];
400
+ const events = [];
401
+ events.push(...ensureBlockStart('text', streamState));
402
+ events.push({
403
+ type: 'content_block_delta',
404
+ index: streamState.textBlockIndex,
405
+ delta: { type: 'text_delta', text }
406
+ });
407
+ return events;
408
+ }
409
+ function createThinkingDeltaEvents(thinking, streamState) {
410
+ const events = [];
411
+ events.push(...ensureBlockStart('thinking', streamState));
412
+ events.push({
413
+ type: 'content_block_delta',
414
+ index: streamState.thinkingBlockIndex,
415
+ delta: { type: 'thinking_delta', thinking }
416
+ });
417
+ return events;
418
+ }
419
+ export function findRealTag(buffer, tag) {
420
+ const codeBlockPattern = /```[\s\S]*?```/g;
421
+ const codeBlocks = [];
422
+ let match;
423
+ while ((match = codeBlockPattern.exec(buffer)) !== null) {
424
+ codeBlocks.push([match.index, match.index + match[0].length]);
425
+ }
426
+ let pos = 0;
427
+ while ((pos = buffer.indexOf(tag, pos)) !== -1) {
428
+ let inCodeBlock = false;
429
+ for (const [start, end] of codeBlocks) {
430
+ if (pos >= start && pos < end) {
431
+ inCodeBlock = true;
432
+ break;
433
+ }
434
+ }
435
+ if (!inCodeBlock) {
436
+ return pos;
437
+ }
438
+ pos += tag.length;
439
+ }
440
+ return -1;
441
+ }
442
+ export function estimateTokens(text) {
443
+ return Math.ceil(text.length / 4);
444
+ }
@@ -0,0 +1,8 @@
1
+ import type { KiroAuthDetails, KiroAuthMethod, KiroRegion } from './types';
2
+ export declare function buildRefreshUrl(region: KiroRegion, authMethod: KiroAuthMethod): string;
3
+ export declare function parseRefreshResponse(response: any, authMethod: KiroAuthMethod): {
4
+ accessToken: string;
5
+ refreshToken: string;
6
+ expiresAt: number;
7
+ };
8
+ export declare function refreshAccessToken(auth: KiroAuthDetails): Promise<KiroAuthDetails>;
@@ -0,0 +1,130 @@
1
+ import { KiroTokenRefreshError } from './errors';
2
+ import { decodeRefreshToken, encodeRefreshToken } from './accounts';
3
+ const SOCIAL_REFRESH_URL_TEMPLATE = 'https://prod.{{region}}.auth.desktop.kiro.dev/refreshToken';
4
+ const IDC_REFRESH_URL_TEMPLATE = 'https://oidc.{{region}}.amazonaws.com/token';
5
+ export function buildRefreshUrl(region, authMethod) {
6
+ const template = authMethod === 'social' ? SOCIAL_REFRESH_URL_TEMPLATE : IDC_REFRESH_URL_TEMPLATE;
7
+ return template.replace('{{region}}', region);
8
+ }
9
+ export function parseRefreshResponse(response, authMethod) {
10
+ if (authMethod === 'social') {
11
+ if (!response.accessToken) {
12
+ throw new KiroTokenRefreshError('Invalid refresh response: Missing accessToken');
13
+ }
14
+ const expiresIn = response.expiresIn || 3600;
15
+ const expiresAt = Date.now() + (expiresIn * 1000);
16
+ return {
17
+ accessToken: response.accessToken,
18
+ refreshToken: response.refreshToken,
19
+ expiresAt,
20
+ };
21
+ }
22
+ else {
23
+ if (!response.accessToken && !response.access_token) {
24
+ throw new KiroTokenRefreshError('Invalid refresh response: Missing access_token');
25
+ }
26
+ const accessToken = response.accessToken || response.access_token;
27
+ const refreshToken = response.refreshToken || response.refresh_token;
28
+ const expiresIn = response.expiresIn || response.expires_in || 3600;
29
+ const expiresAt = Date.now() + (expiresIn * 1000);
30
+ return {
31
+ accessToken,
32
+ refreshToken,
33
+ expiresAt,
34
+ };
35
+ }
36
+ }
37
+ async function refreshSocialToken(refreshUrl, refreshToken) {
38
+ const response = await fetch(refreshUrl, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ },
43
+ body: JSON.stringify({
44
+ refreshToken,
45
+ }),
46
+ });
47
+ if (!response.ok) {
48
+ const errorText = await response.text().catch(() => 'Unknown error');
49
+ let errorData = {};
50
+ try {
51
+ errorData = JSON.parse(errorText);
52
+ }
53
+ catch {
54
+ errorData = { message: errorText };
55
+ }
56
+ const errorCode = errorData.error || errorData.code || `HTTP_${response.status}`;
57
+ const errorMessage = errorData.message || errorData.error_description || errorText;
58
+ throw new KiroTokenRefreshError(`Social token refresh failed: ${errorMessage}`, errorCode, new Error(errorText));
59
+ }
60
+ return response.json();
61
+ }
62
+ async function refreshIdcToken(refreshUrl, refreshToken, clientId, clientSecret) {
63
+ const params = new URLSearchParams();
64
+ params.append('grant_type', 'refresh_token');
65
+ params.append('refresh_token', refreshToken);
66
+ params.append('client_id', clientId);
67
+ params.append('client_secret', clientSecret);
68
+ const response = await fetch(refreshUrl, {
69
+ method: 'POST',
70
+ headers: {
71
+ 'Content-Type': 'application/x-www-form-urlencoded',
72
+ },
73
+ body: params.toString(),
74
+ });
75
+ if (!response.ok) {
76
+ const errorText = await response.text().catch(() => 'Unknown error');
77
+ let errorData = {};
78
+ try {
79
+ errorData = JSON.parse(errorText);
80
+ }
81
+ catch {
82
+ errorData = { message: errorText };
83
+ }
84
+ const errorCode = errorData.error || errorData.code || `HTTP_${response.status}`;
85
+ const errorMessage = errorData.message || errorData.error_description || errorText;
86
+ throw new KiroTokenRefreshError(`IDC token refresh failed: ${errorMessage}`, errorCode, new Error(errorText));
87
+ }
88
+ return response.json();
89
+ }
90
+ export async function refreshAccessToken(auth) {
91
+ const refreshUrl = buildRefreshUrl(auth.region, auth.authMethod);
92
+ const parts = decodeRefreshToken(auth.refresh);
93
+ try {
94
+ let responseData;
95
+ if (auth.authMethod === 'social') {
96
+ responseData = await refreshSocialToken(refreshUrl, parts.refreshToken);
97
+ }
98
+ else {
99
+ if (!parts.clientId || !parts.clientSecret) {
100
+ throw new KiroTokenRefreshError('IDC token refresh requires clientId and clientSecret', 'MISSING_CREDENTIALS');
101
+ }
102
+ responseData = await refreshIdcToken(refreshUrl, parts.refreshToken, parts.clientId, parts.clientSecret);
103
+ }
104
+ const parsed = parseRefreshResponse(responseData, auth.authMethod);
105
+ const updatedParts = {
106
+ refreshToken: parsed.refreshToken || parts.refreshToken,
107
+ profileArn: responseData.profileArn || parts.profileArn,
108
+ clientId: parts.clientId,
109
+ clientSecret: parts.clientSecret,
110
+ authMethod: auth.authMethod,
111
+ };
112
+ return {
113
+ refresh: encodeRefreshToken(updatedParts),
114
+ access: parsed.accessToken,
115
+ expires: parsed.expiresAt,
116
+ authMethod: auth.authMethod,
117
+ region: auth.region,
118
+ profileArn: responseData.profileArn || auth.profileArn,
119
+ clientId: auth.clientId,
120
+ clientSecret: auth.clientSecret,
121
+ email: auth.email,
122
+ };
123
+ }
124
+ catch (error) {
125
+ if (error instanceof KiroTokenRefreshError) {
126
+ throw error;
127
+ }
128
+ throw new KiroTokenRefreshError(`Token refresh failed: ${error instanceof Error ? error.message : String(error)}`, 'UNKNOWN_ERROR', error instanceof Error ? error : undefined);
129
+ }
130
+ }