@byokit/accounts 0.9.0 → 0.10.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.10.0 (2026-09-30)
6
+
7
+
8
+
9
+ - Export portable `classifyFailure` and `Failure`, with an injectable clock and `REST_MS` fallbacks; retain `classify` as an alias.
10
+
5
11
  ## 0.9.0 (2026-09-30)
6
12
 
7
13
 
package/README.md CHANGED
@@ -122,7 +122,7 @@ and [`examples/pwa`](../../examples/pwa) (browser sign-in).
122
122
  | `offered`, `provider`, `PROVIDERS` | The catalogue: each provider's billing, terms status, reason and source |
123
123
  | `billingWords`, `say`, `WORDS`, `signInError`, `failure`, `clock`, `callbackPage` | The plain sentences every app shows the same way (`words.json`), a time in words, and the page a browser sees after a sign-in |
124
124
  | `respond`, `ResponseError`, `IncompleteError`, `sseReader`, `limitResponse`, `isFunctionCall` | Ask ChatGPT's answers endpoint with a sign-in, with tools, pictures, thinking effort and an answer shape; the error with the words to show and the kind acted on |
125
- | `classify`, `REST_MS` | An error's kind (limit, overload, plan without this use, lapsed sign-in, network) and default rest times |
125
+ | `classifyFailure`, `classify`, `REST_MS` | An error's kind (limit, overload, plan without this use, lapsed sign-in, network) and default rest times |
126
126
  | `planOf`, `claims` | The ChatGPT plan and email behind a sign-in, from its own token |
127
127
  | `deviceStart`, `devicePoll`, `credentialOf`, `portableEngine`, `PORTABLE` | The device-code flow, the sign-in built from a token answer, and the engine under `portable` |
128
128
  | `isolate`, `INHERITED`, `emptyAuthContext` (`/isolate`) | Scrub inherited Pi settings and provider keys; ambient discovery off |
@@ -355,3 +355,9 @@ For a plaintext store, stop all writers, revoke the old credentials using the ol
355
355
  remove the old app-owned credential file, and sign in again with a sealing adapter. Old plaintext
356
356
  backups may retain tokens: delete them under the host's retention policy and revoke the affected
357
357
  credentials. Do not point this migration at another tool's sign-in directory.
358
+ `classifyFailure(error, nowMs?)` returns a typed `Failure` (`{ kind, until }`) or `null`
359
+ for an unrecognized error. `until` is epoch milliseconds when the error says "try again
360
+ in N min/hours", and zero otherwise. For resting kinds, use
361
+ `failure.until || nowMs + REST_MS[failure.kind]`; signed-out, not-included and network
362
+ failures have no fallback rest. `classify` remains an alias. Pass a clock for deterministic
363
+ classification; the default uses `Date.now()`. It stores and logs no error text.
@@ -1,6 +1,5 @@
1
1
  import type { CredentialStore, Models } from '@earendil-works/pi-ai';
2
2
  import { type Provider } from './catalogue.ts';
3
- import { type Kind } from './limits.ts';
4
3
  import { ResponseError, type Ask, type ResponseResult, type ResponseTool } from './responses.ts';
5
4
  import { type EndingStore, type RefreshStore } from './stores.ts';
6
5
  import { type Why } from './words.ts';
@@ -141,10 +140,7 @@ export declare class Accounts<R extends AuthHost = AuthHost, M extends Member =
141
140
  respond(member: M, ask: Ask & {
142
141
  tools: ResponseTool[];
143
142
  }): Promise<ResponseResult>;
144
- failed(member: M, key: string, error: string | ResponseError): Promise<{
145
- kind: Kind;
146
- until: number;
147
- } | null>;
143
+ failed(member: M, key: string, error: string | ResponseError): Promise<import("./limits.ts").Failure | null>;
148
144
  /** The first choice whose account is neither resting nor known to be unusable: the fallback ladder. */
149
145
  ladder<T>(member: M, choices: readonly T[], key?: (c: T) => string): T | undefined;
150
146
  /** Where one account stands, in one plain sentence every app shows the same way. */
package/dist/limits.d.ts CHANGED
@@ -2,7 +2,11 @@ export type Kind = 'rate_limit' | 'overloaded' | 'signed_out' | 'not_included' |
2
2
  /** How long an account rests when its error didn't say. */
