{"version":3,"file":"resource-client--yYybltk.mjs","names":["#window","#lastAllowedAt","#chains","#pendingGates","#sleep","#trackers","ignoreRejection","#gateOnce","#tracker","#waitAsync","#hooks","#intervalMs","#maxBucketLevel","#sleep","#pendingAcquisitions","#waitForToken","#chain","#waitAsync","#bucketLevel","#lastCheck","#budgets","#config","#hooks","#httpClient","#queues","#sleep","#dispatchAsync","#getQueue","#gatedSend"],"sources":["../src/internal/utils/is-date-time-string.ts","../src/internal/utils/is-record.ts","../src/internal/utils/to-json-details.ts","../src/internal/http/admission-wait.ts","../src/internal/http/budget-tracker.ts","../src/internal/http/request-deadline.ts","../src/internal/http/budget-gate.ts","../src/internal/http/execute.ts","../src/internal/http/rate-limit-observation.ts","../src/internal/http/rate-limit-queue.ts","../src/internal/utils/sleep.ts","../src/internal/http/resolve-dependencies.ts","../src/internal/resource-client.ts"],"sourcesContent":["/**\n * Narrows `value` to a string that parses to a real {@link Date} via the\n * `Date(string)` constructor. Used by resource parsers to gate\n * `format: date-time` wire fields before handing them to `new Date(...)`,\n * which silently produces an `Invalid Date` for invalid input.\n *\n * @param value - The unknown wire value to validate.\n * @returns `true` when `value` is a string and `new Date(value).getTime()`\n *   is not `NaN`.\n */\nexport function isDateTimeString(value: unknown): value is string {\n\tif (typeof value !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst parsed = new Date(value);\n\treturn !Number.isNaN(parsed.getTime());\n}\n","/**\n * Narrows `value` to a plain JSON-style record. Excludes arrays, class\n * instances, primitives, and `null`/`undefined`. Used by resource\n * parsers to gate property access on wire bodies whose shape isn't\n * known at compile time.\n *\n * @param value - The unknown value to narrow.\n * @returns `true` when `value` is a plain `[object Object]`.\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Object.prototype.toString.call(value) === \"[object Object]\";\n}\n","import { isRecord } from \"./is-record.ts\";\n\n/**\n * Narrows an untyped response body to the `JSONValue` accepted by\n * `ApiError.details`. `HttpResponse.body` is `unknown` because a transport may\n * hand back anything, but only a JSON graph is safe to retain on an error for\n * diagnostics. Anything else — functions, symbols, bigints, class instances,\n * or a cyclic graph — is dropped rather than asserted through.\n *\n * @param value - The parsed response body, or `undefined` for an empty body.\n * @returns The value as a `JSONValue`, or `undefined` when it is absent or not\n *   JSON-representable.\n */\nexport function toJsonDetails(value: unknown): JSONValue | undefined {\n\treturn asJsonValue(value, new Set());\n}\n\nfunction asJsonValue(value: unknown, seen: Set<object>): JSONValue | undefined {\n\tif (value === null) {\n\t\t// eslint-disable-next-line unicorn/no-null -- JSON null is a JSONValue; the repo's undefined-only rule stops at this wire boundary\n\t\treturn null;\n\t}\n\n\tif (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n\t\treturn value;\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn asJsonArray(value, seen);\n\t}\n\n\tif (isRecord(value)) {\n\t\treturn asJsonObject(value, seen);\n\t}\n\n\treturn undefined;\n}\n\nfunction asJsonArray(value: ReadonlyArray<unknown>, seen: Set<object>): JSONValue | undefined {\n\tif (seen.has(value)) {\n\t\treturn undefined;\n\t}\n\n\tseen.add(value);\n\tconst items: Array<JSONValue> = [];\n\tfor (const item of value) {\n\t\tconst converted = asJsonValue(item, seen);\n\t\tif (converted === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\titems.push(converted);\n\t}\n\n\tseen.delete(value);\n\treturn items;\n}\n\nfunction asJsonObject(value: Record<string, unknown>, seen: Set<object>): JSONValue | undefined {\n\tif (seen.has(value)) {\n\t\treturn undefined;\n\t}\n\n\tseen.add(value);\n\tconst entries: Array<[string, JSONValue]> = [];\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tconst converted = asJsonValue(item, seen);\n\t\tif (converted === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tentries.push([key, converted]);\n\t}\n\n\tseen.delete(value);\n\treturn Object.fromEntries(entries);\n}\n","import type {\n\tAdmissionWaitEvent,\n\tAdmissionWaitObserver,\n\tAdmissionWaitReason,\n} from \"../../client/types.ts\";\n\n/** Request-local controls shared by SDK admission mechanisms. */\nexport interface AdmissionWaitContext {\n\t/**\n\t * Absolute deadline for the logical request, as Unix epoch milliseconds.\n\t */\n\treadonly deadlineMs?: number | undefined;\n\t/** Observer for this request's admission waits. */\n\treadonly observer?: AdmissionWaitObserver | undefined;\n\t/** Optional caller cancellation signal. */\n\treadonly signal?: AbortSignal | undefined;\n}\n\ninterface ObserveAdmissionWaitOptions<T> {\n\t/** Intended wait duration, when the scheduler can determine one. */\n\treadonly durationMs?: number;\n\t/** Request-scoped notification callback. */\n\treadonly observer?: AdmissionWaitObserver | undefined;\n\t/** SDK admission mechanism responsible for the wait. */\n\treadonly reason: AdmissionWaitReason;\n\t/** The actual wait to perform. */\n\treadonly waitAsync: () => Promise<T>;\n}\n\n/**\n * Performs one SDK-managed wait and emits a balanced request-scoped lifecycle.\n * Observer failures are deliberately ignored: observation cannot become part\n * of admission control.\n *\n * @template T - Value produced by the observed wait.\n * @param options - Wait metadata, observer, and the wait operation itself.\n * @returns The value produced by the wait.\n */\nexport async function observeAdmissionWaitAsync<T>({\n\tdurationMs,\n\tobserver,\n\treason,\n\twaitAsync,\n}: ObserveAdmissionWaitOptions<T>): Promise<T> {\n\tconst details = {\n\t\t...(durationMs === undefined ? {} : { durationMs }),\n\t\treason,\n\t};\n\tnotify(observer, { ...details, phase: \"started\" });\n\ttry {\n\t\treturn await waitAsync();\n\t} finally {\n\t\tnotify(observer, { ...details, phase: \"ended\" });\n\t}\n}\n\nfunction notify(observer: AdmissionWaitObserver | undefined, event: AdmissionWaitEvent): void {\n\ttry {\n\t\tconst notification = observer?.(event);\n\t\tif (notification !== undefined) {\n\t\t\t// `Boolean` consumes every rejection without throwing; the returned\n\t\t\t// promise and its boolean fulfillment are deliberately ignored.\n\t\t\tvoid Promise.resolve(notification).catch(Boolean);\n\t\t}\n\t} catch {\n\t\t// Admission observers are notification-only and cannot alter control\n\t\t// flow.\n\t}\n}\n","import type { RateLimitSample } from \"./rate-limit-sample.ts\";\n\nconst MS_PER_SECOND = 1000;\n\n/** Live window state for one scope: budget left and when it resets. */\ninterface WindowState {\n\t/** Best estimate of requests still allowed before the window resets. */\n\treadonly predictedRemaining: number;\n\t/** Absolute time (ms) the window resets to full. */\n\treadonly resetAt: number;\n}\n\n/**\n * Tracks the live rate-limit budget for a single scope. Primed by `observe`\n * from response headers and drawn down by `reserve` as requests leave, so\n * `waitMs` can pace requests across the window.\n *\n * Pacing has two regimes. While budget remains, requests are spread evenly over\n * the time left in the window (`timeLeft / remaining`), so a burst does not\n * spend the whole window's budget up front and then stall. Once the budget is\n * spent, requests hold until the window resets. Budget and reset time move\n * together as one window, so the tracker is either unprimed or fully primed,\n * never half-known.\n */\nexport class BudgetTracker {\n\t/** Time (ms) the most recent request was allowed out, for spacing. */\n\t#lastAllowedAt: number | undefined = undefined;\n\t#window: undefined | WindowState = undefined;\n\n\t/**\n\t * Folds a fresh server reading in, replacing any prior window. The latest\n\t * reading wins: observe time is monotonic, so the most recently resolved\n\t * response is the best current estimate. The spacing reference is left\n\t * untouched so a window refresh does not reset pacing mid-stream.\n\t *\n\t * @param sample - Parsed `remaining`/`resetSeconds` from a response.\n\t * @param now - The current time in ms.\n\t */\n\tpublic observe(sample: RateLimitSample, now: number): void {\n\t\tthis.#window = {\n\t\t\tpredictedRemaining: sample.remaining,\n\t\t\tresetAt: now + sample.resetSeconds * MS_PER_SECOND,\n\t\t};\n\t}\n\n\t/**\n\t * Accounts for one request leaving at `now`: records the spacing reference\n\t * and decrements the prediction. A no-op on the prediction while unprimed.\n\t *\n\t * @param now - The time the request was allowed out, in ms.\n\t */\n\tpublic reserve(now: number): void {\n\t\tthis.#lastAllowedAt = now;\n\t\tif (this.#window !== undefined) {\n\t\t\tthis.#window = {\n\t\t\t\t...this.#window,\n\t\t\t\tpredictedRemaining: this.#window.predictedRemaining - 1,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Milliseconds to wait before the next request is allowed.\n\t *\n\t * @param now - The current time in ms.\n\t * @returns `0` when a request may go now (unprimed, or the first paced send);\n\t *   the time until reset when the budget is spent; otherwise the time until\n\t *   this request's evenly-spaced slot.\n\t */\n\tpublic waitMs(now: number): number {\n\t\tif (this.#window === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst { predictedRemaining, resetAt } = this.#window;\n\t\tif (predictedRemaining <= 0) {\n\t\t\treturn Math.max(0, resetAt - now);\n\t\t}\n\n\t\tif (this.#lastAllowedAt === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst interval = (resetAt - now) / predictedRemaining;\n\t\treturn Math.max(0, this.#lastAllowedAt + interval - now);\n\t}\n}\n","import type { AdmissionWaitReason } from \"../../client/types.ts\";\nimport type { OpenCloudError } from \"../../errors/base.ts\";\nimport { RequestAbortedError } from \"../../errors/request-aborted.ts\";\nimport {\n\tRequestDeadlineExceededError,\n\ttype RequestDeadlineExceededErrorOptions,\n} from \"../../errors/request-deadline-exceeded.ts\";\n\nconst DEADLINE_ELAPSED = Symbol(\"request deadline elapsed\");\nconst MAX_ABORT_TIMEOUT_MS = 2_147_483_647;\n\n/**\n * Request-lifecycle signals derived from caller cancellation and a deadline.\n */\nexport interface RequestLifecycle {\n\t/** Caller-supplied absolute deadline, as Unix epoch milliseconds. */\n\treadonly deadlineMs: number | undefined;\n\t/** Signal owned by the deadline, used to classify its expiry. */\n\treadonly deadlineSignal: AbortSignal | undefined;\n\t/** Caller and deadline signals composed for every stage of the request. */\n\treadonly signal: AbortSignal | undefined;\n}\n\ninterface WaitDeadlineInputs {\n\treadonly cause?: Error | undefined;\n\treadonly deadlineMs: number | undefined;\n\treadonly waitMs: number;\n\treadonly waitReason: AdmissionWaitReason;\n}\n\n/**\n * Resolves one signal that spans the whole logical request.\n *\n * @param deadlineMs - Absolute deadline, as Unix epoch milliseconds.\n * @param callerSignal - Optional caller cancellation signal.\n * @returns Signals that span and classify the logical request.\n */\nexport function requestLifecycle(\n\tdeadlineMs: number | undefined,\n\tcallerSignal: AbortSignal | undefined,\n): RequestLifecycle {\n\tif (deadlineMs === undefined) {\n\t\treturn { deadlineMs, deadlineSignal: undefined, signal: callerSignal };\n\t}\n\n\tconst deadlineSignal = deadlineTimeout(deadlineMs);\n\tconst signal =\n\t\tcallerSignal === undefined\n\t\t\t? deadlineSignal\n\t\t\t: AbortSignal.any([callerSignal, deadlineSignal]);\n\treturn { deadlineMs, deadlineSignal, signal };\n}\n\n/**\n * Returns a typed failure when the deadline signal ended the request.\n *\n * @param lifecycle - Signals and timestamp for the logical request.\n * @returns A deadline failure, or `undefined` when another signal won.\n */\nexport function elapsedDeadlineFailure({\n\tdeadlineMs,\n\tdeadlineSignal,\n\tsignal,\n}: RequestLifecycle): RequestDeadlineExceededError | undefined {\n\tif (\n\t\tdeadlineMs === undefined ||\n\t\tdeadlineSignal?.aborted !== true ||\n\t\t!Object.is(signal?.reason, deadlineSignal.reason)\n\t) {\n\t\treturn undefined;\n\t}\n\n\treturn new RequestDeadlineExceededError(\"Request deadline elapsed\", {\n\t\tdeadlineMs,\n\t\tremainingMs: 0,\n\t});\n}\n\n/**\n * Reclassifies an internal abort when the request deadline supplied its signal.\n *\n * @param error - Error returned by the request pipeline.\n * @param lifecycle - Signals and timestamp for the logical request.\n * @returns A deadline failure, or `undefined` for other failures.\n */\nexport function deadlineFailureFromError(\n\terror: OpenCloudError,\n\tlifecycle: RequestLifecycle,\n): RequestDeadlineExceededError | undefined {\n\treturn error instanceof RequestAbortedError ? elapsedDeadlineFailure(lifecycle) : undefined;\n}\n\n/**\n * Refuses a known admission wait that cannot fit before the deadline.\n *\n * @param inputs - Deadline, wait duration, reason, and optional cause.\n * @returns A typed refusal, or `undefined` when the wait fits.\n */\nexport function waitDeadlineFailure({\n\tcause,\n\tdeadlineMs,\n\twaitMs,\n\twaitReason,\n}: WaitDeadlineInputs): RequestDeadlineExceededError | undefined {\n\tif (deadlineMs === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst now = Date.now();\n\tconst remainingMs = Math.max(0, deadlineMs - now);\n\tif (now < deadlineMs && waitMs <= remainingMs) {\n\t\treturn undefined;\n\t}\n\n\tconst options: RequestDeadlineExceededErrorOptions = {\n\t\tcause,\n\t\tdeadlineMs,\n\t\tremainingMs,\n\t\twaitMs,\n\t\twaitReason,\n\t};\n\treturn new RequestDeadlineExceededError(waitMessage(waitMs, remainingMs), options);\n}\n\nfunction armDeadlineTimeout(controller: AbortController, deadlineMs: number): void {\n\tconst remainingMs = deadlineMs - Date.now();\n\tif (remainingMs <= 0) {\n\t\tcontroller.abort(DEADLINE_ELAPSED);\n\t\treturn;\n\t}\n\n\tconst timeout = AbortSignal.timeout(Math.min(Math.ceil(remainingMs), MAX_ABORT_TIMEOUT_MS));\n\ttimeout.addEventListener(\"abort\", () => {\n\t\tarmDeadlineTimeout(controller, deadlineMs);\n\t});\n}\n\nfunction deadlineTimeout(deadlineMs: number): AbortSignal {\n\tconst controller = new AbortController();\n\tif (Number.isFinite(deadlineMs)) {\n\t\tarmDeadlineTimeout(controller, deadlineMs);\n\t} else {\n\t\tcontroller.abort(DEADLINE_ELAPSED);\n\t}\n\n\treturn controller.signal;\n}\n\nfunction waitMessage(waitMs: number, remainingMs: number): string {\n\treturn `Admission wait would take ${waitMs / 1000}s; ${remainingMs / 1000}s remain before the request deadline`;\n}\n","import { ABORTED, raceWithAbortAsync, requestAbortedError } from \"../utils/abort.ts\";\nimport type { SleepFunc } from \"../utils/sleep.ts\";\nimport { type AdmissionWaitContext, observeAdmissionWaitAsync } from \"./admission-wait.ts\";\nimport { BudgetTracker } from \"./budget-tracker.ts\";\nimport type { RateLimitSample } from \"./rate-limit-sample.ts\";\nimport { waitDeadlineFailure } from \"./request-deadline.ts\";\n\nconst REPORTED_BUDGET_REASON = \"reported-budget\";\n\n/**\n * Identifies the rate-limit bucket one request draws on: Roblox meters each\n * operation in its own per-API-key bucket.\n */\nexport interface BudgetScope {\n\t/** The effective API key the request authenticates with. */\n\treadonly apiKey: string;\n\t/** The operation the request belongs to. */\n\treadonly operationKey: string;\n}\n\n/**\n * Header-primed rate-limit gate shared across a client. Holds one\n * {@link BudgetTracker} per {@link BudgetScope}. Before each request the caller\n * gates on the request's scope (sleeping if that budget is spent), and after\n * each response folds the parsed sample back in, so a later call on the same\n * scope can head off a 429 the static per-operation token bucket cannot\n * foresee.\n *\n * Gating is serialized per scope through a promise chain so concurrent\n * requests on one scope cannot read the same budget and reserve the same slot;\n * each waits for the prior gate's reserve before computing its own.\n */\nexport class BudgetGate {\n\treadonly #chains = new Map<string, Promise<void>>();\n\treadonly #pendingGates = new Map<string, number>();\n\treadonly #sleep: SleepFunc;\n\treadonly #trackers = new Map<string, BudgetTracker>();\n\n\t/**\n\t * Creates a gate bound to an injectable sleep.\n\t *\n\t * @param sleep - Injectable sleep (tests pass a fake clock).\n\t */\n\tconstructor(sleep: SleepFunc) {\n\t\tthis.#sleep = sleep;\n\t}\n\n\t/**\n\t * Holds until the scope's budget permits a send, then reserves one slot.\n\t * Runs after the prior gate on the same scope settles, whether it resolved\n\t * or rejected, so one failed attempt cannot poison later gates on the\n\t * scope.\n\t *\n\t * @param scope - The API key and operation to gate on.\n\t * @param context - Request-local observer and cancellation signal.\n\t * @rejects {@link RequestAbortedError} when the caller cancels while waiting.\n\t */\n\tpublic async gateAsync(\n\t\tscope: BudgetScope,\n\t\t{ deadlineMs, observer, signal }: AdmissionWaitContext = {},\n\t): Promise<void> {\n\t\tconst key = scopeKey(scope);\n\t\tconst pendingGates = this.#pendingGates.get(key) ?? 0;\n\t\tconst waitsForEarlierGate = pendingGates > 0;\n\t\tthis.#pendingGates.set(key, pendingGates + 1);\n\t\tconst previous = this.#chains.get(key) ?? Promise.resolve();\n\t\tconst recovered = previous.catch(ignoreRejection);\n\t\tconst mine = recovered.then(async () => {\n\t\t\treturn this.#gateOnce(key, {\n\t\t\t\tdeadlineMs,\n\t\t\t\tobserver: waitsForEarlierGate ? undefined : observer,\n\t\t\t\tsignal,\n\t\t\t});\n\t\t});\n\t\tconst completed = mine.finally(() => {\n\t\t\tconst remainingGates = (this.#pendingGates.get(key) ?? 1) - 1;\n\t\t\tthis.#pendingGates.set(key, remainingGates);\n\t\t});\n\t\tthis.#chains.set(key, completed.catch(ignoreRejection));\n\t\tif (waitsForEarlierGate) {\n\t\t\tawait observeAdmissionWaitAsync({\n\t\t\t\tobserver,\n\t\t\t\treason: REPORTED_BUDGET_REASON,\n\t\t\t\twaitAsync: async () => waitForGateAsync(completed, signal),\n\t\t\t});\n\t\t} else {\n\t\t\tawait waitForGateAsync(completed, signal);\n\t\t}\n\t}\n\n\t/**\n\t * Folds a response's parsed budget back onto the scope. A `undefined`\n\t * sample (headers absent or non-numeric) is ignored, leaving the scope on\n\t * static pacing.\n\t *\n\t * @param scope - The same scope passed to {@link gateAsync}.\n\t * @param sample - Parsed sample, or `undefined` when none was reported.\n\t */\n\tpublic observe(scope: BudgetScope, sample: RateLimitSample | undefined): void {\n\t\tif (sample === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#tracker(scopeKey(scope)).observe(sample, Date.now());\n\t}\n\n\tasync #gateOnce(\n\t\tkey: string,\n\t\t{ deadlineMs, observer, signal }: AdmissionWaitContext,\n\t): Promise<void> {\n\t\tif (signal?.aborted === true) {\n\t\t\tthrow requestAbortedError(signal);\n\t\t}\n\n\t\tconst tracker = this.#tracker(key);\n\t\tconst waitMs = tracker.waitMs(Date.now());\n\t\tif (waitMs > 0) {\n\t\t\tawait this.#waitAsync(waitMs, { deadlineMs, observer, signal });\n\t\t}\n\n\t\ttracker.reserve(Date.now());\n\t}\n\n\t#tracker(key: string): BudgetTracker {\n\t\tconst existing = this.#trackers.get(key);\n\t\tif (existing !== undefined) {\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst tracker = new BudgetTracker();\n\t\tthis.#trackers.set(key, tracker);\n\t\treturn tracker;\n\t}\n\n\tasync #waitAsync(\n\t\twaitMs: number,\n\t\t{ deadlineMs, observer, signal }: AdmissionWaitContext,\n\t): Promise<void> {\n\t\tconst refusal = waitDeadlineFailure({\n\t\t\tdeadlineMs,\n\t\t\twaitMs,\n\t\t\twaitReason: REPORTED_BUDGET_REASON,\n\t\t});\n\t\tif (refusal !== undefined) {\n\t\t\tthrow refusal;\n\t\t}\n\n\t\tawait observeAdmissionWaitAsync({\n\t\t\tdurationMs: waitMs,\n\t\t\tobserver,\n\t\t\treason: REPORTED_BUDGET_REASON,\n\t\t\twaitAsync: async () => {\n\t\t\t\tconst sleepResult = await raceWithAbortAsync(\n\t\t\t\t\tasync () => this.#sleep(waitMs, signal),\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\tif (sleepResult === ABORTED) {\n\t\t\t\t\tthrow requestAbortedError(signal);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction ignoreRejection(): void {\n\t// A failed or cancelled gate must not poison the next caller's chain.\n}\n\nasync function waitForGateAsync(\n\tgate: Promise<void>,\n\tsignal: AbortSignal | undefined,\n): Promise<void> {\n\tconst gateResult = await raceWithAbortAsync(async () => gate, signal);\n\tif (gateResult === ABORTED) {\n\t\tthrow requestAbortedError(signal);\n\t}\n}\n\n/**\n * Composes the map key one budget window is tracked under.\n *\n * @param scope - The API key and operation naming the window.\n * @returns The key for the tracker and chain maps.\n */\nfunction scopeKey({ apiKey, operationKey }: BudgetScope): string {\n\treturn `${apiKey}::${operationKey}`;\n}\n","import type { OpenCloudError } from \"../../errors/base.ts\";\nimport { RetryDelayExceededError } from \"../../errors/retry-delay-exceeded.ts\";\nimport type { Result } from \"../../types.ts\";\nimport { ABORTED, raceWithAbortAsync, requestAbortedError } from \"../utils/abort.ts\";\nimport type { SleepFunc } from \"../utils/sleep.ts\";\nimport { observeAdmissionWaitAsync } from \"./admission-wait.ts\";\nimport { waitDeadlineFailure } from \"./request-deadline.ts\";\nimport { computeRetryWaitMs, type RetryResolvable, shouldRetry } from \"./retry.ts\";\nimport type { AdmissionWaitObserver, HttpRequest, HttpResponse, OpenCloudHooks } from \"./types.ts\";\n\n/** A transport callback: takes a request, returns a classified Result. */\ntype SendFunc = (request: HttpRequest) => Promise<Result<HttpResponse, OpenCloudError>>;\n\ninterface RetryLimit {\n\treadonly cause: OpenCloudError;\n\treadonly deadlineMs: number | undefined;\n\treadonly retryAfterMs: number;\n}\n\ninterface RetryNotification {\n\treadonly attempt: number;\n\treadonly error: OpenCloudError;\n\treadonly hooks: OpenCloudHooks;\n\treadonly waitMs: number;\n}\n\n/**\n * Inputs to {@link executeWithRetryAsync} bundled as an options object to keep\n * the function signature narrow.\n */\ninterface ExecuteOptions {\n\t/** Request-scoped admission-wait observer. */\n\treadonly admissionWaitObserver?: AdmissionWaitObserver | undefined;\n\t/** Fully-resolved retry config (post-merge). */\n\treadonly config: RetryResolvable;\n\t/**\n\t * Absolute deadline for the logical request, as Unix epoch milliseconds.\n\t */\n\treadonly deadlineMs?: number | undefined;\n\t/** Client-level observability hooks. */\n\treadonly hooks: OpenCloudHooks;\n\t/** Transport callback. May be pre-wrapped by a rate-limit queue. */\n\treadonly send: SendFunc;\n\t/** Optional caller cancellation signal. */\n\treadonly signal?: AbortSignal | undefined;\n\t/** Injectable sleep (tests pass a fake). */\n\treadonly sleep: SleepFunc;\n}\n\n/**\n * Retry-aware orchestration loop. Coordinates a single logical request,\n * looping over `options.send` until it succeeds, the error is non-retryable,\n * or `options.config.maxRetries` is exhausted. Fires observability hooks\n * at each transition. Domain- and queue-agnostic: `send` may be any\n * callback, including one wrapped by a rate-limit queue.\n *\n * @param request - The immutable request to send.\n * @param options - The transport callback, resolved config, hooks, and sleep.\n * @returns The first success, or the final error after retries are exhausted.\n */\nexport async function executeWithRetryAsync(\n\trequest: HttpRequest,\n\toptions: ExecuteOptions,\n): Promise<Result<HttpResponse, OpenCloudError>> {\n\tconst { admissionWaitObserver, config, deadlineMs, hooks, signal, sleep } = options;\n\tif (signal?.aborted === true) {\n\t\treturn abortedResult(signal);\n\t}\n\n\tlet result = await attemptAsync(request, options);\n\n\tfor (let retry = 0; retry < config.maxRetries; retry++) {\n\t\tif (result.success || !shouldRetry(result.err, config)) {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst { err } = result;\n\t\tconst waitMs = computeRetryWaitMs(err, { attempt: retry, retryDelay: config.retryDelay });\n\t\tconst refusal = retryRefusal({ cause: err, deadlineMs, retryAfterMs: waitMs });\n\t\tif (refusal !== undefined) {\n\t\t\treturn { err: refusal, success: false };\n\t\t}\n\n\t\tannounceRetry({ attempt: retry + 1, error: err, hooks, waitMs });\n\t\tconst sleepResult = await observeAdmissionWaitAsync({\n\t\t\tdurationMs: waitMs,\n\t\t\tobserver: admissionWaitObserver,\n\t\t\treason: \"retry-delay\",\n\t\t\twaitAsync: async () => raceWithAbortAsync(async () => sleep(waitMs, signal), signal),\n\t\t});\n\t\tif (sleepResult === ABORTED) {\n\t\t\treturn abortedResult(signal);\n\t\t}\n\n\t\tresult = await attemptAsync(request, options);\n\t}\n\n\treturn result;\n}\n\nfunction announceRetry({ attempt, error, hooks, waitMs }: RetryNotification): void {\n\thooks.onRetry?.(attempt, error);\n\thooks.onRateLimit?.(waitMs);\n}\n\nfunction retryRefusal({\n\tcause,\n\tdeadlineMs,\n\tretryAfterMs,\n}: RetryLimit): RetryDelayExceededError | undefined {\n\tif (deadlineMs === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst refusal = waitDeadlineFailure({\n\t\tcause,\n\t\tdeadlineMs,\n\t\twaitMs: retryAfterMs,\n\t\twaitReason: \"retry-delay\",\n\t});\n\tif (refusal === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst { remainingMs } = refusal;\n\treturn new RetryDelayExceededError(\n\t\t`Retry delay would wait ${retryAfterMs / 1000}s; ${remainingMs / 1000}s remain before the request deadline`,\n\t\t{ cause, deadlineMs, remainingMs, retryAfterMs },\n\t);\n}\n\nfunction abortedResult(signal: AbortSignal | undefined): Result<never, OpenCloudError> {\n\treturn { err: requestAbortedError(signal), success: false };\n}\n\nasync function attemptAsync(\n\trequest: HttpRequest,\n\t{ hooks, send, signal }: ExecuteOptions,\n): Promise<Result<HttpResponse, OpenCloudError>> {\n\thooks.onRequest?.(request);\n\tconst attempt = await raceWithAbortAsync(async () => send(request), signal);\n\treturn attempt === ABORTED ? abortedResult(signal) : attempt;\n}\n","import type { OpenCloudError } from \"../../errors/base.ts\";\nimport { hasServerRetryGuidance, RateLimitError } from \"../../errors/rate-limit.ts\";\nimport type { Result } from \"../../types.ts\";\nimport type { RateLimitSample } from \"./rate-limit-sample.ts\";\nimport { parseRateLimitHeaders } from \"./rate-limit-sample.ts\";\nimport type { HttpResponse } from \"./types.ts\";\n\n/**\n * Extracts a {@link RateLimitSample} from a transport result so the budget gate\n * can be fed from every attempt. A 2xx carries the budget in its headers. A 429\n * only primes the gate when it reports zero remaining and valid guidance. This\n * is a conservative scheduling condition, not a semantic classification of the\n * 429. Any other error yields `undefined`.\n *\n * @param result - The classified transport result for one attempt.\n * @returns The parsed sample, or `undefined` when none was reported.\n */\nexport function rateLimitSampleFromResult(\n\tresult: Result<HttpResponse, OpenCloudError>,\n): RateLimitSample | undefined {\n\tif (result.success) {\n\t\treturn parseRateLimitHeaders(result.data.headers);\n\t}\n\n\tconst { err } = result;\n\tif (err instanceof RateLimitError && err.remaining === 0 && hasServerRetryGuidance(err)) {\n\t\treturn { remaining: err.remaining, resetSeconds: err.retryAfterSeconds };\n\t}\n\n\treturn undefined;\n}\n","import { ABORTED, raceWithAbortAsync, requestAbortedError } from \"../utils/abort.ts\";\nimport type { SleepFunc } from \"../utils/sleep.ts\";\nimport { type AdmissionWaitContext, observeAdmissionWaitAsync } from \"./admission-wait.ts\";\nimport { waitDeadlineFailure } from \"./request-deadline.ts\";\nimport type { OpenCloudHooks } from \"./types.ts\";\n\nconst OPERATION_QUEUE_REASON = \"operation-queue\";\n\n/**\n * Identifies and bounds a single Roblox Open Cloud operation for rate\n * limiting, e.g. `{ operationKey: \"game-passes.create\", maxPerSecond: 5 }`.\n */\nexport interface OperationLimit {\n\t/**\n\t * How many requests may be issued back to back before pacing begins,\n\t * as a whole number of requests. Defaults to `max(1, maxPerSecond)`,\n\t * which leaves operations at or above 1/s paced exactly as their\n\t * sustained rate allows while still granting a slower operation one\n\t * request after it has idled. Set this to the allowance the schema\n\t * documents (e.g. 5 per minute) to grant the burst the server permits.\n\t */\n\treadonly burstCapacity?: number;\n\t/** Maximum sustained request rate in requests per second. */\n\treadonly maxPerSecond: number;\n\t/**\n\t * Stable identifier for the operation (e.g. \"game-passes.create\"). Not\n\t * consumed by the queue itself; callers use it to key per-operation\n\t * queues in a registry (see GamePassesClient).\n\t */\n\treadonly operationKey: string;\n}\n\ninterface QueueWait extends AdmissionWaitContext {\n\treadonly now: number;\n\treadonly waitMs: number;\n}\n\n/**\n * Token-bucket rate limiter for a single `(apiKey, operation)` pair. Every\n * call to `acquire` consumes one token; when the bucket is empty the call\n * waits until a token regenerates before invoking the task. Tokens refill at\n * `maxPerSecond` per second, up to the operation's `burstCapacity`.\n *\n * Implemented as a leaky bucket tracking drain debt in ms. `#lastCheck`\n * advances by `waitMs` after every sleep so the algorithm stays correct\n * whether or not the injected sleep moves `Date.now()` forward. `#bucketLevel`\n * and `#maxBucketLevel` are both ms of drain debt, so the ceiling is the burst\n * expressed in that unit: `burstCapacity` refill intervals. Deriving it any\n * other way (notably `maxPerSecond * intervalMs`, whose units cancel to a\n * constant 1000) starves every operation slower than one request per second.\n */\nexport class RateLimitQueue {\n\treadonly #hooks: OpenCloudHooks;\n\treadonly #intervalMs: number;\n\treadonly #maxBucketLevel: number;\n\treadonly #sleep: SleepFunc;\n\n\t#bucketLevel = 0;\n\t#chain: Promise<void> = Promise.resolve();\n\t#lastCheck: number = Date.now();\n\t#pendingAcquisitions = 0;\n\n\t/**\n\t * Creates a rate-limit queue bound to a single operation.\n\t *\n\t * @param limit - The operation key and its per-second request ceiling.\n\t * @param hooks - Observability callbacks; `onRateLimit` fires when the\n\t *   bucket is empty and a sleep is about to start.\n\t * @param sleep - Injectable sleep (tests pass a fake).\n\t */\n\tconstructor(limit: OperationLimit, hooks: OpenCloudHooks, sleep: SleepFunc) {\n\t\tthis.#intervalMs = 1000 / limit.maxPerSecond;\n\t\tconst burstCapacity = limit.burstCapacity ?? Math.max(1, limit.maxPerSecond);\n\t\tthis.#maxBucketLevel = burstCapacity * this.#intervalMs;\n\t\tthis.#hooks = hooks;\n\t\tthis.#sleep = sleep;\n\t}\n\n\t/**\n\t * Waits for a token — sleeping and firing `hooks.onRateLimit` if the\n\t * bucket is empty — then executes `task`. Concurrent callers are\n\t * serialized at token acquisition; tasks themselves run independently\n\t * once their token is secured.\n\t *\n\t * @param task - The request to run once a token is available.\n\t * @param context - Request-local observer and cancellation signal.\n\t * @returns The value produced by `task`.\n\t * @rejects {@link RequestAbortedError} when the caller cancels while queued.\n\t */\n\tpublic async acquireAsync<T>(\n\t\ttask: () => Promise<T>,\n\t\t{ deadlineMs, observer, signal }: AdmissionWaitContext = {},\n\t): Promise<T> {\n\t\tconst waitsForEarlierAcquisition = this.#pendingAcquisitions > 0;\n\t\tthis.#pendingAcquisitions++;\n\t\tconst waitForTokenAsync = async (): Promise<void> => {\n\t\t\treturn this.#waitForToken({\n\t\t\t\tdeadlineMs,\n\t\t\t\tobserver: waitsForEarlierAcquisition ? undefined : observer,\n\t\t\t\tsignal,\n\t\t\t});\n\t\t};\n\n\t\tconst myTurn = this.#chain.catch(ignoreRejection).then(waitForTokenAsync);\n\t\tconst completed = myTurn.finally(() => {\n\t\t\tthis.#pendingAcquisitions--;\n\t\t});\n\t\tthis.#chain = completed.catch(ignoreRejection);\n\t\tif (waitsForEarlierAcquisition) {\n\t\t\tawait observeAdmissionWaitAsync({\n\t\t\t\tobserver,\n\t\t\t\treason: OPERATION_QUEUE_REASON,\n\t\t\t\twaitAsync: async () => waitForTurnAsync(completed, signal),\n\t\t\t});\n\t\t} else {\n\t\t\tawait waitForTurnAsync(completed, signal);\n\t\t}\n\n\t\treturn task();\n\t}\n\n\tasync #waitAsync({ deadlineMs, now, observer, signal, waitMs }: QueueWait): Promise<void> {\n\t\tconst refusal = waitDeadlineFailure({\n\t\t\tdeadlineMs,\n\t\t\twaitMs,\n\t\t\twaitReason: OPERATION_QUEUE_REASON,\n\t\t});\n\t\tif (refusal !== undefined) {\n\t\t\tthrow refusal;\n\t\t}\n\n\t\tthis.#hooks.onRateLimit?.(waitMs);\n\t\tawait observeAdmissionWaitAsync({\n\t\t\tdurationMs: waitMs,\n\t\t\tobserver,\n\t\t\treason: OPERATION_QUEUE_REASON,\n\t\t\twaitAsync: async () => {\n\t\t\t\tconst sleepResult = await raceWithAbortAsync(\n\t\t\t\t\tasync () => this.#sleep(waitMs, signal),\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\tif (sleepResult === ABORTED) {\n\t\t\t\t\tthrow requestAbortedError(signal);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t\tthis.#bucketLevel = this.#maxBucketLevel;\n\t\tthis.#lastCheck = now + waitMs;\n\t}\n\n\tasync #waitForToken({ deadlineMs, observer, signal }: AdmissionWaitContext): Promise<void> {\n\t\tif (signal?.aborted === true) {\n\t\t\tthrow requestAbortedError(signal);\n\t\t}\n\n\t\tconst now = Math.max(Date.now(), this.#lastCheck);\n\t\tconst drained = Math.max(0, this.#bucketLevel - (now - this.#lastCheck));\n\t\tthis.#lastCheck = now;\n\n\t\tif (drained + this.#intervalMs <= this.#maxBucketLevel) {\n\t\t\tthis.#bucketLevel = drained + this.#intervalMs;\n\t\t\treturn;\n\t\t}\n\n\t\tconst waitMs = drained + this.#intervalMs - this.#maxBucketLevel;\n\t\tawait this.#waitAsync({ deadlineMs, now, observer, signal, waitMs });\n\t}\n}\n\nfunction ignoreRejection(): void {\n\t// A failed or cancelled acquire must not poison the next caller's chain.\n}\n\nasync function waitForTurnAsync(\n\tturn: Promise<void>,\n\tsignal: AbortSignal | undefined,\n): Promise<void> {\n\tconst turnResult = await raceWithAbortAsync(async () => turn, signal);\n\tif (turnResult === ABORTED) {\n\t\tthrow requestAbortedError(signal);\n\t}\n}\n","import { setTimeout } from \"node:timers/promises\";\n\n/**\n * Injectable sleep function signature for testing.\n *\n * @since 0.1.0\n */\nexport type SleepFunc = (ms: number, signal?: AbortSignal) => Promise<void>;\n\n/**\n * Timer-backed production sleep that releases its timer on cancellation.\n *\n * @param ms - Duration to wait in milliseconds.\n * @param signal - Optional caller cancellation signal.\n */\nexport async function defaultSleepAsync(ms: number, signal?: AbortSignal): Promise<void> {\n\tawait setTimeout(ms, undefined, { signal });\n}\n","import type { HttpClient, SleepFunc } from \"../../client/types.ts\";\nimport { defaultSleepAsync } from \"../utils/sleep.ts\";\nimport { createFetchHttpClient } from \"./fetch-client.ts\";\n\n/**\n * Options accepted by {@link resolveDependencies}. Mirrors the test-seam\n * subset of the public client options.\n */\ninterface ResolveDependenciesOptions {\n\t/**\n\t * Test seam: custom {@link HttpClient}. Defaults to a fetch-backed client.\n\t */\n\treadonly httpClient?: HttpClient | undefined;\n\t/**\n\t * Test seam: custom {@link SleepFunc}. Defaults to a `setTimeout`-backed\n\t * sleep.\n\t */\n\treadonly sleep?: SleepFunc | undefined;\n}\n\n/**\n * Fully-populated dependency set consumed by resource client constructors.\n */\ninterface ResolvedDependencies {\n\t/** Concrete {@link HttpClient} implementation. */\n\treadonly httpClient: HttpClient;\n\t/** Concrete {@link SleepFunc} implementation. */\n\treadonly sleep: SleepFunc;\n}\n\n/**\n * Resolves the concrete HTTP client and sleep implementation a resource\n * client should use. Falls back to the fetch-backed HTTP client and the\n * default `setTimeout`-based sleep when the caller omits the test seams.\n *\n * Extracted so resource client constructors can keep their dependency\n * resolution logic in a single, unit-testable place; this makes the\n * default branches easy to cover without stubbing globals like `fetch`.\n *\n * @param options - Optional {@link HttpClient} and {@link SleepFunc} test seams.\n * @returns A {@link ResolvedDependencies} with defaults applied.\n */\nexport function resolveDependencies(options: ResolveDependenciesOptions): ResolvedDependencies {\n\treturn {\n\t\thttpClient: options.httpClient ?? createFetchHttpClient(),\n\t\tsleep: options.sleep ?? defaultSleepAsync,\n\t};\n}\n","import type { Except } from \"type-fest\";\n\nimport type {\n\tHttpClient,\n\tHttpRequest,\n\tHttpResponse,\n\tOpenCloudClientOptions,\n\tOpenCloudHooks,\n\tRequestConfig,\n\tRequestOptions,\n\tSleepFunc,\n} from \"../client/types.ts\";\nimport { ApiError, requestContextOf } from \"../errors/api-error.ts\";\nimport type { OpenCloudError } from \"../errors/base.ts\";\nimport { PermissionError } from \"../errors/permission-error.ts\";\nimport { RequestAbortedError } from \"../errors/request-aborted.ts\";\nimport { RequestDeadlineExceededError } from \"../errors/request-deadline-exceeded.ts\";\nimport type { Result } from \"../types.ts\";\nimport type { AdmissionWaitContext } from \"./http/admission-wait.ts\";\nimport { BudgetGate, type BudgetScope } from \"./http/budget-gate.ts\";\nimport { executeWithRetryAsync } from \"./http/execute.ts\";\nimport { rateLimitSampleFromResult } from \"./http/rate-limit-observation.ts\";\nimport { type OperationLimit, RateLimitQueue } from \"./http/rate-limit-queue.ts\";\nimport {\n\tdeadlineFailureFromError,\n\telapsedDeadlineFailure,\n\trequestLifecycle,\n\ttype RequestLifecycle,\n} from \"./http/request-deadline.ts\";\nimport { resolveDependencies } from \"./http/resolve-dependencies.ts\";\nimport {\n\tdefaultRetryDelay,\n\tIDEMPOTENT_METHOD_DEFAULTS,\n\tmergeConfig,\n\ttype MethodKind,\n\ttype RetryResolvable,\n} from \"./http/retry.ts\";\nimport { isUploadRequest } from \"./http/upload-request.ts\";\nimport { requestAbortedError } from \"./utils/abort.ts\";\n\n/**\n * Describes a single resource method's shape for dispatch through\n * `ResourceClient.execute`. Each resource client declares one module-level\n * constant per public method; that constant binds the four resource-specific\n * values (request builder, response parser, retry-policy method kind,\n * operation-level rate limit) and flows through `execute` uniformly.\n *\n * @template P - The resource-specific parameter shape the builder\n *   accepts.\n * @template T - The resource-specific parsed success type the parser\n *   produces.\n */\nexport interface ResourceMethodSpec<P, T> {\n\t/**\n\t * Builds the pure {@link HttpRequest} for a single call. Returns a\n\t * {@link Result} so a builder can short-circuit with a local error\n\t * (typically a {@link OpenCloudError} subclass such as `ValidationError`)\n\t * before any HTTP, queue, or retry work happens. Builders that cannot\n\t * fail wrap their return as `{ data: request, success: true }`.\n\t */\n\treadonly buildRequest: (parameters: P) => Result<HttpRequest, OpenCloudError>;\n\t/** Method-level retry defaults merged into the resolved config. */\n\treadonly methodDefaults: Partial<RetryResolvable>;\n\t/**\n\t * Method kind, controlling merge precedence: `\"create\"` lets method\n\t * defaults win over client config so create safety cannot be relaxed\n\t * silently; `\"idempotent\"` lets client config win over method defaults\n\t * so consumers can loosen retry globally.\n\t */\n\treadonly methodKind: MethodKind;\n\t/**\n\t * Operation-level rate limit, keyed into the client's per-key queue map.\n\t */\n\treadonly operationLimit: OperationLimit;\n\t/**\n\t * Converts the full {@link HttpResponse} into the resource-specific\n\t * parsed shape. Takes the whole response (body, status, headers) so\n\t * future parsers can read headers without widening the signature.\n\t */\n\treadonly parse: (response: HttpResponse) => Result<T, OpenCloudError>;\n\t/**\n\t * Open Cloud scopes the API key or OAuth token must carry for this\n\t * method, sourced from the vendored OpenAPI schema's `x-roblox-scopes`.\n\t * When set, a 401 or 403 ApiError from the upstream call is upgraded to\n\t * a {@link PermissionError} carrying these scopes alongside\n\t * {@link OperationLimit.operationKey}, so callers can name the missing\n\t * scope instead of just the HTTP status. Optional so test specs and\n\t * not-yet-wired resources can opt out.\n\t */\n\treadonly requiredScopes?: ReadonlyArray<string>;\n}\n\n/**\n * Single-argument bundle consumed by `ResourceClient.execute`: the per-method\n * spec, the resource-specific parameters, and optional per-request config\n * overrides.\n *\n * @template P - The resource-specific parameter shape the builder accepts.\n * @template T - The resource-specific parsed success type the parser produces.\n */\ninterface ExecuteCall<P, T> {\n\t/** Optional per-request config overrides. */\n\treadonly options?: RequestOptions | undefined;\n\t/** Resource-specific request parameters. */\n\treadonly parameters: P;\n\t/** Optionally refines a transport error with resource-specific evidence. */\n\treadonly refineError?: ((error: OpenCloudError) => OpenCloudError) | undefined;\n\t/**\n\t * Per-method binding of builder, parser, method kind, and operation limit.\n\t */\n\treadonly spec: ResourceMethodSpec<P, T>;\n}\n\n/**\n * Wraps an infallible request build as a {@link Result}-returning\n * `buildRequest` callback compatible with {@link ResourceMethodSpec}.\n * Use from a resource client whose builder cannot fail; resource clients\n * with local validation should construct the {@link Result} directly.\n *\n * @param request - The pre-built {@link HttpRequest}.\n * @returns A success Result wrapping the request.\n */\nexport function okRequest(request: HttpRequest): Result<HttpRequest, OpenCloudError> {\n\treturn { data: request, success: true };\n}\n\n/**\n * A {@link ResourceMethodSpec.parse} implementation for endpoints that return\n * no business payload on success (such as `DELETE` and reorder operations).\n * Surfaces `undefined` data and never inspects the response body.\n *\n * @returns A success Result with `undefined` data.\n */\nexport function parseEmptyResponse(): Result<undefined, OpenCloudError> {\n\treturn { data: undefined, success: true };\n}\n\nconst CLIENT_DEFAULTS = Object.freeze({\n\tbaseUrl: \"https://apis.roblox.com\",\n\tmaxRetries: 3,\n\tretryableStatuses: IDEMPOTENT_METHOD_DEFAULTS.retryableStatuses,\n\tretryableTransportCodes: IDEMPOTENT_METHOD_DEFAULTS.retryableTransportCodes,\n\tretryDelay: defaultRetryDelay,\n\ttimeout: 30_000,\n} satisfies Except<RetryResolvable, \"apiKey\">);\n\n/**\n * Inputs to {@link buildRequestConfig}, bundled to keep the signature narrow.\n */\ninterface RequestConfigInputs {\n\t/** The resolved config for this call. */\n\treadonly merged: RetryResolvable;\n\t/** The caller's per-request overrides, if any. */\n\treadonly options: RequestOptions | undefined;\n\t/** The built request, inspected for an upload body. */\n\treadonly request: HttpRequest;\n\t/** Caller and deadline signal composed for the whole logical request. */\n\treadonly signal: AbortSignal | undefined;\n}\n\ninterface DispatchInputs {\n\treadonly admission: AdmissionWaitContext;\n\treadonly merged: RetryResolvable;\n\treadonly operationLimit: OperationLimit;\n\treadonly refineError: ((error: OpenCloudError) => OpenCloudError) | undefined;\n\treadonly request: HttpRequest;\n\treadonly requestConfig: RequestConfig;\n}\n\n/** Inputs to the request-scoped budget-gated transport callback. */\ninterface GatedSendInputs {\n\treadonly admission: AdmissionWaitContext;\n\treadonly refineError: ((error: OpenCloudError) => OpenCloudError) | undefined;\n\treadonly requestConfig: RequestConfig;\n\treadonly scope: BudgetScope;\n}\n\n/** Request-only controls resolved before request construction. */\ninterface RequestStart {\n\treadonly admission: AdmissionWaitContext;\n\treadonly lifecycle: RequestLifecycle;\n\treadonly requestOptions: Partial<RetryResolvable>;\n}\n\ninterface FinishRequestInputs<P, T> {\n\treadonly httpResult: Result<HttpResponse, OpenCloudError>;\n\treadonly lifecycle: RequestLifecycle;\n\treadonly spec: ResourceMethodSpec<P, T>;\n}\n\n/**\n * Internal orchestrator shared by every Open Cloud resource client. Holds\n * the frozen client config, observability hooks, injected HTTP client and\n * sleep, and the per-effective-key rate-limit queue registry. Resource\n * classes compose one instance and dispatch every public method through\n * {@link ResourceClient.executeAsync} with a per-method {@link ResourceMethodSpec}.\n * Not exported from any package subpath; reachable only via sibling\n * `src/resources/**` modules in this package.\n */\nexport class ResourceClient {\n\treadonly #budgets: BudgetGate;\n\treadonly #config: Readonly<RetryResolvable>;\n\treadonly #hooks: OpenCloudHooks;\n\treadonly #httpClient: HttpClient;\n\treadonly #queues = new Map<string, RateLimitQueue>();\n\treadonly #sleep: SleepFunc;\n\n\t/**\n\t * Creates a new {@link ResourceClient}. Resolves the injected HTTP\n\t * client and sleep (defaulting to fetch + `setTimeout`) and freezes the\n\t * merged client config so subsequent calls cannot mutate it.\n\t *\n\t * @param options - Client-level configuration including the API key\n\t *   and optional construction-time test seams.\n\t */\n\tconstructor({ apiKey, hooks, httpClient, sleep, ...overrides }: OpenCloudClientOptions) {\n\t\tconst resolved = resolveDependencies({ httpClient, sleep });\n\t\tthis.#httpClient = resolved.httpClient;\n\t\tthis.#sleep = resolved.sleep;\n\t\tthis.#budgets = new BudgetGate(this.#sleep);\n\t\tthis.#hooks = hooks ?? {};\n\t\tthis.#config = Object.freeze({\n\t\t\t...CLIENT_DEFAULTS,\n\t\t\tapiKey,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\t/**\n\t * Dispatches a single resource-method call. Merges the frozen client\n\t * config with the method's `methodDefaults` and the caller's optional\n\t * per-request `options`, routes through the effective-apiKey rate-limit\n\t * queue, runs the retry loop, and finally parses the response with the\n\t * spec's parser.\n\t *\n\t * @param call - The per-method spec, resource-specific parameters, and\n\t *   optional per-request overrides.\n\t * @returns The parsed success payload or the {@link OpenCloudError} that\n\t *   caused the request to fail. Never throws.\n\t * @rejects An unexpected collaborator failure unrelated to caller cancellation.\n\t */\n\tpublic async executeAsync<P, T>({\n\t\toptions,\n\t\tparameters,\n\t\trefineError,\n\t\tspec,\n\t}: ExecuteCall<P, T>): Promise<Result<T, OpenCloudError>> {\n\t\tconst start = startRequest(options);\n\t\tif (!start.success) {\n\t\t\treturn start;\n\t\t}\n\n\t\tconst { admission, lifecycle, requestOptions } = start.data;\n\t\tconst merged = mergeConfig(this.#config, {\n\t\t\tmethodDefaults: spec.methodDefaults,\n\t\t\tmethodKind: spec.methodKind,\n\t\t\trequestOptions,\n\t\t});\n\t\tconst requestResult = spec.buildRequest(parameters);\n\t\tif (!requestResult.success) {\n\t\t\treturn requestResult;\n\t\t}\n\n\t\tconst request = requestResult.data;\n\t\tconst { signal } = admission;\n\t\tconst requestConfig = buildRequestConfig({ merged, options, request, signal });\n\t\tconst httpResult = await this.#dispatchAsync({\n\t\t\tadmission,\n\t\t\tmerged,\n\t\t\toperationLimit: spec.operationLimit,\n\t\t\trefineError,\n\t\t\trequest,\n\t\t\trequestConfig,\n\t\t});\n\t\treturn finishRequest({ httpResult, lifecycle, spec });\n\t}\n\n\t/**\n\t * Returns the sleep function used by this client instance.\n\t *\n\t * @returns The sleep function injected at construction time.\n\t */\n\tpublic get sleep(): SleepFunc {\n\t\treturn this.#sleep;\n\t}\n\n\tasync #dispatchAsync({\n\t\tadmission,\n\t\tmerged,\n\t\toperationLimit,\n\t\trefineError,\n\t\trequest,\n\t\trequestConfig,\n\t}: DispatchInputs): Promise<Result<HttpResponse, OpenCloudError>> {\n\t\tconst queue = this.#getQueue(merged.apiKey, operationLimit);\n\t\ttry {\n\t\t\treturn await queue.acquireAsync(async () => {\n\t\t\t\treturn executeWithRetryAsync(request, {\n\t\t\t\t\tadmissionWaitObserver: admission.observer,\n\t\t\t\t\tconfig: merged,\n\t\t\t\t\tdeadlineMs: admission.deadlineMs,\n\t\t\t\t\thooks: this.#hooks,\n\t\t\t\t\tsend: this.#gatedSend({\n\t\t\t\t\t\tadmission,\n\t\t\t\t\t\trefineError,\n\t\t\t\t\t\trequestConfig,\n\t\t\t\t\t\tscope: {\n\t\t\t\t\t\t\tapiKey: merged.apiKey,\n\t\t\t\t\t\t\toperationKey: operationLimit.operationKey,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tsignal: admission.signal,\n\t\t\t\t\tsleep: this.#sleep,\n\t\t\t\t});\n\t\t\t}, admission);\n\t\t} catch (err) {\n\t\t\treturn dispatchFailure(err);\n\t\t}\n\t}\n\n\t/**\n\t * Builds the transport callback for one logical call, wrapping the HTTP\n\t * client with the budget gate: each attempt waits on the scope's budget\n\t * before sending, then folds the response's reported budget back in so the\n\t * next attempt (or a later call on the same scope) can head off a 429.\n\t *\n\t * @param inputs - Budget scope, transport config, observer, and caller signal.\n\t * @returns A send callback for {@link executeWithRetryAsync}.\n\t */\n\t#gatedSend({\n\t\tadmission,\n\t\trefineError,\n\t\trequestConfig,\n\t\tscope,\n\t}: GatedSendInputs): (request: HttpRequest) => Promise<Result<HttpResponse, OpenCloudError>> {\n\t\treturn async (toSend) => {\n\t\t\tawait this.#budgets.gateAsync(scope, admission);\n\t\t\tconst transportResult = await this.#httpClient.request(toSend, requestConfig);\n\t\t\tconst sendResult =\n\t\t\t\trefineError === undefined || transportResult.success\n\t\t\t\t\t? transportResult\n\t\t\t\t\t: { err: refineError(transportResult.err), success: false as const };\n\t\t\tthis.#budgets.observe(scope, rateLimitSampleFromResult(transportResult));\n\t\t\treturn sendResult;\n\t\t};\n\t}\n\n\t#getQueue(apiKey: string, limit: OperationLimit): RateLimitQueue {\n\t\tconst key = `${apiKey}::${limit.operationKey}`;\n\t\tconst existing = this.#queues.get(key);\n\t\tif (existing !== undefined) {\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst queue = new RateLimitQueue(limit, this.#hooks, this.#sleep);\n\t\tthis.#queues.set(key, queue);\n\t\treturn queue;\n\t}\n}\n\nfunction startRequest(options: RequestOptions | undefined): Result<RequestStart, OpenCloudError> {\n\tconst callerSignal = options?.signal;\n\tif (callerSignal?.aborted === true) {\n\t\treturn { err: requestAbortedError(callerSignal), success: false };\n\t}\n\n\tconst lifecycle = requestLifecycle(options?.deadlineMs, callerSignal);\n\tconst deadlineFailure = elapsedDeadlineFailure(lifecycle);\n\tif (deadlineFailure !== undefined) {\n\t\treturn { err: deadlineFailure, success: false };\n\t}\n\n\tconst { deadlineMs, onAdmissionWait, signal: _signal, ...requestOptions } = options ?? {};\n\treturn {\n\t\tdata: {\n\t\t\tadmission: { deadlineMs, observer: onAdmissionWait, signal: lifecycle.signal },\n\t\t\tlifecycle,\n\t\t\trequestOptions,\n\t\t},\n\t\tsuccess: true,\n\t};\n}\n\nfunction dispatchFailure(err: unknown): Result<never, OpenCloudError> {\n\tif (err instanceof RequestAbortedError || err instanceof RequestDeadlineExceededError) {\n\t\treturn { err, success: false };\n\t}\n\n\tthrow err;\n}\n\n/**\n * Resolves the per-request {@link RequestConfig}. Upload requests\n * ({@link isUploadRequest}) carry no default timeout: a multi-megabyte place\n * file over a slow link is bandwidth-bound, so a transport-attempt timeout only\n * fires spuriously. An explicit `options.timeout` still applies to any\n * request; every non-upload request keeps the merged default.\n *\n * @param inputs - The merged config, the built request, and per-request overrides.\n * @returns The config to hand to the transport, with `timeout` omitted when\n *   no transport-attempt timeout should apply.\n */\nfunction buildRequestConfig({\n\tmerged,\n\toptions,\n\trequest,\n\tsignal,\n}: RequestConfigInputs): RequestConfig {\n\tconst shouldOmitDefaultTimeout = options?.timeout === undefined && isUploadRequest(request);\n\treturn {\n\t\tapiKey: merged.apiKey,\n\t\tbaseUrl: merged.baseUrl,\n\t\t...(signal === undefined ? {} : { signal }),\n\t\t...(shouldOmitDefaultTimeout ? {} : { timeout: merged.timeout }),\n\t};\n}\n\nfunction enrichPermissionError<P, T>(\n\terr: OpenCloudError,\n\tspec: ResourceMethodSpec<P, T>,\n): OpenCloudError {\n\tif (spec.requiredScopes === undefined) {\n\t\treturn err;\n\t}\n\n\tif (err instanceof PermissionError) {\n\t\treturn err;\n\t}\n\n\tif (!(err instanceof ApiError)) {\n\t\treturn err;\n\t}\n\n\tif (err.statusCode !== 401 && err.statusCode !== 403) {\n\t\treturn err;\n\t}\n\n\t// An edge gateway answers 401 and 403 for its own reasons, and the request\n\t// never reached the operation whose scopes these are.\n\tif (err.gatewaySummary !== undefined) {\n\t\treturn err;\n\t}\n\n\treturn new PermissionError(err.message, {\n\t\t...requestContextOf(err),\n\t\tcause: err.cause,\n\t\tcode: err.code,\n\t\tdetails: err.details,\n\t\toperationKey: spec.operationLimit.operationKey,\n\t\trequiredScopes: spec.requiredScopes,\n\t\tstatusCode: err.statusCode,\n\t});\n}\n\nfunction finishRequest<P, T>({\n\thttpResult,\n\tlifecycle,\n\tspec,\n}: FinishRequestInputs<P, T>): Result<T, OpenCloudError> {\n\tif (httpResult.success) {\n\t\treturn spec.parse(httpResult.data);\n\t}\n\n\tconst deadlineFailure = deadlineFailureFromError(httpResult.err, lifecycle);\n\treturn {\n\t\terr: deadlineFailure ?? enrichPermissionError(httpResult.err, spec),\n\t\tsuccess: false,\n\t};\n}\n"],"mappings":"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"}