@omnicross/subscriptions 0.1.6 → 0.1.7

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.
@@ -29,39 +29,70 @@ function errorMessage(error, errorDescription) {
29
29
  }
30
30
  return String(error);
31
31
  }
32
- async function postForm(fetchImpl, url, params, parseErrorMessage) {
33
- const response = await fetchImpl(url, {
34
- method: "POST",
35
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
36
- body: params.toString()
37
- });
32
+ function withStatus(message, response) {
33
+ return response.ok ? message : `${message} (HTTP ${response.status})`;
34
+ }
35
+ var DEFAULT_TOKEN_TIMEOUT_MS = 3e4;
36
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
37
+ const controller = new AbortController();
38
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
39
+ try {
40
+ return await fetchImpl(url, { ...init, signal: controller.signal });
41
+ } catch (e) {
42
+ if (controller.signal.aborted) {
43
+ throw new Error(`token endpoint timed out after ${Math.round(timeoutMs / 1e3)}s`);
44
+ }
45
+ throw e;
46
+ } finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
50
+ async function postForm(fetchImpl, url, params, parseErrorMessage, timeoutMs = DEFAULT_TOKEN_TIMEOUT_MS) {
51
+ const response = await fetchWithTimeout(
52
+ fetchImpl,
53
+ url,
54
+ {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
57
+ body: params.toString()
58
+ },
59
+ timeoutMs
60
+ );
38
61
  const responseData = await response.text();
39
62
  let data;
40
63
  try {
41
64
  data = JSON.parse(responseData);
42
65
  } catch (e2) {
43
- throw new Error(parseErrorMessage);
66
+ throw new Error(withStatus(parseErrorMessage, response));
44
67
  }
45
68
  if (data.error) {
46
- throw new Error(errorMessage(data.error, data.error_description));
69
+ throw new Error(withStatus(errorMessage(data.error, data.error_description), response));
47
70
  }
48
71
  return data;
49
72
  }
50
- async function postJson(fetchImpl, url, body, parseErrorMessage, extraHeaders = {}) {
51
- const response = await fetchImpl(url, {
52
- method: "POST",
53
- headers: { "Content-Type": "application/json", ...extraHeaders },
54
- body: JSON.stringify(body)
55
- });
73
+ async function postJson(fetchImpl, url, body, parseErrorMessage, extraHeaders = {}, timeoutMs = DEFAULT_TOKEN_TIMEOUT_MS) {
74
+ const response = await fetchWithTimeout(
75
+ fetchImpl,
76
+ url,
77
+ {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json", ...extraHeaders },
80
+ body: JSON.stringify(body)
81
+ },
82
+ timeoutMs
83
+ );
56
84
  const responseData = await response.text();
57
85
  let data;
58
86
  try {
59
87
  data = JSON.parse(responseData);
60
88
  } catch (e3) {
61
- throw new Error(parseErrorMessage);
89
+ throw new Error(withStatus(parseErrorMessage, response));
62
90
  }
63
91
  if (data.error) {
64
- throw new Error(errorMessage(data.error, data.error_description));
92
+ throw new Error(withStatus(errorMessage(data.error, data.error_description), response));
93
+ }
94
+ if (!response.ok) {
95
+ throw new Error(withStatus("token endpoint rejected the request", response));
65
96
  }
66
97
  return data;
67
98
  }
@@ -29,39 +29,70 @@ function errorMessage(error, errorDescription) {
29
29
  }
30
30
  return String(error);
31
31
  }
32
- async function postForm(fetchImpl, url, params, parseErrorMessage) {
33
- const response = await fetchImpl(url, {
34
- method: "POST",
35
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
36
- body: params.toString()
37
- });
32
+ function withStatus(message, response) {
33
+ return response.ok ? message : `${message} (HTTP ${response.status})`;
34
+ }
35
+ var DEFAULT_TOKEN_TIMEOUT_MS = 3e4;
36
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
37
+ const controller = new AbortController();
38
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
39
+ try {
40
+ return await fetchImpl(url, { ...init, signal: controller.signal });
41
+ } catch (e) {
42
+ if (controller.signal.aborted) {
43
+ throw new Error(`token endpoint timed out after ${Math.round(timeoutMs / 1e3)}s`);
44
+ }
45
+ throw e;
46
+ } finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
50
+ async function postForm(fetchImpl, url, params, parseErrorMessage, timeoutMs = DEFAULT_TOKEN_TIMEOUT_MS) {
51
+ const response = await fetchWithTimeout(
52
+ fetchImpl,
53
+ url,
54
+ {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
57
+ body: params.toString()
58
+ },
59
+ timeoutMs
60
+ );
38
61
  const responseData = await response.text();
39
62
  let data;
40
63
  try {
41
64
  data = JSON.parse(responseData);
42
65
  } catch {
43
- throw new Error(parseErrorMessage);
66
+ throw new Error(withStatus(parseErrorMessage, response));
44
67
  }
45
68
  if (data.error) {
46
- throw new Error(errorMessage(data.error, data.error_description));
69
+ throw new Error(withStatus(errorMessage(data.error, data.error_description), response));
47
70
  }
48
71
  return data;
49
72
  }
50
- async function postJson(fetchImpl, url, body, parseErrorMessage, extraHeaders = {}) {
51
- const response = await fetchImpl(url, {
52
- method: "POST",
53
- headers: { "Content-Type": "application/json", ...extraHeaders },
54
- body: JSON.stringify(body)
55
- });
73
+ async function postJson(fetchImpl, url, body, parseErrorMessage, extraHeaders = {}, timeoutMs = DEFAULT_TOKEN_TIMEOUT_MS) {
74
+ const response = await fetchWithTimeout(
75
+ fetchImpl,
76
+ url,
77
+ {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json", ...extraHeaders },
80
+ body: JSON.stringify(body)
81
+ },
82
+ timeoutMs
83
+ );
56
84
  const responseData = await response.text();
57
85
  let data;
58
86
  try {
59
87
  data = JSON.parse(responseData);
60
88
  } catch {
61
- throw new Error(parseErrorMessage);
89
+ throw new Error(withStatus(parseErrorMessage, response));
62
90
  }
63
91
  if (data.error) {
64
- throw new Error(errorMessage(data.error, data.error_description));
92
+ throw new Error(withStatus(errorMessage(data.error, data.error_description), response));
93
+ }
94
+ if (!response.ok) {
95
+ throw new Error(withStatus("token endpoint rejected the request", response));
65
96
  }
66
97
  return data;
67
98
  }
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkTPW5Q25Ycjs = require('./chunk-TPW5Q25Y.cjs');
5
+ var _chunkPWV5NBO5cjs = require('./chunk-PWV5NBO5.cjs');
6
6
 
7
7
  // src/scheduler/SubscriptionAccountSelector.ts
8
8
  var SESSION_AFFINITY_TTL_MS = 36e5;
@@ -172,7 +172,7 @@ function isPoolGated(accounts, health, resolvedModel) {
172
172
  function hasUsableToken(token) {
173
173
  return typeof token === "string" && token.trim() !== "";
174
174
  }
175
- async function resolveStrictPreferredToken(tokens, providerId, preferredId, activeGetter, ctx) {
175
+ async function resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx) {
176
176
  let config;
177
177
  try {
178
178
  config = await tokens.getFullConfig();
@@ -219,6 +219,7 @@ async function resolveStrictPreferredToken(tokens, providerId, preferredId, acti
219
219
  throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "empty-token");
220
220
  }
221
221
  const remapped = remapReportForAccount(supportedModelsById.get(preferredId), ctx.resolvedModel);
222
+ if (selector) maybeTouchLastUsed(selector, tokens, providerId, preferredId);
222
223
  _optionalChain([ctx, 'access', _ => _.reportSelection, 'optionalCall', _2 => _2(preferredId, preferredId === activeAccountId, remapped)]);
223
224
  return token;
224
225
  }
@@ -284,7 +285,7 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
284
285
  const preferredId = typeof _optionalChain([ctx, 'optionalAccess', _9 => _9.preferredAccountId]) === "string" && ctx.preferredAccountId.trim() !== "" ? ctx.preferredAccountId.trim() : void 0;
285
286
  const preferredGroup = typeof _optionalChain([ctx, 'optionalAccess', _10 => _10.preferredAccountGroup]) === "string" && ctx.preferredAccountGroup.trim() !== "" ? ctx.preferredAccountGroup.trim() : void 0;
286
287
  if (preferredId && ctx && ctx.boundAccountFallbackPolicy !== "pool") {
287
- return resolveStrictPreferredToken(tokens, providerId, preferredId, activeGetter, ctx);
288
+ return resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx);
288
289
  }
289
290
  if (selector && tokens.getAccessTokenForAccount) {
290
291
  const config = await tokens.getFullConfig();
@@ -375,7 +376,12 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
375
376
  if (activeAllowance.action === "pause") {
376
377
  throw new (0, _AccountAllowanceScheduling.AccountAllowanceExhaustedError)(providerId, activeAllowance.resumeAt);
377
378
  }
378
- _optionalChain([report, 'optionalCall', _22 => _22(activeAccountId, true, remapFor(activeAccountId))]);
379
+ const token = await activeGetter();
380
+ if (hasUsableToken(token)) {
381
+ maybeTouchLastUsed(selector, tokens, providerId, activeAccountId);
382
+ _optionalChain([report, 'optionalCall', _22 => _22(activeAccountId, true, remapFor(activeAccountId))]);
383
+ }
384
+ return token;
379
385
  }
380
386
  return activeGetter();
381
387
  }
@@ -1697,4 +1703,4 @@ function stripAuthHeaders(headers) {
1697
1703
 
1698
1704
 
1699
1705
 
1700
- exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth = _chunkTPW5Q25Ycjs.claude_exports; exports.codexOAuth = _chunkTPW5Q25Ycjs.codex_exports; exports.geminiOAuth = _chunkTPW5Q25Ycjs.gemini_exports; exports.getSubscriptionAccountService = getSubscriptionAccountService; exports.getSubscriptionProviderRegistry = getSubscriptionProviderRegistry; exports.setSubscriptionAccountService = setSubscriptionAccountService; exports.setSubscriptionProviderRegistry = setSubscriptionProviderRegistry;
1706
+ exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth = _chunkPWV5NBO5cjs.claude_exports; exports.codexOAuth = _chunkPWV5NBO5cjs.codex_exports; exports.geminiOAuth = _chunkPWV5NBO5cjs.gemini_exports; exports.getSubscriptionAccountService = getSubscriptionAccountService; exports.getSubscriptionProviderRegistry = getSubscriptionProviderRegistry; exports.setSubscriptionAccountService = setSubscriptionAccountService; exports.setSubscriptionProviderRegistry = setSubscriptionProviderRegistry;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  claude_exports,
3
3
  codex_exports,
4
4
  gemini_exports
5
- } from "./chunk-IXGHVMZB.js";
5
+ } from "./chunk-UETFQ5LB.js";
6
6
 
7
7
  // src/scheduler/SubscriptionAccountSelector.ts
8
8
  var SESSION_AFFINITY_TTL_MS = 36e5;
@@ -172,7 +172,7 @@ function isPoolGated(accounts, health, resolvedModel) {
172
172
  function hasUsableToken(token) {
173
173
  return typeof token === "string" && token.trim() !== "";
174
174
  }
175
- async function resolveStrictPreferredToken(tokens, providerId, preferredId, activeGetter, ctx) {
175
+ async function resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx) {
176
176
  let config;
177
177
  try {
178
178
  config = await tokens.getFullConfig();
@@ -219,6 +219,7 @@ async function resolveStrictPreferredToken(tokens, providerId, preferredId, acti
219
219
  throw new BoundAccountSelectionError(providerId, "empty-token");
220
220
  }
221
221
  const remapped = remapReportForAccount(supportedModelsById.get(preferredId), ctx.resolvedModel);
222
+ if (selector) maybeTouchLastUsed(selector, tokens, providerId, preferredId);
222
223
  ctx.reportSelection?.(preferredId, preferredId === activeAccountId, remapped);
223
224
  return token;
224
225
  }
@@ -284,7 +285,7 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
284
285
  const preferredId = typeof ctx?.preferredAccountId === "string" && ctx.preferredAccountId.trim() !== "" ? ctx.preferredAccountId.trim() : void 0;
285
286
  const preferredGroup = typeof ctx?.preferredAccountGroup === "string" && ctx.preferredAccountGroup.trim() !== "" ? ctx.preferredAccountGroup.trim() : void 0;
286
287
  if (preferredId && ctx && ctx.boundAccountFallbackPolicy !== "pool") {
287
- return resolveStrictPreferredToken(tokens, providerId, preferredId, activeGetter, ctx);
288
+ return resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx);
288
289
  }
289
290
  if (selector && tokens.getAccessTokenForAccount) {
290
291
  const config = await tokens.getFullConfig();
@@ -375,7 +376,12 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
375
376
  if (activeAllowance.action === "pause") {
376
377
  throw new AccountAllowanceExhaustedError(providerId, activeAllowance.resumeAt);
377
378
  }
378
- report?.(activeAccountId, true, remapFor(activeAccountId));
379
+ const token = await activeGetter();
380
+ if (hasUsableToken(token)) {
381
+ maybeTouchLastUsed(selector, tokens, providerId, activeAccountId);
382
+ report?.(activeAccountId, true, remapFor(activeAccountId));
383
+ }
384
+ return token;
379
385
  }
380
386
  return activeGetter();
381
387
  }
package/dist/oauth.cjs CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkTPW5Q25Ycjs = require('./chunk-TPW5Q25Y.cjs');
5
+ var _chunkPWV5NBO5cjs = require('./chunk-PWV5NBO5.cjs');
6
6
 
7
7
 
8
8
 
9
9
 
10
- exports.claudeOAuth = _chunkTPW5Q25Ycjs.claude_exports; exports.codexOAuth = _chunkTPW5Q25Ycjs.codex_exports; exports.geminiOAuth = _chunkTPW5Q25Ycjs.gemini_exports;
10
+ exports.claudeOAuth = _chunkPWV5NBO5cjs.claude_exports; exports.codexOAuth = _chunkPWV5NBO5cjs.codex_exports; exports.geminiOAuth = _chunkPWV5NBO5cjs.gemini_exports;
package/dist/oauth.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  claude_exports,
3
3
  codex_exports,
4
4
  gemini_exports
5
- } from "./chunk-IXGHVMZB.js";
5
+ } from "./chunk-UETFQ5LB.js";
6
6
  export {
7
7
  claude_exports as claudeOAuth,
8
8
  codex_exports as codexOAuth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnicross/subscriptions",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Omnicross subscription-as-provider auth strategies, OAuth flows, and the OpenCodeGo scenario dispatcher.",
5
5
  "license": "MIT",
6
6
  "author": "Sayo (https://github.com/Dumoedss)",