@cartanova/qgrid-cli 2.2.0 → 2.3.1

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 (35) hide show
  1. package/bundle/dist/application/qgrid/conv-routing.js +2 -6
  2. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +64 -37
  3. package/bundle/dist/application/qgrid/token-subscriber.js +14 -1
  4. package/bundle/dist/application/qgrid/tool-emulation.js +25 -20
  5. package/bundle/dist/application/request-log/request-log.model.js +54 -8
  6. package/bundle/dist/sonamu.config.js +11 -2
  7. package/bundle/dist/testing/global.js +5 -2
  8. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +30 -0
  9. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +215 -0
  10. package/bundle/dist/utils/providers/anthropic/claude-session.js +220 -0
  11. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +177 -0
  12. package/bundle/dist/utils/providers/common/model-cost.js +64 -32
  13. package/bundle/dist/utils/providers/openai/openai-refresh.js +21 -9
  14. package/bundle/src/application/qgrid/conv-routing.test.ts +85 -0
  15. package/bundle/src/application/qgrid/conv-routing.ts +3 -2
  16. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +37 -0
  17. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +99 -44
  18. package/bundle/src/application/qgrid/token-subscriber.ts +23 -1
  19. package/bundle/src/application/qgrid/tool-emulation.test.ts +46 -0
  20. package/bundle/src/application/qgrid/tool-emulation.ts +15 -3
  21. package/bundle/src/application/request-log/request-log.model.ts +98 -13
  22. package/bundle/src/sonamu.config.ts +13 -2
  23. package/bundle/src/testing/global.ts +16 -2
  24. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +38 -0
  25. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +564 -0
  26. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +365 -0
  27. package/bundle/src/utils/providers/anthropic/claude-session.test.ts +263 -0
  28. package/bundle/src/utils/providers/anthropic/claude-session.ts +327 -0
  29. package/bundle/src/utils/providers/anthropic/stream-json-adapter.test.ts +373 -0
  30. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +344 -0
  31. package/bundle/src/utils/providers/common/model-cost.test.ts +39 -0
  32. package/bundle/src/utils/providers/common/model-cost.ts +159 -25
  33. package/bundle/src/utils/providers/common/provider-dispatcher.ts +13 -2
  34. package/bundle/src/utils/providers/openai/openai-refresh.ts +34 -9
  35. package/package.json +1 -1
@@ -27,6 +27,7 @@ interface RefreshResult {
27
27
  }
28
28
 
29
29
  export async function handleChatgptAuthTokensRefresh(tokenId: number): Promise<RefreshResult> {
30
+ logger.info(`refresh requested for token ${tokenId} (pid=${process.pid})`);
30
31
  const existing = inflightRefresh.get(tokenId);
31
32
  if (existing) {
32
33
  logger.info(`refresh dedup for token ${tokenId}`);
@@ -86,6 +87,19 @@ async function doRefresh(tokenId: number): Promise<RefreshResult> {
86
87
 
87
88
  if (!resp.ok) {
88
89
  const body = await resp.text().catch(() => "");
90
+ // 401 본문의 error 코드가 토큰 사망의 결정적 사인이다.
91
+ // refresh_token_expired → refresh_token 자체 만료
92
+ // refresh_token_reused → 이미 사용된(회전 폐기된) refresh_token 재사용 → 패밀리 무효화
93
+ // refresh_token_invalidated → 서버측 revoke
94
+ // 위 3개는 모두 영구 실패. 재등록 외 복구 불가.
95
+ let errorCode: string | undefined;
96
+ try {
97
+ errorCode = (JSON.parse(body) as { error?: string }).error;
98
+ } catch {}
99
+ logger.error(
100
+ `OpenAI refresh FAILED token=${token.name}(id=${tokenId}) status=${resp.status} ` +
101
+ `code=${errorCode ?? "?"} body=${body}`,
102
+ );
89
103
  throw new Error(`OpenAI refresh failed: ${resp.status} ${body}`);
90
104
  }
91
105
 
@@ -115,16 +129,27 @@ async function doRefresh(tokenId: number): Promise<RefreshResult> {
115
129
  ...(data.id_token ? { idToken: data.id_token } : {}),
116
130
  };
117
131
 
118
- await TokenModel.save([
119
- {
120
- id: tokenId,
121
- provider: "openai",
122
- credentials: updatedCreds,
123
- name: token.name,
124
- },
125
- ]);
132
+ // 회전(rotated)이 일어났는데 이 save 가 실패하면, OpenAI 쪽 옛 refresh_token 은 이미
133
+ // 폐기된 상태에서 DB 에는 옛 토큰이 남는다 → 다음 refresh 가 refresh_token_reused 로
134
+ // 영구 사망. 이 구간 실패는 토큰 사망의 직접 원인이므로 반드시 크게 남긴다.
135
+ try {
136
+ await TokenModel.save([
137
+ {
138
+ id: tokenId,
139
+ provider: "openai",
140
+ credentials: updatedCreds,
141
+ name: token.name,
142
+ },
143
+ ]);
144
+ } catch (e) {
145
+ logger.error(
146
+ `OpenAI refresh: DB save FAILED after rotation(rotated=${rotated}) ` +
147
+ `token=${token.name}(id=${tokenId}) — 옛 refresh_token 폐기됨, DB 미반영 → 토큰 사망 위험. err=${String(e)}`,
148
+ );
149
+ throw e;
150
+ }
126
151
 
127
- logger.info(`token ${token.name} refreshed successfully`);
152
+ logger.info(`token ${token.name} refreshed successfully (rotated=${rotated})`);
128
153
 
129
154
  return {
130
155
  accessToken: data.access_token,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"