//#region src/errors/base.d.ts /** * Options for constructing an {@link OpenCloudError}. * * @since 0.3.0 */ interface OpenCloudErrorOptions extends ErrorOptions { /** * Machine-readable classifier for the failure, when the error has one. An * `ApiError` and `RateLimitError` fill it from the response body; a * `ValidationError` narrows it to its own closed union. Errors with nothing * to classify (transport failures and poll timeouts) leave it `undefined`. */ readonly code?: string | undefined; } /** * Base error class for all Open Cloud SDK errors. * * All specific error types (RateLimitError, ApiError, NetworkError) * extend this class, enabling `instanceof OpenCloudError` checks. * * `code` is declared here rather than on the subclasses that populate it, so a * caller holding the `OpenCloudError` that `Result.err` is typed as can branch * on it without first narrowing to a subclass. * * @since 0.1.0 * * @example * * ```ts * import { ApiError, OpenCloudError } from "@bedrock-rbx/ocale"; * * // `Result.err` is typed as OpenCloudError, so a caller draining a queue * // branches on the canonical status without narrowing to a subclass first. * const err: OpenCloudError = new ApiError("HTTP 404: Queue items not found.", { * code: "NOT_FOUND", * statusCode: 404, * }); * * expect(err.code).toBe("NOT_FOUND"); * expect(new OpenCloudError("no classifier").code).toBeUndefined(); * ``` */ declare class OpenCloudError extends Error { /** Machine-readable classifier, or `undefined` when the error has none. */ readonly code: string | undefined; override readonly name: string; /** * Creates a new OpenCloudError. * * @param message - Human-readable error description. * @param options - Error options including the optional `cause` and the * machine-readable `code`. */ constructor(message?: string, options?: OpenCloudErrorOptions); } //#endregion //#region src/internal/utils/sleep.d.ts /** * Injectable sleep function signature for testing. * * @since 0.1.0 */ type SleepFunc = (ms: number, signal?: AbortSignal) => Promise; //#endregion //#region src/types.d.ts /** * Discriminated union for explicit error handling. * * Every SDK client method returns `Promise>`. * Errors are never thrown; they are returned as `{ err, success: false }`. * * @since 0.1.0 * * @template T - The success value type. * @template E - The error type (defaults to `Error`). * * @example * * ```ts * import type { Result } from "@bedrock-rbx/ocale"; * * function parseAge(input: string): Result { * const age = Number(input); * return Number.isFinite(age) * ? { data: age, success: true } * : { err: new Error(`Not a number: ${input}`), success: false }; * } * * const ok = parseAge("42"); * if (ok.success) { * // ok.data is narrowed to number here; value is 42 * expect(ok.data).toBe(42); * } * * const bad = parseAge("nope"); * if (!bad.success) { * // bad.err is narrowed to Error here; message mentions the input * expect(bad.err.message).toContain("Not a number"); * } * ``` */ type Result = { data: T; success: true; } | { err: E; success: false; }; /** * One page of a cursor-paginated SDK response. * * `list`-style methods on resource clients (for example * `GamePassesClient.list`) return a {@link Result} wrapping a `Page`. * `nextPageToken` carries the cursor for the next page when one exists, * or `undefined` on the last page; the SDK normalizes the wire's * `null`-vs-absent variants to `undefined` so callers only ever see one * shape. * * @since 0.1.0 * * @template T - The public item type for the listed resource. * * @example * * ```ts * import type { Page } from "@bedrock-rbx/ocale"; * * const middle: Page = { items: ["a", "b"], nextPageToken: "cursor" }; * expect(middle.items).toEqual(["a", "b"]); * expect(middle.nextPageToken).toBe("cursor"); * * const last: Page = { items: ["c"], nextPageToken: undefined }; * expect(last.items).toEqual(["c"]); * expect(last.nextPageToken).toBeUndefined(); * ``` */ interface Page { /** Items in this page, in the order returned by the API. */ readonly items: ReadonlyArray; /** Cursor for the next page; `undefined` on the last page. */ readonly nextPageToken: string | undefined; } //#endregion //#region src/client/types.d.ts /** * Why a logical request is waiting for SDK-managed admission. * * @example * * ```ts * import type { AdmissionWaitReason } from "@bedrock-rbx/ocale"; * * const reason: AdmissionWaitReason = "retry-delay"; * expect(reason).toBe("retry-delay"); * ``` * * @since 0.3.1 */ type AdmissionWaitReason = "operation-capacity" | "operation-queue" | "reported-budget" | "retry-delay"; /** * One boundary in a request's SDK-managed admission-wait lifecycle. * * `durationMs` is the scheduler's intended duration, not elapsed wall time, * and is absent when the SDK cannot know the duration up front. * * @example * * ```ts * import type { AdmissionWaitEvent } from "@bedrock-rbx/ocale"; * * const event: AdmissionWaitEvent = { * durationMs: 500, * phase: "started", * reason: "reported-budget", * }; * expect(event.durationMs).toBe(500); * ``` * * @since 0.3.1 */ interface AdmissionWaitEvent { /** Intended wait duration in milliseconds, when known. */ readonly durationMs?: number; /** Whether the wait has just begun or has finished. */ readonly phase: "ended" | "started"; /** SDK admission mechanism responsible for the wait. */ readonly reason: AdmissionWaitReason; } /** * Receives request-scoped admission-wait lifecycle notifications. * * @example * * ```ts * import type { AdmissionWaitEvent, AdmissionWaitObserver } from "@bedrock-rbx/ocale"; * * const events: AdmissionWaitEvent[] = []; * const observer: AdmissionWaitObserver = (event) => events.push(event); * observer({ phase: "started", reason: "operation-queue" }); * expect(events).toHaveLength(1); * ``` * * @since 0.3.1 */ type AdmissionWaitObserver = (event: AdmissionWaitEvent) => unknown; /** * A normalized HTTP request to send to the Roblox Open Cloud API. * * @since 0.1.0 */ interface HttpRequest { /** The request body. */ readonly body?: HttpRequestBody; /** * Caller-supplied request headers. Applied after the transport sets * `x-api-key` and any body-driven `Content-Type`, so a caller-supplied * header replaces the transport's default. */ readonly headers?: Readonly>; /** The HTTP method. */ readonly method: "DELETE" | "GET" | "PATCH" | "POST"; /** Relative path, e.g. `/game-passes/v1/universes/123/...`. */ readonly url: string; } /** * A normalized HTTP response from the Roblox Open Cloud API. * * @since 0.1.0 */ interface HttpResponse { /** * The parsed response body. `undefined` when the response had an empty * body (for example HTTP 204 No Content, or any other status where the * server returned no payload). */ readonly body: unknown; /** Response headers with lowercased keys. */ readonly headers: Readonly>; /** The HTTP status code. */ readonly status: number; } /** * Per-request configuration passed to {@link HttpClient.request}. * * @since 0.1.0 */ interface RequestConfig { /** The Roblox Open Cloud API key. */ readonly apiKey: string; /** Base URL for the API, e.g. `https://apis.roblox.com`. */ readonly baseUrl: string; /** Caller cancellation signal for this request. */ readonly signal?: AbortSignal; /** Optional request timeout in milliseconds. */ readonly timeout?: number; } /** * HTTP transport abstraction. Implementations classify every response into * a typed {@link Result}. * * @since 0.1.0 */ interface HttpClient { /** Sends an HTTP request and classifies the response. */ request(request: HttpRequest, config: RequestConfig): Promise>; } /** * Client-level observability hooks. All hooks are notification-only and * fire-and-forget; they cannot alter retry behaviour. * * @since 0.1.0 */ interface OpenCloudHooks { /** Fired before the SDK sleeps for a computed retry or rate-limit wait. */ readonly onRateLimit?: (waitMs: number) => void; /** Fired before each HTTP attempt (including retries). */ readonly onRequest?: (request: HttpRequest) => void; /** Fired before a retry is attempted. `attempt` is 1-indexed. */ readonly onRetry?: (attempt: number, error: OpenCloudError) => void; } /** * Options accepted by every resource client constructor. Cross-cutting * configuration that applies to all requests made through the client instance. * * @since 0.1.0 */ interface OpenCloudClientOptions { /** The Roblox Open Cloud API key used as the default for every request. */ readonly apiKey: string; /** Base URL for the Open Cloud API. Defaults to `https://apis.roblox.com`. */ readonly baseUrl?: string; /** Optional observability hooks. */ readonly hooks?: OpenCloudHooks; /** * Plug in a custom {@link HttpClient} to wrap or replace the default * fetch-backed transport. Useful for wrapping `fetch` with tracing * or metrics, routing through a custom proxy, or feeding the SDK * from a recorded-fixture or replay layer. Most consumers leave this * unset and use the default. */ readonly httpClient?: HttpClient; /** Maximum retry attempts. Defaults to `3`. */ readonly maxRetries?: number; /** * Status codes eligible for retry. Defaults to the idempotent-method set * `[429, 500, 502, 503, 504]`. Resource clients may tighten this per * method (e.g. `create` only retries `429`). */ readonly retryableStatuses?: ReadonlyArray; /** * Node-style transport error codes eligible for retry when a request fails * with a `NetworkError` (e.g. `["ECONNRESET", "ETIMEDOUT"]`). * Defaults to the idempotent-method transient set. Create methods default * to none and cannot be relaxed by a client-level value. Pass the exported * `TRANSIENT_TRANSPORT_CODES` set (or your own subset) on a single call's * {@link RequestOptions} to opt a create into transport retries when a * duplicate resource is acceptable. */ readonly retryableTransportCodes?: ReadonlyArray; /** Fallback delay function used when no server hint is available. */ readonly retryDelay?: (attempt: number) => number; /** * Plug in a custom {@link SleepFunc} used between retry attempts and * for rate-limit waits. Useful for integrating with a custom * scheduler or virtual clock. Most consumers leave this unset and * use the default `setTimeout`-backed sleep. */ readonly sleep?: SleepFunc; /** * Default per-request timeout in milliseconds for JSON-bound methods, * defaulting to `30_000`. Upload methods (those whose request body is * `FormData` or `Uint8Array`, such as place publishes and icon uploads) * have no default timeout and ignore this option: upload latency is * bandwidth-bound, and the SDK cannot size a wall-clock budget without * knowing payload size and link quality. Set a transport-attempt timeout * on any single call, upload or otherwise, with `options.timeout`. */ readonly timeout?: number; } /** * Per-request override shape. Any subset of the overridable client options * may be supplied for a single request; omitted fields fall through to the * client-level defaults. * * @since 0.1.0 */ type RequestOptions = Partial> & { /** * Absolute Unix timestamp in milliseconds by which this logical request * must finish. SDK-managed waits that cannot fit fail with a typed * `RequestDeadlineExceededError` instead of consuming the remaining budget. */ readonly deadlineMs?: number; /** * Receives the admission waits entered by this logical request only. * Notifications cannot alter scheduling or retry behavior. */ readonly onAdmissionWait?: AdmissionWaitObserver; /** Cancels this request at any point in its lifecycle. */ readonly signal?: AbortSignal; }; /** * Supported request body types. * * - `FormData` for multipart uploads (Content-Type set automatically by * fetch). * - `Record` for JSON bodies (serialized with * `JSON.stringify`). * - `Uint8Array` for raw binary uploads (default Content-Type is * `application/octet-stream`; override via {@link HttpRequest.headers}). * `SharedArrayBuffer`-backed views are not accepted by `fetch`; wrap them * via `new Uint8Array(bytes)` to obtain an `ArrayBuffer`-backed copy. * - `undefined` for requests without a body (GET, DELETE). */ type HttpRequestBody = FormData | Record | Uint8Array | undefined; //#endregion export { HttpRequest as a, OpenCloudHooks as c, Page as d, Result as f, OpenCloudErrorOptions as h, HttpClient as i, RequestConfig as l, OpenCloudError as m, AdmissionWaitObserver as n, HttpResponse as o, SleepFunc as p, AdmissionWaitReason as r, OpenCloudClientOptions as s, AdmissionWaitEvent as t, RequestOptions as u }; //# sourceMappingURL=types-C3Egi37J.d.mts.map