UNPKG

reso.js

Version:

A robust, Typescript-first Node.js client designed for interacting with RESO Web API services, fully aligned with the current RESO Web API specification.

167 lines (156 loc) 5.91 kB
import { FetchOptions, ResponseType, FetchHook, FetchContext, FetchResponse } from 'ofetch'; import PQueue from 'p-queue'; type AuthOptionType = 'bearer' | 'credentials'; interface BaseAuthOptions { type: AuthOptionType; } interface AuthBearerOptions extends BaseAuthOptions { type: 'bearer'; credentials: { token: string; tokenType?: string; }; } interface AuthClientCredentialsOptions extends BaseAuthOptions { type: 'credentials'; credentials: { tokenURL: string; clientId: string; clientSecret: string; scope?: string; grantType?: string; }; refreshBuffer?: number; } type AuthOptions = AuthBearerOptions | AuthClientCredentialsOptions; type CreateAuthOptions = AuthOptions; interface TransportError { code: string | number; message: string; target: string; details: TransportErrorDetail[]; [key: string]: unknown; } interface TransportErrorDetail { code: string; target: string; message: string; } declare enum TransportErrorCode { ServiceUnavailable = "SERVICE_UNAVAILABLE", Forbidden = "FORBIDDEN", BadRequest = "BAD_REQUEST", NotFound = "NOT_FOUND", RequestEntityTooLarge = "REQUEST_ENTITY_TO_LARGE", UnsupportedMedia = "UNSUPPORTED_MEDIA", TooManyRequests = "TOO_MANY_REQUESTS", InternalServerError = "INTERNAL_SERVER_ERROR", NotImplemented = "NOT_IMPLEMENTED", Unknown = "UNKNOWN" } type FeedErrorOptions = { message?: string; } & Partial<Pick<TransportError, 'code' | 'target' | 'details'>>; interface CreateLimiterOptions { duration?: number; points?: number; } type FeedLimiter = PQueue; type FeedHttpOptions = Omit<FetchOptions, 'onResponse' | 'onResponseError' | 'onRequest' | 'onRequestError' | 'baseURL'> & Required<Pick<FetchOptions, 'baseURL'>>; interface FeedHooksOptions<T = unknown, R extends ResponseType = ResponseType> { onRequest?: FetchHook<FetchContext<T, R>>[]; onRequestError?: FetchHook<FetchContext<T, R> & { error: Error; }>[]; onResponse?: FetchHook<FetchContext<T, R> & { response: FetchResponse<T>; }>[]; onResponseError?: FetchHook<FetchContext<T, R> & { response: FetchResponse<T>; }>[]; } interface FeedOptions { http: FeedHttpOptions; hooks?: FeedHooksOptions; } interface CreateFeedOptions { http: FeedHttpOptions; hooks?: FeedHooksOptions; limiter?: CreateLimiterOptions; auth?: CreateAuthOptions; } interface RequestOptions { query?: string | undefined; } type ResourceId = string | number; type ResourceQuery = string; interface FeedBaseResponse<R> { context?: string; data: R | R[]; } interface FeedEntityResponse<R> extends FeedBaseResponse<R> { data: R; } interface FeedCollectionResponse<R> extends FeedBaseResponse<R> { nextLink?: string; count?: string | number; data: R[]; } /** * Conditional type utility that determines if a given type 'T' resolves to 'any'. * * If T is any it resolves to type 'Y' * If T is not any it resolves to type 'N' */ type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N; /** * Resolves the type of the Resource (R) based on the Schema and the requested Resource. * * If Schema is 'any', it defaults to Record<string, unknown>. * If Schema is specific, it looks up Schema[R]. */ type ResolveResourceType<Schema, R> = IfAny<Schema, Record<string, unknown>, // Fallback for 'any' or 'unknown' Schema Schema extends Record<string, any> ? (R extends keyof Schema ? Schema[R] : never) : never>; declare class Feed<Schema> { http: FeedOptions['http']; hooks: FeedOptions['hooks']; constructor(opts: FeedOptions); /** * Fetch the OData $metadata. * * @param [query] The optional query to apply for the metadata request (rarely used). * @returns The raw metadata XML document */ $metadata(query?: ResourceQuery): Promise<string>; /** * Fetch a single resource entity by its unique ID. * @param resource The name of the resource collection. * @param id The unique identifier for the specific entity. * @param [query] The optional query to apply. * @returns The entity */ readById<R extends IfAny<Schema, string, keyof Schema>>(resource: R, id: ResourceId, query?: ResourceQuery): Promise<FeedEntityResponse<ResolveResourceType<Schema, R>>>; /** * Fetch a resource collection. * * The generator will yield a response for each page of results * and automatically follow the `@odata.nextLink` until all entities are retrieved. * * @param resource The name of the resource collection. * @param [query] The optional query to apply. * @returns An async generator that yields paginated collection responses. */ readByQuery<R extends IfAny<Schema, string, keyof Schema>>(resource: R, query?: ResourceQuery): AsyncGenerator<FeedCollectionResponse<ResolveResourceType<Schema, R>>, void, unknown>; request<R>(path: string, options?: RequestOptions): Promise<string | FeedCollectionResponse<R> | FeedEntityResponse<R>>; } declare function createFeed<Schema>(opts: CreateFeedOptions): Feed<Schema>; declare class FeedError extends Error { name: TransportErrorCode; code: string | number; target: string | null; details: NonNullable<FeedErrorOptions['details']>; constructor(opts: FeedErrorOptions); toString(): string; } export { FeedError, TransportErrorCode, createFeed }; export type { AuthBearerOptions, AuthClientCredentialsOptions, AuthOptionType, AuthOptions, BaseAuthOptions, CreateAuthOptions, CreateFeedOptions, CreateLimiterOptions, FeedBaseResponse, FeedCollectionResponse, FeedEntityResponse, FeedErrorOptions, FeedHooksOptions, FeedHttpOptions, FeedLimiter, FeedOptions, IfAny, RequestOptions, ResolveResourceType, ResourceId, ResourceQuery, TransportError, TransportErrorDetail };