3
3
  export declare const REST_MS: Record<Kind, number>;
4
4
  /** `until` is 0 when the error didn't say. Anything unrecognised is null: the app fails that one request. */
5
- export declare function classify(error: string): {
5
+ export type Failure = {
6
6
  kind: Kind;
7
7
  until: number;
8
- } | null;
8
+ };
9
+ /** Pure when the host passes its clock. REST_MS supplies the fallback rest duration. */
10
+ export declare function classifyFailure(error: string, nowMs?: number): Failure | null;
11
+ /** Backwards-compatible name for classifyFailure. */
12
+ export declare const classify: typeof classifyFailure;
package/dist/limits.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /** How long an account rests when its error didn't say. */
2
2
  export const REST_MS = { rate_limit: 60 * 60_000, overloaded: 5 * 60_000, signed_out: 0, not_included: 0, network: 0 };
3
- /** `until` is 0 when the error didn't say. Anything unrecognised is null: the app fails that one request. */
4
- export function classify(error) {
3
+ /** Pure when the host passes its clock. REST_MS supplies the fallback rest duration. */
4
+ export function classifyFailure(error, nowMs = Date.now()) {
5
5
  const m = /try again in ~?(\d+)\s*(min|h)/i.exec(error);
6
- const until = m ? Date.now() + Number(m[1]) * (m[2].toLowerCase() === 'h' ? 3_600_000 : 60_000) : 0;
6
+ const until = m ? nowMs + Number(m[1]) * (m[2].toLowerCase() === 'h' ? 3_600_000 : 60_000) : 0;
7
7
  if (/your plan doesn't include/i.test(error))
8
8
  return { kind: 'not_included', until };
9
9
  if (/usage limit|rate.?limit|quota|too many requests|\b429\b/i.test(error))
@@ -16,3 +16,5 @@ export function classify(error) {
16
16
  return { kind: 'network', until };
17
17
  return null;
18
18
  }
19
+ /** Backwards-compatible name for classifyFailure. */
20
+ export const classify = classifyFailure;
@@ -1,7 +1,7 @@
1
1
  export { Accounts, planOf, portable, type AccountsOptions, type AuthHost, type Loopback, type Member, type Platform, type SignIn, type Status } from './accounts.ts';
2
2
  export { PROVIDERS, offered, provider, type Billing, type Provider, type Terms } from './catalogue.ts';
3
3
  export { PORTABLE, claims, credentialOf, devicePoll, deviceStart, portableEngine, type EngineOptions, type Poll } from './engine.ts';
4
- export { REST_MS, classify, type Kind } from './limits.ts';
4
+ export { REST_MS, classify, classifyFailure, type Failure, type Kind } from './limits.ts';
5
5
  export { IncompleteError, ResponseError, isFunctionCall, limitResponse, respond, sseReader, type Ask, type ResponseFunctionCall, type ResponseInputItem, type ResponseOutputItem, type ResponseOutputMessage, type ResponseReasoning, type ResponseResult, type ResponseStreamEvent, type ResponseText, type ResponseTextFormat, type ResponseTool, type ResponseToolChoice } from './responses.ts';
6
6
  export { browserStore, memoryStore, recordStore, secureStore, RefreshRequiredError, type RefreshStore, type SecureStoreLike } from './stores.ts';
7
7
  export { WORDS, billingWords, callbackPage, clock, failure, say, signInError, type WordKey, type Why } from './words.ts';
package/dist/portable.js CHANGED
@@ -3,7 +3,7 @@
3
3
  export { Accounts, planOf, portable } from "./accounts.js";
4
4
  export { PROVIDERS, offered, provider } from "./catalogue.js";
5
5
  export { PORTABLE, claims, credentialOf, devicePoll, deviceStart, portableEngine } from "./engine.js";
6
- export { REST_MS, classify } from "./limits.js";
6
+ export { REST_MS, classify, classifyFailure } from "./limits.js";
7
7
  export { IncompleteError, ResponseError, isFunctionCall, limitResponse, respond, sseReader } from "./responses.js";
8
8
  export { browserStore, memoryStore, recordStore, secureStore, RefreshRequiredError } from "./stores.js";
9
9
  export { WORDS, billingWords, callbackPage, clock, failure, say, signInError } from "./words.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byokit/accounts",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Sign in with the AI plan you already pay for, into your app's own store.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",