@coseung2/opencodex 2.8.0-cs.12 → 2.8.0-cs.14

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 (62) hide show
  1. package/gui/dist/assets/index-MUpaVatk.js +67 -0
  2. package/gui/dist/index.html +1 -1
  3. package/package.json +3 -3
  4. package/packages/ocx-notch/README.md +3 -2
  5. package/src/adapters/cursor/discovery.ts +6 -2
  6. package/src/adapters/cursor/effort-map.ts +3 -0
  7. package/src/adapters/google-antigravity-replay.ts +24 -0
  8. package/src/adapters/google.ts +16 -11
  9. package/src/chat/inbound.ts +5 -11
  10. package/src/cli/account-api.ts +9 -1
  11. package/src/cli/account-extended.ts +4 -1
  12. package/src/codex/account-label.ts +14 -1
  13. package/src/codex/account-lifecycle.ts +12 -1
  14. package/src/codex/account-namespaces.ts +21 -0
  15. package/src/codex/account-priority.ts +49 -0
  16. package/src/codex/account-store.ts +73 -10
  17. package/src/codex/auth-api.ts +312 -45
  18. package/src/codex/auth-context.ts +61 -16
  19. package/src/codex/catalog/metadata.ts +34 -12
  20. package/src/codex/catalog/parsing.ts +8 -1
  21. package/src/codex/catalog/provider-fetch.ts +24 -6
  22. package/src/codex/catalog.ts +1 -1
  23. package/src/codex/pool-rotation.ts +51 -4
  24. package/src/codex/quota.ts +154 -35
  25. package/src/codex/routing.ts +133 -33
  26. package/src/codex/warmup.ts +204 -82
  27. package/src/config.ts +84 -1
  28. package/src/lib/bounded-body.ts +13 -6
  29. package/src/lib/bun-stream-caps.ts +5 -6
  30. package/src/lib/redact.ts +13 -0
  31. package/src/oauth/index.ts +79 -12
  32. package/src/oauth/log.ts +3 -1
  33. package/src/oauth/store.ts +31 -8
  34. package/src/oauth/token-guardian.ts +130 -9
  35. package/src/providers/antigravity-models.ts +53 -24
  36. package/src/providers/codex-capacity.ts +303 -0
  37. package/src/providers/model-rename-migration.ts +147 -0
  38. package/src/providers/model-rename-startup.ts +29 -0
  39. package/src/providers/quota.ts +126 -16
  40. package/src/providers/registry.ts +262 -38
  41. package/src/responses/parser.ts +19 -12
  42. package/src/responses/spill-store.ts +14 -1
  43. package/src/responses/state.ts +108 -14
  44. package/src/router.ts +6 -0
  45. package/src/server/index.ts +9 -1
  46. package/src/server/management/logs-usage-routes.ts +1 -0
  47. package/src/server/management/oauth-account-routes.ts +8 -1
  48. package/src/server/relay.ts +10 -42
  49. package/src/server/request-log.ts +42 -1
  50. package/src/server/responses/compact.ts +16 -4
  51. package/src/server/responses/core.ts +217 -59
  52. package/src/server/responses/empty-completion-guard.ts +275 -0
  53. package/src/server/responses/encrypted-payload.ts +54 -39
  54. package/src/server/responses/fetch-helpers.ts +24 -3
  55. package/src/server/responses/ws-upstream.ts +318 -0
  56. package/src/server/sse-frame-buffer.ts +292 -0
  57. package/src/server/ws-bridge.ts +17 -11
  58. package/src/types.ts +13 -1
  59. package/src/usage/log.ts +24 -0
  60. package/src/usage/summary.ts +152 -2
  61. package/vendor/ocx-notch/win32-x64/ocx-notch.exe +0 -0
  62. package/gui/dist/assets/index-GgF1IpQa.js +0 -67
@@ -4,7 +4,9 @@ import { atomicWriteFile, getConfigDir } from "../config";
4
4
  import { captureConfigGeneration, type GenerationContext } from "../lib/state-store-sweeper";
5
5
 
