@farthershore/farthershore-js/errors exports
Every public export and declaration from @farthershore/farthershore-js/errors.
Every public export and declaration from @farthershore/farthershore-js/errors.
Import from @farthershore/farthershore-js/errors. This reference is extracted from the published declaration surface for version 0.32.0. Read the collection's guides for workflows, prerequisites and failure handling.
A {@link ProviderLimitError} for a `503 provider_throttled` — the ADAPTIVE
upstream throttle (an LLM/API provider rate limit) the platform RELAYS. The
reaction is `fallback`/`backoff_retry`; `.limitClass` is `adaptive`. Still a
retryable throttle (`instanceof FartherShoreRateLimitedError` holds).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L330.
export declare class AdaptiveThrottleError extends ProviderLimitError {
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreRateLimitedError} subclass for a `429
concurrency_limit_exceeded` (T7 — a customer/subscription "wait for a slot",
NOT a 503; the platform/coordinator faults are the separate 503
`concurrency_*_unavailable` codes). Too many requests in flight
simultaneously; it resolves as outstanding requests drain (no period), so the
reaction is `queue`/`backoff_retry`. Still a retryable throttle (`instanceof
FartherShoreRateLimitedError` holds). `.limitClass` is `concurrency`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L311.
export declare class ConcurrencyLimitError extends FartherShoreRateLimitedError {
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
Fix #10 — derive the {@link LimitFacet} for a caught limit error: a THIN
COMPOSITION over the contracts class taxonomy ({@link classifyFsLimit }, via
the error's already-derived `.limitClass`) + the request lifecycle + the
headroom the deny reported. It does NOT re-derive the six classes — it reads
the class off the error and composes the reaction/retry/upgrade/headroom view
a UI renders. Returns null when the error is not a usage-limit deny.
Accepts either a {@link LimitExceededError} (and its 413/spend subclasses) or
a {@link FartherShoreRateLimitedError} (and its concurrency/adaptive
subclasses) — both already carry `.limitClass`/`.envelope`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L572.
export declare function deriveLimitFacet(err: unknown): LimitFacet | null;
A5-amend (T11) — derive an {@link ObservedLimitDeny} from a caught error, or
null when the error is not a limit/throttle deny. PURE; safe on any value.
Forward-compat: an unknown class is preserved (null + `unknownLimitClass`),
never discarded. `now` is injectable for tests.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L613.
export declare function deriveObservedLimitDeny(err: unknown, now?: () => number): ObservedLimitDeny | null;
Thrown when a request was aborted (e.g. a React hook unmounted or its deps
changed before the request resolved). Callers/hooks should ignore it.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L713.
export declare class FartherShoreAbortError extends FartherShoreError {
constructor(message?: string);
}
A non-2xx response from Core or the Gateway. Exposes:
- `.status` — the HTTP status code;
- `.code` — the platform error code from the `{ error: { code, message } }`
envelope (or a fallback when the envelope is absent);
- `.body` — the parsed response body, for richer error detail.
Callers commonly branch on `.status` — e.g. `401`/`403` (re-auth), `404`
(treat as absent), `409` (conflict/retry) — rather than parsing the message.
Every instance also carries the throttle hints the gateway attaches when
present: `.retryAfterSeconds` (from `Retry-After`) and `.rateLimit` (from
`X-RateLimit-Remaining` / `-Reset`). Both are null when the headers are
absent — a developer who does nothing still gets them transparently.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L49.
export declare class FartherShoreApiError extends FartherShoreError {
readonly status: number;
readonly code: string;
readonly body: unknown;
/** Seconds to wait before retrying, parsed from `Retry-After`; null when the
* response carried no `Retry-After`. */
readonly retryAfterSeconds: number | null;
/** The `X-RateLimit-Remaining` / `-Reset` snapshot, or null when absent. */
readonly rateLimit: RateLimitSnapshot | null;
/**
* Whether the request that produced this error actually carried an auth
* credential (a bearer was attached). Set by the transport AFTER the error is
* minted. A `401` with `authed === false` is a NEVER-authenticated visitor (a
* signed-out `/me` read sent no bearer) — the managed auth layer must treat it
* as a no-op, NOT a lapsed-session redirect. Defaults to `true` so any caller
* that doesn't thread the flag keeps the prior (always-fire) behaviour.
*/
authed: boolean;
/**
* Whether a `401` on this request should trigger the MANAGED auth-layer
* recovery (the hosted-sign-in redirect / persona sign-out). Best-effort `/me`
* reads that already swallow a 401 (and render a signed-out/unsubscribed
* surface) set this `false`: re-authenticating an already signed-in user can
* never clear an authorization 401, so the redirect is futile and loops. Set
* by the transport from `CoreRequest.recoverAuth`. The config-level
* `onUnauthorized` + `onError` hooks STILL fire (observability is unaffected);
* only the managed reaction is gated. Defaults to `true` (always recover).
*/
recoverAuth: boolean;
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreApiError} for a `BILLING_NOT_CONFIGURED` deny — a
TRANSIENT onboarding state where the plan's Stripe billing is still being set
up ("Plan billing is being set up. Please try again in a moment."). The
subscriber should see a retry affordance, not a hard error. `.transient` is
always true; pair with {@link isBillingNotConfigured} when you only have the
caught value.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L508.
export declare class FartherShoreBillingNotConfiguredError extends FartherShoreApiError {
/** Always true — this is a "setting up, retry shortly" state. */
readonly transient: true;
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
Thrown at client construction for invalid/missing config (e.g. no `coreUrl`,
no global `fetch`).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L723.
export declare class FartherShoreConfigError extends FartherShoreError {
constructor(message: string);
}
Public export FartherShoreError.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L2.
export declare class FartherShoreError extends Error {
constructor(message: string);
}
A {@link FartherShoreApiError} for a subscription-lifecycle block — the
gateway's `lifecycle_block` constraint denies the request (`403
subscription_inactive`) because the subscription is SUSPENDED / CANCELLED /
INACTIVE (a failed payment, a cancellation, or an expired trial). `.suggestedAction`
tells the app which remediation to surface: `restore` for a cancellation, else
`billing-portal` to fix the payment method.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L444.
export declare class FartherShoreLifecycleBlockedError extends FartherShoreApiError {
/** The remediation to point the subscriber at — `restore` (a cancellation can
* be reversed) or `billing-portal` (a failed/expired payment must be fixed). */
readonly suggestedAction: RemediationAction;
constructor(status: number, code: string, message: string, body: unknown, suggestedAction: RemediationAction, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A network-level failure (DNS, connection, CORS, abort).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L707.
export declare class FartherShoreNetworkError extends FartherShoreError {
readonly cause?: unknown;
constructor(message: string, cause?: unknown);
}
Thrown when the client is used before `bootstrap()` has resolved the product
it needs (e.g. a per-product call with no configured businessId).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L718.
export declare class FartherShoreNotReadyError extends FartherShoreError {
constructor(message: string);
}
A {@link FartherShoreApiError} for a `409 PLAN_OFFER_CHANGED` — the caller
passed an `offerFingerprint` (from `fs.plans.getPlanOffers()`) to
`subscribe()` / `startOnboarding()`, and the target plan's ECONOMIC content
(fee, meters, grants, trial, interval — never presentation) changed between
render and purchase. No checkout session was created and no state changed.
Remedy: refetch `getPlanOffers()`, re-present the current price for consent,
and retry with the fresh fingerprint.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L494.
export declare class FartherShorePlanOfferChangedError extends FartherShoreApiError {
/** Always `refetch_offers` — refetch the plan offers and re-present the
* current price before retrying. */
readonly suggestedAction: "refetch_offers";
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreApiError} the caller should BACK OFF and retry — a rate
limit (`429`) or one of the transient throttle deny codes. `.retryAfterSeconds`
(when the gateway sent `Retry-After`) is the hint for how long. Catch it to
implement a retry/backoff loop without re-parsing status codes.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L288.
export declare class FartherShoreRateLimitedError extends FartherShoreApiError {
/** The semantic {@link FsLimitClass} when this throttle classifies to one
* (`rate` / `concurrency` / `adaptive`), else null. */
readonly limitClass: FsLimitClass__2d5726601b87 | null;
/** The parsed `_fs` deny envelope when present. */
readonly envelope: FsDenyEnvelope | null;
/** The recommended client reaction (default `backoff_retry` for a throttle). */
readonly reaction: FsLimitReaction;
/** Whether the platform or an upstream provider decided the throttle. */
readonly limitOrigin: FsLimitOrigin;
/** The gateway decision id, when the `_fs` envelope carried one. */
readonly decisionId: string | null;
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreApiError} for a `409 INVALID_STATE` from the
onboarding/restore path — the subscriber already has a subscription that
conflicts with the attempted action (the "already subscribed — restore it"
case). `.suggestedAction` is always `restore`: the remedy is
`fs.billing.restoreSubscription()`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L468.
export declare class FartherShoreSubscriptionConflictError extends FartherShoreApiError {
/** Always `restore` — an existing subscription should be restored, not
* re-created. */
readonly suggestedAction: "restore";
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
The direct-URL secure-fetch (`fs.fetch`) DENY vocabulary — the SDK's typed
projection of the gateway secret-inject wire codes so a builder catches a
meaningful `FartherShoreApiError.code`, not a raw 403/502. Each maps a family
of gateway wire codes onto ONE stable SDK code:
- `VARIABLE_NOT_ALLOWED_HOST` ← `host_not_allowed` (403) — the target host
is not on the variable's allowlist (set at variable-create; the
provider-catalog auto-detect ran server-side).
- `MACHINE_KEY_FORBIDDEN` ← `api_key_cannot_use_secret_inject` (403) — a
machine/API-key (`fsk_`) caller may not use server-only secret injection;
it is a signed-in customer-session-only affordance.
- `UPSTREAM_ERROR` ← any `upstream_*` (502) — the upstream call was refused
or failed at the SSRF-safe forwarder (unreachable / not-https /
blocked-host / redirect-refused / invalid-url).
Branch on these instead of parsing the message or status.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L660.
declare const FS_SECURE_FETCH_ERROR_CODES: {
readonly VARIABLE_NOT_ALLOWED_HOST: "VARIABLE_NOT_ALLOWED_HOST";
readonly MACHINE_KEY_FORBIDDEN: "MACHINE_KEY_FORBIDDEN";
readonly UPSTREAM_ERROR: "UPSTREAM_ERROR";
};
The `_fs` deny envelope a limit deny body carries under the `_fs` key
(`{ error, code, _fs: FsDenyEnvelope }`). A SUPERSET of {@link LimitDescriptor}:
a single self-describing block telling a client WHAT class of limit was hit,
WHY, and what to DO — without re-deriving it from the wire code + status. A
hand-mirror of the contracts `FsDenyEnvelope` (the published surface stays
contracts-free); the field set is bound to the source by the drift guard. The
optional fields are absent when not known so the envelope stays byte-minimal.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L109.
export interface FsDenyEnvelope {
/**
* The semantic class of limit hit — the primary axis clients branch on.
* `null` ONLY when the wire carried a `limitClass` string the SDK's closed
* mirror does NOT know (a FUTURE class added to contracts but not yet shipped
* in this bundle, T13). In that case the raw value is preserved on
* {@link unknownLimitClass} and the whole `_fs` block on {@link raw} so a
* client can still render + introspect the deny, while the SDK refuses to
* invent a known-class facet for it. A KNOWN class is always non-null.
*/
limitClass: FsLimitClass__2d5726601b87 | null;
/**
* T13 — the raw `limitClass` string when it is NOT a member of the closed
* {@link FsLimitClass} mirror (a future/unknown class). Undefined for every
* known class. Lets a forward-compat client surface "a `<unknownLimitClass>`
* limit was hit" + a debug breadcrumb without the SDK guessing semantics.
*/
unknownLimitClass?: string;
/**
* T13 — the raw `_fs` block exactly as it arrived on the wire, preserved for
* debugging/forwarding. Always present (even for a known class) so a developer
* can inspect fields this bundle's typed projection doesn't model yet.
*/
raw?: Record<string, unknown>;
/** The limit's scope when known (e.g. `subscription`, `org`, `route`). */
scope?: string;
/** Actor facet for actor-scoped subscriber limits. Carries kind only; raw
* actor ids must never be present in deny envelopes. */
actorScope?: "member" | "service_account";
/** The metered/resource dimension when known (e.g. `tokens`, `requests`). */
metric?: string;
/** Unix epoch ms when the limit window resets, when known. */
reset?: number;
/** Units remaining in the window at decision time, when known. */
remaining?: number;
/** Units already consumed in the window at decision time, when known. */
used?: number;
/** The cap value (the ceiling that was hit), when known. */
limit?: number;
/** True when retrying the SAME request can succeed (velocity/transient cap). */
retrySafe: boolean;
/** True when the caller must MODIFY the request (reduce size / change plan)
* before it can succeed — the `capacity`/`spend` affordances. */
mustModify: boolean;
/** Provider-supplied reason verbatim, when relayed upstream (an `adaptive`
* throttle). */
providerReason?: string;
/** Whether the platform or an upstream provider decided the limit. */
limitOrigin: FsLimitOrigin;
/** Human-facing next step for the END USER, when one applies. */
userAction?: string;
/** Human-facing next step for the DEVELOPER/operator, when one applies. */
devAction?: string;
/** The per-attempt request id (correlates with logs/traces). */
requestId?: string;
/** The gateway decision id (correlates with the usage event / audit). */
decisionId?: string;
/** Which exact constraint denied (projects from
* `LimitDecision.blockingConstraintId`); present on a limit deny when known. */
blockingConstraintId?: string;
/** The recommended client reaction. */
reaction: FsLimitReaction;
/** Envelope schema version. Bumped on a NON-additive envelope change. */
envelopeVersion?: number;
}
Where a limit was decided. Mirrors the contracts `LimitOrigin` (`platform` —
a plan/entitlement limit the platform owns; `provider` — an upstream throttle
the platform relays).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L96.
export type FsLimitOrigin = "platform" | "provider" | "subscriber";
What a client should DO about a limit deny — the recommended reaction.
Mirrors the contracts `LimitReaction`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L99.
export type FsLimitReaction = "none" | "backoff_retry" | "wait_then_retry" | "queue" | "reduce_then_retry" | "fallback" | "upgrade";
An `fs.fetch` secure-fetch deny code (see {@link FS_SECURE_FETCH_ERROR_CODES}).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L666.
export type FsSecureFetchErrorCode = (typeof FS_SECURE_FETCH_ERROR_CODES)[keyof typeof FS_SECURE_FETCH_ERROR_CODES];
True when an error is the transient `BILLING_NOT_CONFIGURED` onboarding state
— a {@link FartherShoreBillingNotConfiguredError} (or any
{@link FartherShoreApiError} carrying that `code`). A consumer can show a
"setting up — retry" state instead of failing. Pure; safe on any value.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L517.
export declare function isBillingNotConfigured(err: unknown): boolean;
True when an error should be retried after a backoff.
T10 — when a deny carries an `_fs` envelope, that envelope is AUTHORITATIVE:
the retry decision is driven by `_fs.reaction` / `_fs.retrySafe`, NEVER by raw
status-code inference. This holds for KNOWN and UNKNOWN (T13) limit classes
alike — a future class relayed on a 429 is retried only if its reaction
explicitly says so. So a non-retry-safe deny that happens to land on a
transient status (a `spend`/`upgrade` reaction on a 429) is NOT retried, and
an unknown-class deny with `reaction:"none"` is NOT retried despite the
transient status.
Without an `_fs` envelope the legacy TRANSIENT heuristics apply (config.ts
JSDoc: "429 + transient 502/503/504 + network faults"):
- a {@link FartherShoreNetworkError} (DNS/connection/CORS — a fresh attempt
may connect);
- any {@link FartherShoreApiError} at a transient status (429/502/503/504),
REGARDLESS of deny code — a plain 503 with `code:"unknown"` retries too;
- any {@link FartherShoreApiError} whose `code` is in the canonical
retryable deny set (the named throttle/dependency denies).
Pure; safe to call on any caught value. (Aborts are handled separately in the
retry loop and never reach here as retryable.)
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L701.
export declare function isRetryable(err: unknown): boolean;
True when an error is specifically a rate-limit/throttle the caller should
back off on — a {@link FartherShoreRateLimitedError} or any
{@link FartherShoreApiError} at status `429`. Pure.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L705.
export declare function isThrottled(err: unknown): boolean;
The machine-readable limit descriptor the gateway/core attach to a limit
deny body (`{ error: { code, message, limitCode, dimension, currentCapacity } }`).
The SDK turns this into an upgrade prompt — see {@link LimitExceededError}.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L85.
export interface LimitDescriptor {
/** Stable identifier for the limit that was hit, e.g. `resource:widgets`. */
limitCode: string;
/** The metered/resource dimension, when known (e.g. `widgets`, `requests`). */
dimension: string | null;
/** The cap the subscriber is at, when known. */
currentCapacity: number | null;
}
A {@link FartherShoreApiError} that is specifically a plan-limit block — a
resource quota (`402 resource_count_limit_exceeded`), a usage quota, a rate
limit, or a credit cap. Carries the {@link LimitDescriptor} so the app can
resolve an upgrade target from the bootstrap catalog and prompt the user
(see `useUpgrade` / `<UpgradePrompt>`).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L206.
export declare class LimitExceededError extends FartherShoreApiError {
readonly limitCode: string;
readonly dimension: string | null;
readonly currentCapacity: number | null;
/** The semantic {@link FsLimitClass} of this limit — derived from the `_fs`
* envelope when present, else from the wire code + limitCode + status
* ({@link classifyFsLimit}). null only when nothing classifies it. */
readonly limitClass: FsLimitClass__2d5726601b87 | null;
/** The parsed `_fs` deny envelope, when the body carried one. The richer
* source for the reaction/headroom fields below. */
readonly envelope: FsDenyEnvelope | null;
/** True when retrying the SAME request can succeed (a velocity/transient cap);
* false when it never will (a spend cap / oversized request). */
readonly retrySafe: boolean;
/** True when the caller must MODIFY the request before it can succeed (a
* `capacity` ceiling or `spend` cap). */
readonly mustModify: boolean;
/** The recommended client reaction. */
readonly reaction: FsLimitReaction;
/** Whether the platform or an upstream provider decided the limit. */
readonly limitOrigin: FsLimitOrigin;
/** The gateway decision id (correlates with the usage event / audit), when
* the `_fs` envelope carried one. */
readonly decisionId: string | null;
/** When the limit window resets, when known (from the `_fs` envelope `reset`,
* unix-epoch ms, else the `X-RateLimit-Reset` snapshot). */
readonly reset: Date | null;
/** Units remaining in the window at decision time, when known. */
readonly remaining: number | null;
/** Units already consumed in the window at decision time, when known. */
readonly used: number | null;
/** The cap value hit, when known. */
readonly limit: number | null;
constructor(status: number, code: string, message: string, body: unknown, descriptor: LimitDescriptor, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
The fully-resolved facet of a limit deny — the single object a UI branches on.
Composes the semantic {@link FsLimitClass} with the REQUEST LIFECYCLE
(retry-safe? must the request be modified? can a plan change resolve it?) and
the HEADROOM (remaining/used/limit/reset) the deny reported.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L531.
export interface LimitFacet {
/** The semantic class — the primary axis a UI branches on. */
limitClass: FsLimitClass__2d5726601b87;
/** The recommended client reaction (from the `_fs` envelope, else a
* per-class default). */
reaction: FsLimitReaction;
/** Whether the platform or an upstream provider decided the limit. */
limitOrigin: FsLimitOrigin;
/** True when retrying the SAME request can succeed (rate/concurrency/adaptive
* are retry-safe; quota/spend/capacity are not). */
retrySafe: boolean;
/** True when the caller must MODIFY the request (capacity) or change the plan
* (spend) before it can succeed. */
mustModify: boolean;
/** True ONLY for the upgrade-affording classes (`quota` / `spend`). Drives
* whether a UI mounts the upgrade prompt — capacity's "bigger model"
* is a SEPARATE affordance, NOT an upgrade. */
canUpgrade: boolean;
/** When the limit window resets, when known. */
reset: Date | null;
/** Units remaining in the window at decision time, when known. */
remaining: number | null;
/** Units already consumed, when known. */
used: number | null;
/** The cap value hit, when known. */
limit: number | null;
/** The gateway decision id, when known. */
decisionId: string | null;
}
Build the right API error for a non-2xx response, minted on the platform's
canonical deny vocabulary so callers can `catch` the specific subclass:
- {@link LimitExceededError} (and its 413/spend subclasses
{@link RequestTooLargeError} / {@link SpendLimitError}) — the body carries
a limit descriptor on a limit status (`isDenyLimitStatus` ≡ contracts
DENY_LIMIT_STATUSES = 402/403/413/429). The most specific/actionable case
wins (a descriptor-bearing 429 stays a LimitExceededError).
- {@link ConcurrencyLimitError} (429 customer wait-for-slot, T7) /
{@link AdaptiveThrottleError} (503 provider relay) — the two retryable
throttle subclasses, dispatched off `concurrency_limit_exceeded` /
`provider_throttled` regardless of whether a descriptor is present.
- {@link FartherShoreLifecycleBlockedError} — a lifecycle-block deny
(`subscription_inactive`); carries a restore-vs-billing-portal suggestion.
- {@link FartherShoreSubscriptionConflictError} — `409` + `INVALID_STATE`
(the onboarding "already subscribed — restore it" path).
- {@link FartherShoreBillingNotConfiguredError} — `BILLING_NOT_CONFIGURED`
(the transient "billing is being set up, retry" onboarding state).
- {@link FartherShoreRateLimitedError} — a retryable/throttle deny code OR
status `429`. The 503-FAMILY does NOT mint a LimitExceededError; the
transient 503 throttles surface here as retryable instead.
- {@link FartherShoreApiError} — everything else.
Header-derived throttle hints (`Retry-After`, `X-RateLimit-*`) are parsed once
and threaded onto whichever class is minted. Used at the single non-2xx throw
site for each transport so core + gateway surface errors uniformly. `headers`
is optional so legacy callers still compile (hints default to null).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L643.
export declare function makeApiError(status: number, code: string, message: string, body: unknown, headers?: Headers | null): FartherShoreApiError;
Map a gateway secret-inject wire `code` onto the stable {@link * FsSecureFetchErrorCode}, or null when the wire code is not a secure-fetch
deny (leave the code untouched — a limit/throttle deny still classifies via
its own path). The `upstream_` PREFIX is matched so every SSRF-forwarder
refusal (`upstream_unreachable`, `upstream_not_https`, `upstream_blocked_host`,
`upstream_redirect_refused`, `upstream_invalid_url`, `upstream_timeout`, …)
collapses to one `UPSTREAM_ERROR` a builder can catch. Pure.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L676.
export declare function mapSecureFetchErrorCode(code: string): FsSecureFetchErrorCode | null;
A5-amend (T11) — a snapshot of a single OBSERVED limit/throttle deny, captured
as it leaves the transport. The ADVISORY input to `useLimitStatus()`: the
freshest known RECENT deny (NOT a live poll — the gateway stays authoritative).
Provider-neutral; forward-compat (an unknown future class keeps `limitClass`
null + the raw value on `unknownLimitClass`, never crashing — T13).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L580.
export interface ObservedLimitDeny {
/** The semantic class, or null for an UNKNOWN/future class (T13). */
limitClass: FsLimitClass__2d5726601b87 | null;
/** The raw `limitClass` string when it is outside the closed mirror (T13). */
unknownLimitClass?: string;
/** The recommended client reaction. */
reaction: FsLimitReaction;
/** Whether the platform or an upstream provider decided the deny. */
limitOrigin: FsLimitOrigin;
/** The provider-supplied reason verbatim, when this relayed an upstream
* throttle (an adaptive deny). */
providerReason: string | null;
/** When the limit window resets, when known. */
reset: Date | null;
/** Units remaining in the window at decision time, when known. */
remaining: number | null;
/** The cap value hit, when known. */
limit: number | null;
/** The HTTP status of the deny. */
status: number;
/** The wire `code` of the deny. */
code: string;
/** The gateway decision id, when known. */
decisionId: string | null;
/** Wall-clock instant (epoch ms) the deny was observed — drives staleness. */
observedAt: number;
}
Parse the `_fs` deny envelope off a deny body, or null when absent/invalid.
Reads the block under the `_fs` key (the gateway/core stamp it there).
FORWARD-COMPAT (T13): the closed {@link FsLimitClass} mirror can lag contracts
by a release, so a deny carrying a `limitClass` this bundle does NOT know must
NOT be discarded — that would silently drop the reaction/origin/headroom
signal a forward-compat client needs. Instead the typed `limitClass` is set to
`null`, the raw value is preserved on `unknownLimitClass`, and the whole `_fs`
block is preserved on `raw`. A `reaction` outside the closed set degrades to
`none` (never auto-retry on an unknown intent). The ONLY hard requirement to
recognize an envelope is a string `limitClass` present — everything else is
best-effort. Pure; safe on any value.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L188.
export declare function parseFsDenyEnvelope(body: unknown): FsDenyEnvelope | null;
Extract a {@link LimitDescriptor} from a deny body, or null if absent.
Handles both shapes: nested `{ error: { limitCode, … } }` (core resource
limits, proxied raw through the gateway) and flat `{ error, code, limitCode,
… }` (gateway compute limits — quota/rate-limit).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L524.
export declare function parseLimitDescriptor(body: unknown): LimitDescriptor | null;
Parse the gateway's `X-RateLimit-Remaining` / `X-RateLimit-Reset` headers
into a {@link RateLimitSnapshot}, or null when neither is present. Pure +
SSR-safe (no `window`).
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L22.
export declare function parseRateLimit(headers: Headers | null): RateLimitSnapshot | null;
Parse a `Retry-After` header value to seconds. Supports the two RFC forms —
a non-negative integer ("120") and an HTTP-date — and returns null for a
missing/unparseable value or a date in the past. Pure + SSR-safe.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L18.
export declare function parseRetryAfterSeconds(value: string | null): number | null;
A {@link FartherShoreApiError} for a Managed-RBAC permission deny — the
gateway's `permission` constraint denied the request (`403
permission_denied`) because the credential's permission claim did not
satisfy the matched route's required `<subject>:<verb>`. `.permission`
carries the missing permission (when the deny envelope names it) so an app
can tell the user EXACTLY what they lack and offer a request-access flow.
This is the RBAC axis: a permission deny is about WHO you are, not WHAT plan
you're on, so it never routes to an upsell.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L354.
export declare class PermissionDeniedError extends FartherShoreApiError {
/** The missing `<subject>:<verb>` permission, or null when the deny
* envelope didn't name it. */
readonly permission: string | null;
constructor(status: number, code: string, message: string, body: unknown, permission: string | null, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreRateLimitedError} subclass for a throttle the platform is
RELAYING from an upstream PROVIDER (`.limitOrigin === "provider"`) — the cap
is the provider's, not a plan limit, so the platform can't raise it; the only
affordances are back-off / fallback, never an upgrade. The base class for the
503 adaptive throttle below.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L321.
export declare class ProviderLimitError extends FartherShoreRateLimitedError {
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
Parsed `X-RateLimit-*` snapshot the gateway attaches to throttle responses.
The gateway emits `X-RateLimit-Remaining` + `X-RateLimit-Reset` but NOT
`X-RateLimit-Limit`, so there is deliberately no `limit` field.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L8.
export interface RateLimitSnapshot {
/** Requests left in the current window, or null when the header is absent. */
remaining: number | null;
/** When the window resets, or null when the header is absent. The
* `X-RateLimit-Reset` value is unix-epoch SECONDS. */
resetAt: Date | null;
}
A subscriber-facing remediation a blocked request points the user toward.
`restore` lifts a scheduled/active cancellation (no new payment); `billing-portal`
opens the Stripe Customer Portal to fix a failed/expired payment method.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L423.
export type RemediationAction = "restore" | "billing-portal";
A {@link LimitExceededError} subclass for a `413 request_too_large` — the
per-request CAPACITY ceiling (payload/token footprint exceeds a per-request
cap). `instanceof LimitExceededError` STILL holds (it IS a limit affordance),
but the reaction is `mustModify` (`reduce_then_retry`): retrying the same
bytes never helps, so it must NOT drive an upgrade prompt. `.limitClass` is
`capacity`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L258.
export declare class RequestTooLargeError extends LimitExceededError {
constructor(status: number, code: string, message: string, body: unknown, descriptor: LimitDescriptor, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
Which SUBJECT KIND a route requires — the consumer-principal (D2) axis. A
`member` route wants a person's credential (a user session or a PERSONAL
key); a `service` route wants an org-owned service-account key.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L363.
export type RequiredSubjectKind = "member" | "service";
A {@link LimitExceededError} subclass for a `402` SPEND cap — a monetary
ceiling (available funding / spend cap) was hit. `instanceof LimitExceededError`
STILL holds (it is an upgrade affordance — `resolveUpgrade` offers a higher
plan). `.limitClass` is `spend`.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L267.
export declare class SpendLimitError extends LimitExceededError {
constructor(status: number, code: string, message: string, body: unknown, descriptor: LimitDescriptor, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreApiError} for a route SUBJECT-KIND requirement deny — the
gateway rejected the request (`403 member_subject_required` /
`service_subject_required`) because the route declares `requireMember()` /
`requireService()` and the resolved principal was the wrong kind. `.required`
tells you which kind the route wants, so a portal can render the fix in a word
("this action needs a personal key" / "…a service-account key") WITHOUT
string-matching the raw envelope.
Distinct from {@link PermissionDeniedError}: that is about WHICH permission you
lack (the RBAC verb axis); this is about WHAT KIND of credential you presented
(the subject axis). A member calling a service-only route isn't missing a
permission — they're using the wrong kind of key, so the remedy is switching
credentials, never an upsell or an access request.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L394.
export declare class SubjectRequiredError extends FartherShoreApiError {
/** The subject kind the route requires (`member` | `service`). */
readonly required: RequiredSubjectKind;
constructor(status: number, code: string, message: string, body: unknown, required: RequiredSubjectKind, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
A {@link FartherShoreApiError} for a route surface deny — the
gateway rejected the request (`403 surface_not_allowed`) because the
route's `surfaces` excludes the caller's surface. This is not a missing
permission: the remedy is using a surface the route exposes, not an upsell or
access request. A hidden route returns a plain 404 instead.
Declaration source: packages/farthershore-js/dist/errors/index.d.ts#L417.
export declare class SurfaceNotAllowedError extends FartherShoreApiError {
constructor(status: number, code: string, message: string, body: unknown, retryAfterSeconds?: number | null, rateLimit?: RateLimitSnapshot | null);
}
These declarations explain types reachable from the public exports above. They are source evidence, not supported package imports. Suffixed names are documentation identifiers that preserve distinct lexical bindings. Standard-library and third-party types (for example Promise, React and Zod) remain external boundaries; their implementation declarations are not expanded here.
Declaration source: packages/farthershore-js/dist/deny-codes.d.ts#L63.
declare const FS_LIMIT_CLASSES__cf69b28be276: readonly ["quota", "rate", "concurrency", "capacity", "spend", "adaptive"];
Declaration source: packages/farthershore-js/dist/deny-codes.d.ts#L65.
export type FsLimitClass__2d5726601b87 = (typeof FS_LIMIT_CLASSES__cf69b28be276)[number];