w-dispatch-ai 1.0.21 → 1.0.23
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/README.md +627 -569
- package/dist/w-dispatch-ai.umd.js +2 -2
- package/dist/w-dispatch-ai.umd.js.map +1 -1
- package/docs/WDispatchAi.mjs.html +12 -4
- package/docs/adapters.mjs.html +5 -3
- package/docs/budgetFor.mjs.html +2 -2
- package/docs/buildValidator.mjs.html +166 -0
- package/docs/castPintOr.mjs.html +2 -2
- package/docs/dfTimeoutMs.mjs.html +2 -2
- package/docs/dispatchAi.mjs.html +2 -2
- package/docs/dispatchAiFallback.mjs.html +2 -2
- package/docs/dispatchAiWkf.mjs.html +2 -2
- package/docs/dispatchAntigravity.mjs.html +2 -2
- package/docs/dispatchApiOpenaiCompat.mjs.html +4 -68
- package/docs/dispatchApiOpenaiResponses.mjs.html +498 -0
- package/docs/dispatchClaude.mjs.html +2 -2
- package/docs/dispatchCodex.mjs.html +2 -2
- package/docs/dispatchOpencode.mjs.html +2 -2
- package/docs/getCliArgs.mjs.html +2 -2
- package/docs/getErrorResult.mjs.html +2 -2
- package/docs/getErrorType.mjs.html +5 -3
- package/docs/global.html +11790 -3425
- package/docs/index.html +2 -2
- package/docs/quota_dfQuotaTimeoutMs.mjs.html +99 -0
- package/docs/quota_fetchQuotaJson.mjs.html +348 -0
- package/docs/quota_fromCodexUsageHttp.mjs.html +335 -0
- package/docs/quota_getQuotaAntigravity.mjs.html +463 -0
- package/docs/quota_getQuotaClaude.mjs.html +457 -0
- package/docs/quota_getQuotaCodex.mjs.html +515 -0
- package/docs/quota_readJsonOrNull.mjs.html +113 -0
- package/docs/quota_toQuotaLabel.mjs.html +146 -0
- package/docs/quota_toQuotaResult.mjs.html +214 -0
- package/docs/quota_toQuotaScopedLabel.mjs.html +117 -0
- package/docs/quota_toQuotaWindow.mjs.html +239 -0
- package/docs/readEnvFile.mjs.html +2 -2
- package/docs/resolveProviders.mjs.html +3 -3
- package/docs/wkf_callAiWithFallback.mjs.html +2 -2
- package/docs/wkf_createFileStore.mjs.html +2 -2
- package/docs/wkf_createUsageCounter.mjs.html +2 -2
- package/docs/wkf_extractJsonLoose.mjs.html +2 -2
- package/docs/wkf_noSideEffectPrefix.mjs.html +2 -2
- package/docs/wkf_runFanout.mjs.html +2 -2
- package/docs/wkf_runFanoutPipeline.mjs.html +2 -2
- package/docs/wkf_runRolePipeline.mjs.html +2 -2
- package/docs/wkf_salvageTruncatedArray.mjs.html +2 -2
- package/g.mjs +2 -2
- package/package.json +2 -2
- package/src/WDispatchAi.mjs +10 -2
- package/src/adapters.mjs +3 -1
- package/src/buildValidator.mjs +94 -0
- package/src/dispatchApiOpenaiCompat.mjs +2 -66
- package/src/dispatchApiOpenaiResponses.mjs +426 -0
- package/src/getErrorType.mjs +3 -1
- package/src/providers.mjs +303 -213
- package/src/quota/dfQuotaTimeoutMs.mjs +27 -0
- package/src/quota/fetchQuotaJson.mjs +276 -0
- package/src/quota/fromCodexUsageHttp.mjs +263 -0
- package/src/quota/getQuotaAntigravity.mjs +391 -0
- package/src/quota/getQuotaClaude.mjs +385 -0
- package/src/quota/getQuotaCodex.mjs +443 -0
- package/src/quota/readJsonOrNull.mjs +41 -0
- package/src/quota/toQuotaLabel.mjs +74 -0
- package/src/quota/toQuotaResult.mjs +142 -0
- package/src/quota/toQuotaScopedLabel.mjs +45 -0
- package/src/quota/toQuotaWindow.mjs +167 -0
- package/src/resolveProviders.mjs +1 -1
- package/test/tools/fakeCliForTest.mjs +4 -3
- package/test/tools/fakeServerForApiTest.mjs +108 -3
- package/test/tools/fakeServerForQuotaTest.mjs +171 -0
- package/test/unit-WDispatchAi.test.mjs +19 -6
- package/test/unit-adapters.test.mjs +5 -3
- package/test/unit-dispatchAi.test.mjs +1 -1
- package/test/unit-dispatchApiOpenaiResponses.test.mjs +198 -0
- package/test/unit-fetchQuotaJson.test.mjs +70 -0
- package/test/unit-fromCodexUsageHttp.test.mjs +76 -0
- package/test/unit-getQuotaAntigravity.test.mjs +123 -0
- package/test/unit-getQuotaClaude.test.mjs +137 -0
- package/test/unit-getQuotaCodex.test.mjs +191 -0
- package/test/unit-readJsonOrNull.test.mjs +44 -0
- package/test/unit-toQuotaLabel.test.mjs +43 -0
- package/test/unit-toQuotaResult.test.mjs +53 -0
- package/test/unit-toQuotaWindow.test.mjs +73 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>quota/fromCodexUsageHttp.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">quota/fromCodexUsageHttp.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
|
|
49
|
+
import isestr from 'wsemi/src/isestr.mjs'
|
|
50
|
+
import isearr from 'wsemi/src/isearr.mjs'
|
|
51
|
+
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
52
|
+
import isnum from 'wsemi/src/isnum.mjs'
|
|
53
|
+
import cdbl from 'wsemi/src/cdbl.mjs'
|
|
54
|
+
import toQuotaScopedLabel from './toQuotaScopedLabel.mjs'
|
|
55
|
+
import toQuotaWindow from './toQuotaWindow.mjs'
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
// fromCodexUsageHttp.mjs — 將chatgpt.com之/wham/usage回應對映為統一結構
|
|
59
|
+
//
|
|
60
|
+
// 【為何獨立成檔】此端點為ChatGPT前端自用之內部端點, 欄位形狀已知會變(尤其additional_rate_limits),
|
|
61
|
+
// 對映邏輯獨立後可用離線fixture斷言, 不必每次都靠真帳號才能驗證。
|
|
62
|
+
//
|
|
63
|
+
// 【additional_rate_limits之寬容解析】本機帳號此欄實測為null, 形狀取自同類工具codex-reset-checker
|
|
64
|
+
// 之測試fixture(其作者觀察到的真實回應): 集合可為陣列或以名稱為鍵之物件; 單筆之識別可為
|
|
65
|
+
// limit_name / metered_limit_name / name / id; 顯示名可為display_name / title; 窗口可在單筆頂層、
|
|
66
|
+
// rate_limit之下(snake或camel), 或單筆本身就是一個窗口(直接帶used_percent, 或置於window鍵);
|
|
67
|
+
// 直接窗口不分primary/secondary時, 以名稱含weekly/secondary/reserve或窗口長度≥6天判為週限額。
|
|
68
|
+
// 已知名稱: codex-spark(GPT-5.3-Codex-Spark)、gpt-reserve(Luna reserve之週限額)。
|
|
69
|
+
// 任何欄位缺漏皆「該窗口不列入」而不拋錯, 原始回應由呼叫端保留於raw。
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
//直接窗口判為週限額之窗口長度門檻(秒)
|
|
73
|
+
let SEC_WEEKLY_MIN = 6 * 86400
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 取第一個為非空字串之鍵值
|
|
78
|
+
*
|
|
79
|
+
* @param {Object} o 輸入物件
|
|
80
|
+
* @param {Array} keys 輸入鍵陣列
|
|
81
|
+
* @returns {String} 回傳字串, 皆無回傳''
|
|
82
|
+
*/
|
|
83
|
+
function firstStr(o, keys) {
|
|
84
|
+
for (let k of keys) {
|
|
85
|
+
let v = get(o, k, '')
|
|
86
|
+
if (isestr(v)) {
|
|
87
|
+
return v
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return ''
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 將單一窗口{used_percent, limit_window_seconds, reset_at, reset_after_seconds}正規化
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} o 輸入窗口物件
|
|
98
|
+
* @param {String} key 輸入窗口鍵字串
|
|
99
|
+
* @param {String} scope 輸入範圍字串
|
|
100
|
+
* @returns {Object|null} 回傳統一窗口物件, 輸入非物件回傳null
|
|
101
|
+
*/
|
|
102
|
+
function fromWindow(o, key, scope) {
|
|
103
|
+
if (!iseobj(o)) {
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
let ws = get(o, 'limit_window_seconds', null)
|
|
107
|
+
let windowSeconds = isnum(ws) ? cdbl(ws) : null
|
|
108
|
+
return toQuotaWindow({
|
|
109
|
+
key,
|
|
110
|
+
label: toQuotaScopedLabel(windowSeconds, scope),
|
|
111
|
+
windowSeconds,
|
|
112
|
+
usedPercent: get(o, 'used_percent', null),
|
|
113
|
+
resetAt: get(o, 'reset_at', ''),
|
|
114
|
+
resetAfterSeconds: get(o, 'reset_after_seconds', null),
|
|
115
|
+
scope,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 取出additional_rate_limits之集合並統一為陣列
|
|
122
|
+
*
|
|
123
|
+
* @param {Object} data 輸入回應物件
|
|
124
|
+
* @returns {Array} 回傳單筆物件陣列, 無則[]
|
|
125
|
+
*/
|
|
126
|
+
function collectAdditional(data) {
|
|
127
|
+
let cands = [
|
|
128
|
+
get(data, 'additional_rate_limits', null),
|
|
129
|
+
get(data, 'rate_limit.additional_rate_limits', null),
|
|
130
|
+
]
|
|
131
|
+
for (let c of cands) {
|
|
132
|
+
if (isearr(c)) {
|
|
133
|
+
return c
|
|
134
|
+
}
|
|
135
|
+
if (iseobj(c)) {
|
|
136
|
+
return Object.keys(c).map((k) => {
|
|
137
|
+
let v = c[k]
|
|
138
|
+
if (!iseobj(v)) {
|
|
139
|
+
return v
|
|
140
|
+
}
|
|
141
|
+
let nm = firstStr(v, ['limit_name', 'name', 'id'])
|
|
142
|
+
return { ...v, limit_name: nm === '' ? k : nm }
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return []
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 自單筆取出指定窗口(頂層、rate_limit、rateLimit之下, snake或camel)
|
|
152
|
+
*
|
|
153
|
+
* @param {Object} it 輸入單筆物件
|
|
154
|
+
* @param {String} snake 輸入snake鍵, 例如'primary_window'
|
|
155
|
+
* @param {String} camel 輸入camel鍵, 例如'primaryWindow'
|
|
156
|
+
* @returns {Object|null} 回傳窗口物件, 無回傳null
|
|
157
|
+
*/
|
|
158
|
+
function pickWindow(it, snake, camel) {
|
|
159
|
+
for (let c of [it, get(it, 'rate_limit', null), get(it, 'rateLimit', null)]) {
|
|
160
|
+
if (!iseobj(c)) {
|
|
161
|
+
continue
|
|
162
|
+
}
|
|
163
|
+
let w = get(c, snake, null)
|
|
164
|
+
if (!iseobj(w)) {
|
|
165
|
+
w = get(c, camel, null)
|
|
166
|
+
}
|
|
167
|
+
if (iseobj(w)) {
|
|
168
|
+
return w
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return null
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 單筆本身即為窗口時取出之
|
|
177
|
+
*
|
|
178
|
+
* @param {Object} it 輸入單筆物件
|
|
179
|
+
* @returns {Object|null} 回傳窗口物件, 無回傳null
|
|
180
|
+
*/
|
|
181
|
+
function directWindow(it) {
|
|
182
|
+
if (!iseobj(it)) {
|
|
183
|
+
return null
|
|
184
|
+
}
|
|
185
|
+
if (get(it, 'used_percent', undefined) !== undefined) {
|
|
186
|
+
return it
|
|
187
|
+
}
|
|
188
|
+
let w = get(it, 'window', null)
|
|
189
|
+
if (iseobj(w)) {
|
|
190
|
+
return w
|
|
191
|
+
}
|
|
192
|
+
let rl = get(it, 'rate_limit', null)
|
|
193
|
+
if (iseobj(rl) && get(rl, 'used_percent', undefined) !== undefined) {
|
|
194
|
+
return rl
|
|
195
|
+
}
|
|
196
|
+
return null
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* 將chatgpt.com之/wham/usage回應對映為統一結構
|
|
202
|
+
*
|
|
203
|
+
* 主窗口(rate_limit.primary_window / secondary_window)、程式碼審查限額(code_review_rate_limit)、
|
|
204
|
+
* 以及寬容解析之additional_rate_limits皆納入windows;額外限額之窗口鍵為「<識別>:primary|secondary」,
|
|
205
|
+
* scope為其顯示名或識別。任何欄位缺漏皆略過該窗口而不拋錯
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} data 輸入/wham/usage之回應物件
|
|
208
|
+
* @returns {Object} 回傳物件,內含email(字串,無則'')、plan(字串,無則'')、windows(統一窗口陣列)、credits(點數與重置券資訊物件)
|
|
209
|
+
* @example
|
|
210
|
+
*
|
|
211
|
+
* import fromCodexUsageHttp from './src/quota/fromCodexUsageHttp.mjs'
|
|
212
|
+
*
|
|
213
|
+
* let m = fromCodexUsageHttp({
|
|
214
|
+
* email: 'a@b.c',
|
|
215
|
+
* plan_type: 'plus',
|
|
216
|
+
* rate_limit: { primary_window: { used_percent: 42, limit_window_seconds: 18000, reset_after_seconds: 100 } },
|
|
217
|
+
* additional_rate_limits: [{ limit_name: 'codex-spark', primary_window: { used_percent: 12, limit_window_seconds: 18000 } }],
|
|
218
|
+
* })
|
|
219
|
+
* console.log(m.windows.map((w) => `${w.key}=${w.label}`))
|
|
220
|
+
* // => [ 'primary=5小時', 'codex-spark:primary=5小時(codex-spark)' ]
|
|
221
|
+
*
|
|
222
|
+
*/
|
|
223
|
+
function fromCodexUsageHttp(data) {
|
|
224
|
+
|
|
225
|
+
//email與plan
|
|
226
|
+
let email = firstStr(data, ['email'])
|
|
227
|
+
let plan = firstStr(data, ['plan_type'])
|
|
228
|
+
|
|
229
|
+
//windows, 主窗口
|
|
230
|
+
let windows = []
|
|
231
|
+
for (let k of ['primary', 'secondary']) {
|
|
232
|
+
let w = fromWindow(get(data, `rate_limit.${k}_window`, null), k, '')
|
|
233
|
+
if (w !== null) {
|
|
234
|
+
windows.push(w)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//code review限額, 與對話額度分開計算
|
|
239
|
+
for (let k of ['primary', 'secondary']) {
|
|
240
|
+
let w = fromWindow(get(data, `code_review_rate_limit.${k}_window`, null), `code_review:${k}`, 'code review')
|
|
241
|
+
if (w !== null) {
|
|
242
|
+
windows.push(w)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//additional_rate_limits, 寬容解析
|
|
247
|
+
let addi = collectAdditional(data)
|
|
248
|
+
for (let i = 0; i < addi.length; i++) {
|
|
249
|
+
let it = addi[i]
|
|
250
|
+
if (!iseobj(it)) {
|
|
251
|
+
continue
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//id與scope
|
|
255
|
+
let id = firstStr(it, ['limit_name', 'metered_limit_name', 'name', 'id'])
|
|
256
|
+
if (id === '') {
|
|
257
|
+
id = `additional_${i + 1}`
|
|
258
|
+
}
|
|
259
|
+
let display = firstStr(it, ['display_name', 'title', 'name', 'limit_name', 'metered_limit_name'])
|
|
260
|
+
let scope = display === '' ? id : display
|
|
261
|
+
let identity = `${id} ${display}`.toLowerCase()
|
|
262
|
+
|
|
263
|
+
//窗口, 先找明確之primary/secondary, 皆無時把單筆本身當窗口並以名稱或長度判別週限額
|
|
264
|
+
let pri = pickWindow(it, 'primary_window', 'primaryWindow')
|
|
265
|
+
let sec = pickWindow(it, 'secondary_window', 'secondaryWindow')
|
|
266
|
+
if (pri === null && sec === null) {
|
|
267
|
+
let d = directWindow(it)
|
|
268
|
+
if (d !== null) {
|
|
269
|
+
let ws = get(d, 'limit_window_seconds', null)
|
|
270
|
+
let weekly = /weekly|secondary|reserve/.test(identity) || (isnum(ws) && cdbl(ws) >= SEC_WEEKLY_MIN)
|
|
271
|
+
if (weekly) {
|
|
272
|
+
sec = d
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
pri = d
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let wp = fromWindow(pri, `${id}:primary`, scope)
|
|
281
|
+
if (wp !== null) {
|
|
282
|
+
windows.push(wp)
|
|
283
|
+
}
|
|
284
|
+
let ws2 = fromWindow(sec, `${id}:secondary`, scope)
|
|
285
|
+
if (ws2 !== null) {
|
|
286
|
+
windows.push(ws2)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//credits, 點數餘額與「額度重置券」(可提前重置窗口)與限額狀態
|
|
291
|
+
let credits = {
|
|
292
|
+
hasCredits: get(data, 'credits.has_credits', false),
|
|
293
|
+
unlimited: get(data, 'credits.unlimited', false),
|
|
294
|
+
balance: get(data, 'credits.balance', ''),
|
|
295
|
+
resetCreditsAvailable: get(data, 'rate_limit_reset_credits.available_count', null),
|
|
296
|
+
spendControlReached: get(data, 'spend_control.reached', false),
|
|
297
|
+
rateLimitReachedType: get(data, 'rate_limit_reached_type', null),
|
|
298
|
+
individualLimit: get(data, 'spend_control.individual_limit', null),
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
email,
|
|
303
|
+
plan,
|
|
304
|
+
windows,
|
|
305
|
+
credits,
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
export default fromCodexUsageHttp
|
|
311
|
+
</code></pre>
|
|
312
|
+
</article>
|
|
313
|
+
</section>
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
</div>
|
|
321
|
+
|
|
322
|
+
<br class="clear">
|
|
323
|
+
|
|
324
|
+
<footer>
|
|
325
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sat Sep 05 2026 22:03:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
326
|
+
</footer>
|
|
327
|
+
|
|
328
|
+
<script>prettyPrint();</script>
|
|
329
|
+
<script src="scripts/polyfill.js"></script>
|
|
330
|
+
<script src="scripts/linenumber.js"></script>
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
</body>
|
|
335
|
+
</html>
|