6
6
  export type StoredAccountQuota = {
7
+ fiveHourPercent?: number;
7
8
  weeklyPercent?: number;
9
+ fiveHourResetAt?: number;
8
10
  monthlyPercent?: number;
9
11
  weeklyResetAt?: number;
10
12
  monthlyResetAt?: number;
@@ -41,13 +43,15 @@ export type WhamUsageResponse = {
41
43
  };
42
44
 
43
45
  type WhamUsageWindow = {
44
- used_percent?: number;
45
- reset_at?: number;
46
- limit_window_seconds?: number;
46
+ used_percent?: number | string | null;
47
+ reset_at?: number | string | null;
48
+ limit_window_seconds?: number | string | null;
47
49
  };
48
50
 
49
51
  const MONTHLY_WINDOW_MIN_SECONDS = 28 * 24 * 60 * 60;
50
52
  const MONTHLY_WINDOW_MIN_MINUTES = MONTHLY_WINDOW_MIN_SECONDS / 60;
53
+ const FIVE_HOUR_WINDOW_MIN_SECONDS = 2 * 60 * 60;
54
+ const FIVE_HOUR_WINDOW_MAX_SECONDS = 12 * 60 * 60;
51
55
 
52
56
  const accountQuota = new Map<string, StoredAccountQuota>();
53
57
  let lastReconciledGeneration = 0;
@@ -62,15 +66,26 @@ function mayCommitAccountQuota(accountId: string, writerGeneration: number): boo
62
66
  export const CODEX_UNKNOWN_USAGE_SCORE = 101;
63
67
  export const CODEX_EXHAUSTED_USAGE_PERCENT = 100;
64
68
 
69
+ /** Plans whose WHAM payloads expose a separate rolling five-hour window. */
70
+ export function isCodexFiveHourQuotaPlan(plan: string | null | undefined): boolean {
71
+ const normalized = plan?.trim().toLowerCase();
72
+ // Business is the current name for the older Team workspace plan.
73
+ return normalized === "plus" || normalized === "team" || normalized === "business";
74
+ }
75
+
65
76
  export function isCodexQuotaExhausted(
66
- quota: Pick<StoredAccountQuota, "weeklyPercent" | "monthlyPercent"> | null,
77
+ quota: Pick<StoredAccountQuota, "fiveHourPercent" | "weeklyPercent" | "monthlyPercent"> | null,
67
78
  plan?: string | null,
68
79
  ): boolean {
69
80
  if (!quota) return false;
70
81
  const normalizedPlan = plan?.trim().toLowerCase();
71
82
  const values = normalizedPlan === "go" || normalizedPlan === "free"
72
83
  ? [quota.monthlyPercent]
73
- : [quota.weeklyPercent, quota.monthlyPercent];
84
+ : [
85
+ ...(isCodexFiveHourQuotaPlan(plan) ? [quota.fiveHourPercent] : []),
86
+ quota.weeklyPercent,
87
+ quota.monthlyPercent,
88
+ ];
74
89
  return values.some(value => typeof value === "number"
75
90
  && Number.isFinite(value)
76
91
  && value >= CODEX_EXHAUSTED_USAGE_PERCENT);
@@ -97,15 +112,23 @@ function normalizeResetAt(value: unknown): number | undefined {
97
112
  }
98
113
 
99
114
  function hasKnownQuotaValue(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
100
- return [quota.weeklyPercent, quota.monthlyPercent]
115
+ return [quota.fiveHourPercent, quota.weeklyPercent, quota.monthlyPercent]
101
116
  .some(value => typeof value === "number" && Number.isFinite(value));
102
117
  }
103
118
 
119
+ function windowDurationSeconds(window: WhamUsageWindow | null | undefined): number | undefined {
120
+ const raw: unknown = window?.limit_window_seconds;
121
+ const seconds = typeof raw === "number"
122
+ ? raw
123
+ : typeof raw === "string" && raw.trim() !== ""
124
+ ? Number(raw)
125
+ : undefined;
126
+ return typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0 ? seconds : undefined;
127
+ }
128
+
104
129
  function isExplicitMonthlyWindow(window: WhamUsageWindow | null | undefined): boolean {
105
- const seconds = window?.limit_window_seconds;
106
- return typeof seconds === "number"
107
- && Number.isFinite(seconds)
108
- && seconds >= MONTHLY_WINDOW_MIN_SECONDS;
130
+ const seconds = windowDurationSeconds(window);
131
+ return seconds !== undefined && seconds >= MONTHLY_WINDOW_MIN_SECONDS;
109
132
  }
110
133
 
111
134
  function isExplicitMonthlyWindowMinutes(windowMinutes: unknown): boolean {
@@ -119,17 +142,39 @@ function isExplicitMonthlyWindowMinutes(windowMinutes: unknown): boolean {
119
142
  && minutes >= MONTHLY_WINDOW_MIN_MINUTES;
120
143
  }
121
144
 
145
+ function isExplicitFiveHourWindow(window: WhamUsageWindow | null | undefined): boolean {
146
+ const seconds = windowDurationSeconds(window);
147
+ return seconds !== undefined
148
+ && seconds >= FIVE_HOUR_WINDOW_MIN_SECONDS
149
+ && seconds <= FIVE_HOUR_WINDOW_MAX_SECONDS;
150
+ }
151
+
152
+ function isExplicitFiveHourWindowMinutes(windowMinutes: unknown): boolean {
153
+ const minutes = typeof windowMinutes === "number"
154
+ ? windowMinutes
155
+ : typeof windowMinutes === "string" && windowMinutes.trim() !== ""
156
+ ? Number(windowMinutes)
157
+ : undefined;
158
+ return typeof minutes === "number"
159
+ && Number.isFinite(minutes)
160
+ && minutes >= FIVE_HOUR_WINDOW_MIN_SECONDS / 60
161
+ && minutes <= FIVE_HOUR_WINDOW_MAX_SECONDS / 60;
162
+ }
122
163
 
123
164
  function snapshotHasWeekly(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
124
165
  return quota.weeklyPercent !== undefined || quota.weeklyResetAt !== undefined;
125
166
  }
126
167
 
168
+ function snapshotHasFiveHour(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
169
+ return quota.fiveHourPercent !== undefined || quota.fiveHourResetAt !== undefined;
170
+ }
171
+
127
172
  function snapshotHasMonthly(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
128
173
  return quota.monthlyPercent !== undefined || quota.monthlyResetAt !== undefined;
129
174
  }
130
175
 
131
176
  function snapshotHasUsage(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
132
- return snapshotHasWeekly(quota) || snapshotHasMonthly(quota);
177
+ return snapshotHasFiveHour(quota) || snapshotHasWeekly(quota) || snapshotHasMonthly(quota);
133
178
  }
134
179
  export function setAccountQuotaFromParsed(
135
180
  accountId: string,
@@ -143,6 +188,8 @@ export function setAccountQuotaFromParsed(
143
188
  const creditsOnly = quota.resetCredits !== undefined && !snapshotHasUsage(quota);
144
189
 
145
190
  if (creditsOnly) {
191
+ if (existing?.fiveHourPercent !== undefined) next.fiveHourPercent = existing.fiveHourPercent;
192
+ if (existing?.fiveHourResetAt !== undefined) next.fiveHourResetAt = existing.fiveHourResetAt;
146
193
  if (existing?.weeklyPercent !== undefined) next.weeklyPercent = existing.weeklyPercent;
147
194
  if (existing?.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
148
195
  if (existing?.monthlyPercent !== undefined) next.monthlyPercent = existing.monthlyPercent;
@@ -153,20 +200,32 @@ export function setAccountQuotaFromParsed(
153
200
  return;
154
201
  }
155
202
 
156
- if (snapshotHasWeekly(quota)) {
203
+ const hasFiveHour = snapshotHasFiveHour(quota);
204
+ const hasWeekly = snapshotHasWeekly(quota);
205
+ const hasMonthly = snapshotHasMonthly(quota);
206
+
207
+ if (hasFiveHour) {
208
+ if (quota.fiveHourPercent !== undefined) next.fiveHourPercent = quota.fiveHourPercent;
209
+ if (quota.fiveHourResetAt !== undefined) next.fiveHourResetAt = quota.fiveHourResetAt;
210
+ // A five-hour-only response can be a partial snapshot; retain a known
211
+ // weekly value until a later response supplies that window.
212
+ if (!hasWeekly && existing?.weeklyPercent !== undefined) {
213
+ next.weeklyPercent = existing.weeklyPercent;
214
+ if (existing.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
215
+ }
216
+ }
217
+
218
+ if (hasWeekly) {
157
219
  if (quota.weeklyPercent !== undefined) next.weeklyPercent = quota.weeklyPercent;
158
220
  if (quota.weeklyResetAt !== undefined) next.weeklyResetAt = quota.weeklyResetAt;
159
- } else if (snapshotHasMonthly(quota) && !snapshotHasWeekly(quota)) {
221
+ } else if (hasMonthly && !hasFiveHour) {
160
222
  // Monthly-only snapshots intentionally clear stale weekly values (issue #382).
161
- } else if (existing?.weeklyPercent !== undefined) {
162
- next.weeklyPercent = existing.weeklyPercent;
163
- if (existing.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
164
223
  }
165
224
 
166
- if (snapshotHasMonthly(quota)) {
225
+ if (hasMonthly) {
167
226
  if (quota.monthlyPercent !== undefined) next.monthlyPercent = quota.monthlyPercent;
168
227
  if (quota.monthlyResetAt !== undefined) next.monthlyResetAt = quota.monthlyResetAt;
169
- } else if (snapshotHasWeekly(quota) && existing?.monthlyPercent !== undefined) {
228
+ } else if ((hasWeekly || hasFiveHour) && existing?.monthlyPercent !== undefined) {
170
229
  next.monthlyPercent = existing.monthlyPercent;
171
230
  if (existing.monthlyResetAt !== undefined) next.monthlyResetAt = existing.monthlyResetAt;
172
231
  }
@@ -178,7 +237,10 @@ export function setAccountQuotaFromParsed(
178
237
  schedulePersistAccountQuotas();
179
238
  }
180
239
 
181
- export function parseUpstreamQuotaHeaders(headers: Headers): Omit<StoredAccountQuota, "updatedAt"> | null {
240
+ export function parseUpstreamQuotaHeaders(
241
+ headers: Headers,
242
+ plan?: string | null,
243
+ ): Omit<StoredAccountQuota, "updatedAt"> | null {
182
244
  const primaryRaw = headers.get("x-codex-primary-used-percent");
183
245
  const secondaryRaw = headers.get("x-codex-secondary-used-percent");
184
246
  const tertiaryRaw = headers.get("x-codex-tertiary-used-percent");
@@ -196,25 +258,52 @@ export function parseUpstreamQuotaHeaders(headers: Headers): Omit<StoredAccountQ
196
258
  const secondaryResetAt = normalizeResetAt(secondaryResetRaw);
197
259
  const tertiaryResetAt = normalizeResetAt(tertiaryResetRaw);
198
260
  const primaryIsMonthly = primaryRaw !== null && isExplicitMonthlyWindowMinutes(primaryWindowMinutes);
261
+ const trackFiveHour = plan == null || isCodexFiveHourQuotaPlan(plan);
262
+ const primaryIsFiveHour = trackFiveHour && primaryRaw !== null && isExplicitFiveHourWindowMinutes(primaryWindowMinutes);
263
+ const secondaryIsFiveHour = trackFiveHour && secondaryRaw !== null && isExplicitFiveHourWindowMinutes(secondaryWindowMinutes);
199
264
 
200
265
  if (primaryIsMonthly) {
201
266
  if (primaryPercent !== undefined) {
202
267
  quota.monthlyPercent = primaryPercent;
203
268
  if (primaryResetAt !== undefined) quota.monthlyResetAt = primaryResetAt;
204
269
  }
205
- if (secondaryPercent !== undefined) {
270
+ if (secondaryIsFiveHour && secondaryPercent !== undefined) {
271
+ quota.fiveHourPercent = secondaryPercent;
272
+ if (secondaryResetAt !== undefined) quota.fiveHourResetAt = secondaryResetAt;
273
+ } else if (secondaryPercent !== undefined) {
206
274
  quota.weeklyPercent = secondaryPercent;
207
275
  if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
208
276
  }
209
277
  } else {
210
- const weeklyPercent = primaryPercent ?? secondaryPercent;
211
- const weeklyResetAt = primaryPercent !== undefined
212
- ? primaryResetAt
213
- : secondaryResetAt;
278
+ if (primaryIsFiveHour && primaryPercent !== undefined) {
279
+ quota.fiveHourPercent = primaryPercent;
280
+ if (primaryResetAt !== undefined) quota.fiveHourResetAt = primaryResetAt;
281
+ }
282
+ if (secondaryIsFiveHour && secondaryPercent !== undefined) {
283
+ quota.fiveHourPercent ??= secondaryPercent;
284
+ if (quota.fiveHourResetAt === undefined && secondaryResetAt !== undefined) {
285
+ quota.fiveHourResetAt = secondaryResetAt;
286
+ }
287
+ }
288
+ const weeklyPercent = primaryIsFiveHour ? secondaryPercent : primaryPercent ?? secondaryPercent;
289
+ const weeklyResetAt = primaryIsFiveHour
290
+ ? secondaryResetAt
291
+ : primaryPercent !== undefined ? primaryResetAt : secondaryResetAt;
214
292
  if (weeklyPercent !== undefined) {
215
293
  quota.weeklyPercent = weeklyPercent;
216
294
  if (weeklyResetAt !== undefined) quota.weeklyResetAt = weeklyResetAt;
217
295
  }
296
+ if (trackFiveHour
297
+ && !primaryIsFiveHour
298
+ && primaryPercent !== undefined
299
+ && secondaryPercent !== undefined
300
+ && primaryWindowMinutes === null
301
+ && secondaryWindowMinutes === null) {
302
+ quota.fiveHourPercent = primaryPercent;
303
+ if (primaryResetAt !== undefined) quota.fiveHourResetAt = primaryResetAt;
304
+ quota.weeklyPercent = secondaryPercent;
305
+ if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
306
+ }
218
307
  }
219
308
 
220
309
  if (tertiaryPercent !== undefined && quota.monthlyPercent === undefined) {
@@ -229,8 +318,9 @@ export function applyAccountQuotaFromUpstreamHeaders(
229
318
  accountId: string,
230
319
  headers: Headers,
231
320
  writerGeneration = captureConfigGeneration(),
321
+ plan?: string | null,
232
322
  ): void {
233
- const quota = parseUpstreamQuotaHeaders(headers);
323
+ const quota = parseUpstreamQuotaHeaders(headers, plan);
234
324
  if (!quota) return;
235
325
  setAccountQuotaFromParsed(accountId, quota, writerGeneration);
236
326
  }
@@ -251,7 +341,9 @@ export function updateAccountQuota(
251
341
  if (nextWeekly === undefined && nextMonthly === undefined && resetCredits === undefined) return;
252
342
 
253
343
  const quota: StoredAccountQuota = {
344
+ ...(existing?.fiveHourPercent !== undefined ? { fiveHourPercent: existing.fiveHourPercent } : {}),
254
345
  ...(existing?.weeklyPercent !== undefined ? { weeklyPercent: existing.weeklyPercent } : {}),
346
+ ...(existing?.fiveHourResetAt !== undefined ? { fiveHourResetAt: existing.fiveHourResetAt } : {}),
255
347
  ...(existing?.monthlyPercent !== undefined ? { monthlyPercent: existing.monthlyPercent } : {}),
256
348
  ...(existing?.weeklyResetAt !== undefined ? { weeklyResetAt: existing.weeklyResetAt } : {}),
257
349
  ...(existing?.monthlyResetAt !== undefined ? { monthlyResetAt: existing.monthlyResetAt } : {}),
@@ -378,20 +470,43 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
378
470
  const secondaryResetAt = normalizeResetAt(secondaryWindow?.reset_at);
379
471
  const tertiaryResetAt = normalizeResetAt(tertiaryWindow?.reset_at);
380
472
  const primaryIsMonthly = isExplicitMonthlyWindow(primaryWindow);
381
-
382
- // [Decision Log]
383
- // - 목적과 의도: distinguish weekly and roughly monthly WHAM primary windows without plan-name guesses.
384
- // - 기존 구현 제약 조건: primary meant weekly, and older responses omit limit_window_seconds.
385
- // - 검토한 주요 대안: exact-duration matching, plan-specific mapping, and a duration lower bound.
386
- // - 선택한 방식: only an explicit primary duration of at least 28 days changes it to monthly.
387
- // - 다른 대안 대신 방식을 선택한 이유: it accepts calendar-month variance and preserves legacy payloads.
388
- // - 장점, 단점 및 영향: Team monthly quotas classify correctly; unknown durations remain weekly by design.
389
- const weeklyPercent = primaryIsMonthly ? secondaryPercent : primaryPercent ?? secondaryPercent;
390
- const weeklyResetAt = primaryIsMonthly
473
+ const primaryIsFiveHour = isExplicitFiveHourWindow(primaryWindow);
474
+ const secondaryIsFiveHour = isExplicitFiveHourWindow(secondaryWindow);
475
+
476
+ // Explicit durations win over positional assumptions. This matters because
477
+ // WHAM has shipped both a legacy primary=weekly shape and a dual-window
478
+ // primary=5h, secondary=weekly shape over time.
479
+ let weeklyPercent = primaryIsMonthly ? secondaryPercent : primaryPercent ?? secondaryPercent;
480
+ let weeklyResetAt = primaryIsMonthly
391
481
  ? secondaryResetAt
392
482
  : primaryPercent !== undefined ? primaryResetAt : secondaryResetAt;
393
483
  const monthlyPercent = primaryIsMonthly ? primaryPercent ?? tertiaryPercent : tertiaryPercent;
394
484
  const monthlyResetAt = primaryIsMonthly && primaryPercent !== undefined ? primaryResetAt : tertiaryResetAt;
485
+ const trackFiveHour = !thirtyDayOnly
486
+ && (isCodexFiveHourQuotaPlan(data.plan_type)
487
+ // If WHAM omitted plan_type, an explicit 5h duration is still
488
+ // unambiguous and should not be discarded from the display contract.
489
+ || (data.plan_type == null && (primaryIsFiveHour || secondaryIsFiveHour)));
490
+ let fiveHourPercent = trackFiveHour && primaryIsFiveHour ? primaryPercent : undefined;
491
+ let fiveHourResetAt = trackFiveHour && primaryIsFiveHour ? primaryResetAt : undefined;
492
+ if (trackFiveHour && secondaryIsFiveHour && fiveHourPercent === undefined) {
493
+ fiveHourPercent = secondaryPercent;
494
+ fiveHourResetAt = secondaryResetAt;
495
+ }
496
+ // Older dual-window payloads omitted durations. For Plus/Team/Business,
497
+ // the primary+secondary pair is the legacy positional 5h+weekly shape.
498
+ if (trackFiveHour && !primaryIsMonthly && !primaryIsFiveHour
499
+ && primaryPercent !== undefined && secondaryPercent !== undefined
500
+ && windowDurationSeconds(primaryWindow) === undefined
501
+ && windowDurationSeconds(secondaryWindow) === undefined) {
502
+ fiveHourPercent = primaryPercent;
503
+ fiveHourResetAt = primaryResetAt;
504
+ weeklyPercent = secondaryPercent;
505
+ weeklyResetAt = secondaryResetAt;
506
+ } else if (trackFiveHour && primaryIsFiveHour) {
507
+ weeklyPercent = secondaryPercent;
508
+ weeklyResetAt = secondaryResetAt;
509
+ }
395
510
  if (thirtyDayOnly) {
396
511
  if (monthlyPercent !== undefined) {
397
512
  quota.monthlyPercent = monthlyPercent;
@@ -401,6 +516,10 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
401
516
  quota.weeklyPercent = weeklyPercent;
402
517
  if (weeklyResetAt !== undefined) quota.weeklyResetAt = weeklyResetAt;
403
518
  }
519
+ if (trackFiveHour && fiveHourPercent !== undefined) {
520
+ quota.fiveHourPercent = fiveHourPercent;
521
+ if (fiveHourResetAt !== undefined) quota.fiveHourResetAt = fiveHourResetAt;
522
+ }
404
523
  if (!thirtyDayOnly && monthlyPercent !== undefined) {
405
524
  quota.monthlyPercent = monthlyPercent;
406
525
  if (monthlyResetAt !== undefined) quota.monthlyResetAt = monthlyResetAt;