diff --git a/.changeset/little-items-allow.md b/.changeset/little-items-allow.md new file mode 100644 index 00000000000..219e5fb353a --- /dev/null +++ b/.changeset/little-items-allow.md @@ -0,0 +1,8 @@ +--- +"thirdweb": minor +"@thirdweb-dev/insight": minor +"@thirdweb-dev/engine": minor +"@thirdweb-dev/nebula": minor +--- + +update hey-api version to 0.76.0 diff --git a/packages/engine/package.json b/packages/engine/package.json index baa6b16a2f0..556a88ff18f 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -27,12 +27,9 @@ "dist/*", "src/*" ], - "dependencies": { - "@hey-api/client-fetch": "0.10.0" - }, "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.72.1", + "@hey-api/openapi-ts": "0.76.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, diff --git a/packages/engine/src/client/client.gen.ts b/packages/engine/src/client/client.gen.ts index 2a1dfa5d7a9..ff215a40ad1 100644 --- a/packages/engine/src/client/client.gen.ts +++ b/packages/engine/src/client/client.gen.ts @@ -5,7 +5,7 @@ import { createClient, createConfig, type ClientOptions as DefaultClientOptions, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import type { ClientOptions } from "./types.gen.js"; /** diff --git a/packages/engine/src/client/client/client.ts b/packages/engine/src/client/client/client.ts new file mode 100644 index 00000000000..8cb5e5bde84 --- /dev/null +++ b/packages/engine/src/client/client/client.ts @@ -0,0 +1,189 @@ +import type { Client, Config, RequestOptions } from "./types.js"; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from "./utils.js"; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors< + Request, + Response, + unknown, + RequestOptions + >(); + + const request: Client["request"] = async (options) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.body && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.body === "") { + opts.headers.delete("Content-Type"); + } + + const url = buildUrl(opts); + const requestInit: ReqInit = { + redirect: "follow", + ...opts, + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request._fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response = await _fetch(request); + + for (const fn of interceptors.response._fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + if ( + response.status === 204 || + response.headers.get("Content-Length") === "0" + ) { + return opts.responseStyle === "data" + ? {} + : { + data: {}, + ...result, + }; + } + + const parseAs = + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json"; + + let data: any; + switch (parseAs) { + case "arrayBuffer": + case "blob": + case "formData": + case "json": + case "text": + data = await response[parseAs](); + break; + case "stream": + return opts.responseStyle === "data" + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === "json") { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === "data" + ? data + : { + data, + ...result, + }; + } + + let error = await response.text(); + + try { + error = JSON.parse(error); + } catch { + // noop + } + + let finalError = error; + + for (const fn of interceptors.error._fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === "data" + ? undefined + : { + error: finalError, + ...result, + }; + }; + + return { + buildUrl, + connect: (options) => request({ ...options, method: "CONNECT" }), + delete: (options) => request({ ...options, method: "DELETE" }), + get: (options) => request({ ...options, method: "GET" }), + getConfig, + head: (options) => request({ ...options, method: "HEAD" }), + interceptors, + options: (options) => request({ ...options, method: "OPTIONS" }), + patch: (options) => request({ ...options, method: "PATCH" }), + post: (options) => request({ ...options, method: "POST" }), + put: (options) => request({ ...options, method: "PUT" }), + request, + setConfig, + trace: (options) => request({ ...options, method: "TRACE" }), + }; +}; diff --git a/packages/engine/src/client/client/index.ts b/packages/engine/src/client/client/index.ts new file mode 100644 index 00000000000..33d0123ce32 --- /dev/null +++ b/packages/engine/src/client/client/index.ts @@ -0,0 +1,22 @@ +export type { Auth } from "../core/auth.js"; +export type { QuerySerializerOptions } from "../core/bodySerializer.js"; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from "../core/bodySerializer.js"; +export { buildClientParams } from "../core/params.js"; +export { createClient } from "./client.js"; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + OptionsLegacyParser, + RequestOptions, + RequestResult, + ResponseStyle, + TDataShape, +} from "./types.js"; +export { createConfig, mergeHeaders } from "./utils.js"; diff --git a/packages/engine/src/client/client/types.ts b/packages/engine/src/client/client/types.ts new file mode 100644 index 00000000000..6d37980f22f --- /dev/null +++ b/packages/engine/src/client/client/types.ts @@ -0,0 +1,222 @@ +import type { Auth } from "../core/auth.js"; +import type { + Client as CoreClient, + Config as CoreConfig, +} from "../core/types.js"; +import type { Middleware } from "./utils.js"; + +export type ResponseStyle = "data" | "fields"; + +export interface Config + extends Omit, + CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T["baseUrl"]; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: (request: Request) => ReturnType; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: + | "arrayBuffer" + | "auto" + | "blob" + | "formData" + | "json" + | "stream" + | "text"; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T["throwOnError"]; +} + +export interface RequestOptions< + TResponseStyle extends ResponseStyle = "fields", + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }> { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends "data" + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record + ? TData[keyof TData] + : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends "data" + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined + : ( + | { + data: TData extends Record + ? TData[keyof TData] + : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method">, +) => RequestResult; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method"> & + Pick>, "method">, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: Pick & Options, +) => string; + +export type Client = CoreClient & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = OmitKeys< + RequestOptions, + "body" | "path" | "query" | "url" +> & + Omit; + +export type OptionsLegacyParser< + TData = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = TData extends { body?: any } + ? TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "body" | "headers" | "url" + > & + TData + : OmitKeys, "body" | "url"> & + TData & + Pick, "headers"> + : TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "headers" | "url" + > & + TData & + Pick, "body"> + : OmitKeys, "url"> & TData; diff --git a/packages/engine/src/client/client/utils.ts b/packages/engine/src/client/client/utils.ts new file mode 100644 index 00000000000..103b5315f96 --- /dev/null +++ b/packages/engine/src/client/client/utils.ts @@ -0,0 +1,417 @@ +import { getAuthToken } from "../core/auth.js"; +import type { + QuerySerializer, + QuerySerializerOptions, +} from "../core/bodySerializer.js"; +import { jsonBodySerializer } from "../core/bodySerializer.js"; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer.js"; +import type { Client, ClientOptions, Config, RequestOptions } from "./types.js"; + +interface PathSerializer { + path: Record; + url: string; +} + +const PATH_PARAM_RE = /\{[^{}]+\}/g; + +type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +type MatrixStyle = "label" | "matrix" | "simple"; +type ArraySeparatorStyle = ArrayStyle | MatrixStyle; + +const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = "simple"; + + if (name.endsWith("*")) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith(".")) { + name = name.substring(1); + style = "label"; + } else if (name.startsWith(";")) { + name = name.substring(1); + style = "matrix"; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); + continue; + } + + if (typeof value === "object") { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === "matrix") { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === "label" ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const createQuerySerializer = ({ + allowReserved, + array, + object, +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === "object") { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved, + explode: true, + name, + style: "form", + value, + ...array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === "object") { + const serializedObject = serializeObjectParam({ + allowReserved, + explode: true, + name, + style: "deepObject", + value: value as Record, + ...object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join("&"); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = ( + contentType: string | null, +): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return "stream"; + } + + const cleanContent = contentType.split(";")[0]?.trim(); + + if (!cleanContent) { + return; + } + + if ( + cleanContent.startsWith("application/json") || + cleanContent.endsWith("+json") + ) { + return "json"; + } + + if (cleanContent === "multipart/form-data") { + return "formData"; + } + + if ( + ["application/", "audio/", "image/", "video/"].some((type) => + cleanContent.startsWith(type), + ) + ) { + return "blob"; + } + + if (cleanContent.startsWith("text/")) { + return "text"; + } + + return; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, "security"> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? "Authorization"; + + switch (auth.in) { + case "query": + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case "cookie": + options.headers.append("Cookie", `${name}=${token}`); + break; + case "header": + default: + options.headers.set(name, token); + break; + } + + return; + } +}; + +export const buildUrl: Client["buildUrl"] = (options) => { + const url = getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === "function" + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = (baseUrl ?? "") + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ""; + if (search.startsWith("?")) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith("/")) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +export const mergeHeaders = ( + ...headers: Array["headers"] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header || typeof header !== "object") { + continue; + } + + const iterator = + header instanceof Headers ? header.entries() : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === "object" ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + _fns: (Interceptor | null)[]; + + constructor() { + this._fns = []; + } + + clear() { + this._fns = []; + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === "number") { + return this._fns[id] ? id : -1; + } else { + return this._fns.indexOf(id); + } + } + exists(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + return !!this._fns[index]; + } + + eject(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = null; + } + } + + update(id: number | Interceptor, fn: Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = fn; + return id; + } else { + return false; + } + } + + use(fn: Interceptor) { + this._fns = [...this._fns, fn]; + return this._fns.length - 1; + } +} + +// `createInterceptors()` response, meant for external use as it does not +// expose internals +export interface Middleware { + error: Pick< + Interceptors>, + "eject" | "use" + >; + request: Pick>, "eject" | "use">; + response: Pick< + Interceptors>, + "eject" | "use" + >; +} + +// do not add `Middleware` as return type so we can use _fns internally +export const createInterceptors = () => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: "form", + }, + object: { + explode: true, + style: "deepObject", + }, +}); + +const defaultHeaders = { + "Content-Type": "application/json", +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: "auto", + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/packages/engine/src/client/core/auth.ts b/packages/engine/src/client/core/auth.ts new file mode 100644 index 00000000000..70e9d5dba5e --- /dev/null +++ b/packages/engine/src/client/core/auth.ts @@ -0,0 +1,40 @@ +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: "header" | "query" | "cookie"; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: "basic" | "bearer"; + type: "apiKey" | "http"; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = + typeof callback === "function" ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === "bearer") { + return `Bearer ${token}`; + } + + if (auth.scheme === "basic") { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/packages/engine/src/client/core/bodySerializer.ts b/packages/engine/src/client/core/bodySerializer.ts new file mode 100644 index 00000000000..e68daa47a7b --- /dev/null +++ b/packages/engine/src/client/core/bodySerializer.ts @@ -0,0 +1,84 @@ +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer.js"; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +export interface QuerySerializerOptions { + allowReserved?: boolean; + array?: SerializerOptions; + object?: SerializerOptions; +} + +const serializeFormDataPair = (data: FormData, key: string, value: unknown) => { + if (typeof value === "string" || value instanceof Blob) { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +) => { + if (typeof value === "string") { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new FormData(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: T) => + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value, + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new URLSearchParams(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/packages/engine/src/client/core/params.ts b/packages/engine/src/client/core/params.ts new file mode 100644 index 00000000000..0771542b148 --- /dev/null +++ b/packages/engine/src/client/core/params.ts @@ -0,0 +1,141 @@ +type Slot = "body" | "headers" | "path" | "query"; + +export type Field = + | { + in: Exclude; + key: string; + map?: string; + } + | { + in: Extract; + key?: string; + map?: string; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: "body", + $headers_: "headers", + $path_: "path", + $query_: "query", +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + { + in: Slot; + map?: string; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ("in" in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === "object" && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ("in" in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + (params[field.in] as Record)[name] = arg; + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else { + for (const [slot, allowed] of Object.entries( + config.allowExtra ?? {}, + )) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/packages/engine/src/client/core/pathSerializer.ts b/packages/engine/src/client/core/pathSerializer.ts new file mode 100644 index 00000000000..4052ad12795 --- /dev/null +++ b/packages/engine/src/client/core/pathSerializer.ts @@ -0,0 +1,179 @@ +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = "label" | "matrix" | "simple"; +export type ObjectStyle = "form" | "deepObject"; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "form": + return ","; + case "pipeDelimited": + return "|"; + case "spaceDelimited": + return "%20"; + default: + return ","; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + case "simple": + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === "label" || style === "simple") { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ""; + } + + if (typeof value === "object") { + throw new Error( + "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== "deepObject" && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; + }); + const joinedValues = values.join(","); + switch (style) { + case "form": + return `${name}=${joinedValues}`; + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === "deepObject" ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; diff --git a/packages/engine/src/client/core/types.ts b/packages/engine/src/client/core/types.ts new file mode 100644 index 00000000000..41322e707cb --- /dev/null +++ b/packages/engine/src/client/core/types.ts @@ -0,0 +1,98 @@ +import type { Auth, AuthToken } from "./auth.js"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.js"; + +export interface Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, +> { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + connect: MethodFn; + delete: MethodFn; + get: MethodFn; + getConfig: () => Config; + head: MethodFn; + options: MethodFn; + patch: MethodFn; + post: MethodFn; + put: MethodFn; + request: RequestFn; + setConfig: (config: Config) => Config; + trace: MethodFn; +} + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit["headers"] + | Record< + string, + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: + | "CONNECT" + | "DELETE" + | "GET" + | "HEAD" + | "OPTIONS" + | "PATCH" + | "POST" + | "PUT" + | "TRACE"; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} diff --git a/packages/engine/src/client/sdk.gen.ts b/packages/engine/src/client/sdk.gen.ts index d5b748b73b3..5c9c02a09d2 100644 --- a/packages/engine/src/client/sdk.gen.ts +++ b/packages/engine/src/client/sdk.gen.ts @@ -4,35 +4,37 @@ import type { Client, Options as ClientOptions, TDataShape, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import { client as _heyApiClient } from "./client.gen.js"; import type { CreateAccountData, - CreateAccountResponse, + CreateAccountResponses, EncodeFunctionDataData, - EncodeFunctionDataResponse, + EncodeFunctionDataResponses, GetNativeBalanceData, - GetNativeBalanceResponse, + GetNativeBalanceErrors, + GetNativeBalanceResponses, GetTransactionAnalyticsData, - GetTransactionAnalyticsResponse, + GetTransactionAnalyticsResponses, GetTransactionAnalyticsSummaryData, - GetTransactionAnalyticsSummaryResponse, + GetTransactionAnalyticsSummaryErrors, + GetTransactionAnalyticsSummaryResponses, ListAccountsData, - ListAccountsResponse, + ListAccountsResponses, ReadContractData, - ReadContractResponse, + ReadContractResponses, SearchTransactionsData, - SearchTransactionsResponse, + SearchTransactionsResponses, SendTransactionData, - SendTransactionResponse, + SendTransactionResponses, SignMessageData, - SignMessageResponse, + SignMessageResponses, SignTransactionData, - SignTransactionResponse, + SignTransactionResponses, SignTypedDataData, - SignTypedDataResponse, + SignTypedDataResponses, WriteContractData, - WriteContractResponse, + WriteContractResponses, } from "./types.gen.js"; export type Options< @@ -60,7 +62,7 @@ export const listAccounts = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - ListAccountsResponse, + ListAccountsResponses, unknown, ThrowOnError >({ @@ -83,7 +85,7 @@ export const createAccount = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - CreateAccountResponse, + CreateAccountResponses, unknown, ThrowOnError >({ @@ -110,7 +112,7 @@ export const writeContract = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - WriteContractResponse, + WriteContractResponses, unknown, ThrowOnError >({ @@ -137,7 +139,7 @@ export const sendTransaction = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SendTransactionResponse, + SendTransactionResponses, unknown, ThrowOnError >({ @@ -164,7 +166,7 @@ export const signTransaction = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SignTransactionResponse, + SignTransactionResponses, unknown, ThrowOnError >({ @@ -191,7 +193,7 @@ export const signMessage = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SignMessageResponse, + SignMessageResponses, unknown, ThrowOnError >({ @@ -218,7 +220,7 @@ export const signTypedData = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SignTypedDataResponse, + SignTypedDataResponses, unknown, ThrowOnError >({ @@ -245,7 +247,7 @@ export const readContract = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - ReadContractResponse, + ReadContractResponses, unknown, ThrowOnError >({ @@ -272,8 +274,8 @@ export const getNativeBalance = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - GetNativeBalanceResponse, - unknown, + GetNativeBalanceResponses, + GetNativeBalanceErrors, ThrowOnError >({ security: [ @@ -299,7 +301,7 @@ export const encodeFunctionData = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - EncodeFunctionDataResponse, + EncodeFunctionDataResponses, unknown, ThrowOnError >({ @@ -326,7 +328,7 @@ export const searchTransactions = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SearchTransactionsResponse, + SearchTransactionsResponses, unknown, ThrowOnError >({ @@ -353,7 +355,7 @@ export const getTransactionAnalytics = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsResponse, + GetTransactionAnalyticsResponses, unknown, ThrowOnError >({ @@ -382,8 +384,8 @@ export const getTransactionAnalyticsSummary = < options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsSummaryResponse, - unknown, + GetTransactionAnalyticsSummaryResponses, + GetTransactionAnalyticsSummaryErrors, ThrowOnError >({ security: [ diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 064ab2ad8bd..56424f028fb 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -18,6 +18,7 @@ export type TransactionsFilterNested = { }; /** + * Auto-determine Best Execution Options * This is the default execution option. If you do not specify an execution type, and only specify a "from" string, engine will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. */ export type AutoExecutionOptions = { @@ -39,6 +40,9 @@ export type AutoExecutionOptions = { chainId: string; }; +/** + * ERC4337 Execution (Smart Account) + */ export type AaExecutionOptions = { type: "ERC4337"; /** @@ -73,6 +77,7 @@ export type AaExecutionOptions = { }; /** + * AA:zksync Execution Options * Uses zkSync native AA for execution. This type of execution is only available on zkSync chains. */ export type AaZksyncExecutionOptions = { @@ -131,6 +136,7 @@ export type ListAccountsResponses = { * EVM address in hex format */ address: string; + label?: string; /** * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory */ @@ -167,6 +173,7 @@ export type CreateAccountResponses = { * EVM address in hex format */ address: string; + label?: string; /** * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory */ diff --git a/packages/engine/src/configure.ts b/packages/engine/src/configure.ts index edc7316dc82..a115d77acbb 100644 --- a/packages/engine/src/configure.ts +++ b/packages/engine/src/configure.ts @@ -1,4 +1,4 @@ -import type { Config } from "@hey-api/client-fetch"; +import type { Config } from "./client/client/index.js"; import { client } from "./client/client.gen.js"; export type EngineClientOptions = { diff --git a/packages/engine/tsconfig.base.json b/packages/engine/tsconfig.base.json index 1dfe1e7b2ce..f0e556fd3c6 100644 --- a/packages/engine/tsconfig.base.json +++ b/packages/engine/tsconfig.base.json @@ -20,7 +20,8 @@ "jsx": "react-jsx", "lib": [ "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. - "DOM" // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM", // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM.Iterable" // Adding `DOM.Iterable` for the Headers.entries() method. ], "module": "NodeNext", diff --git a/packages/insight/package.json b/packages/insight/package.json index dcf341a9f1c..f371ddff756 100644 --- a/packages/insight/package.json +++ b/packages/insight/package.json @@ -27,12 +27,9 @@ "dist/*", "src/*" ], - "dependencies": { - "@hey-api/client-fetch": "0.10.0" - }, "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.72.1", + "@hey-api/openapi-ts": "0.76.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, diff --git a/packages/insight/src/client/client.gen.ts b/packages/insight/src/client/client.gen.ts index 0da7c63fefd..accc0a34013 100644 --- a/packages/insight/src/client/client.gen.ts +++ b/packages/insight/src/client/client.gen.ts @@ -5,7 +5,7 @@ import { createClient, createConfig, type ClientOptions as DefaultClientOptions, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import type { ClientOptions } from "./types.gen.js"; /** diff --git a/packages/insight/src/client/client/client.ts b/packages/insight/src/client/client/client.ts new file mode 100644 index 00000000000..8cb5e5bde84 --- /dev/null +++ b/packages/insight/src/client/client/client.ts @@ -0,0 +1,189 @@ +import type { Client, Config, RequestOptions } from "./types.js"; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from "./utils.js"; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors< + Request, + Response, + unknown, + RequestOptions + >(); + + const request: Client["request"] = async (options) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.body && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.body === "") { + opts.headers.delete("Content-Type"); + } + + const url = buildUrl(opts); + const requestInit: ReqInit = { + redirect: "follow", + ...opts, + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request._fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response = await _fetch(request); + + for (const fn of interceptors.response._fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + if ( + response.status === 204 || + response.headers.get("Content-Length") === "0" + ) { + return opts.responseStyle === "data" + ? {} + : { + data: {}, + ...result, + }; + } + + const parseAs = + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json"; + + let data: any; + switch (parseAs) { + case "arrayBuffer": + case "blob": + case "formData": + case "json": + case "text": + data = await response[parseAs](); + break; + case "stream": + return opts.responseStyle === "data" + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === "json") { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === "data" + ? data + : { + data, + ...result, + }; + } + + let error = await response.text(); + + try { + error = JSON.parse(error); + } catch { + // noop + } + + let finalError = error; + + for (const fn of interceptors.error._fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === "data" + ? undefined + : { + error: finalError, + ...result, + }; + }; + + return { + buildUrl, + connect: (options) => request({ ...options, method: "CONNECT" }), + delete: (options) => request({ ...options, method: "DELETE" }), + get: (options) => request({ ...options, method: "GET" }), + getConfig, + head: (options) => request({ ...options, method: "HEAD" }), + interceptors, + options: (options) => request({ ...options, method: "OPTIONS" }), + patch: (options) => request({ ...options, method: "PATCH" }), + post: (options) => request({ ...options, method: "POST" }), + put: (options) => request({ ...options, method: "PUT" }), + request, + setConfig, + trace: (options) => request({ ...options, method: "TRACE" }), + }; +}; diff --git a/packages/insight/src/client/client/index.ts b/packages/insight/src/client/client/index.ts new file mode 100644 index 00000000000..33d0123ce32 --- /dev/null +++ b/packages/insight/src/client/client/index.ts @@ -0,0 +1,22 @@ +export type { Auth } from "../core/auth.js"; +export type { QuerySerializerOptions } from "../core/bodySerializer.js"; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from "../core/bodySerializer.js"; +export { buildClientParams } from "../core/params.js"; +export { createClient } from "./client.js"; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + OptionsLegacyParser, + RequestOptions, + RequestResult, + ResponseStyle, + TDataShape, +} from "./types.js"; +export { createConfig, mergeHeaders } from "./utils.js"; diff --git a/packages/insight/src/client/client/types.ts b/packages/insight/src/client/client/types.ts new file mode 100644 index 00000000000..6d37980f22f --- /dev/null +++ b/packages/insight/src/client/client/types.ts @@ -0,0 +1,222 @@ +import type { Auth } from "../core/auth.js"; +import type { + Client as CoreClient, + Config as CoreConfig, +} from "../core/types.js"; +import type { Middleware } from "./utils.js"; + +export type ResponseStyle = "data" | "fields"; + +export interface Config + extends Omit, + CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T["baseUrl"]; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: (request: Request) => ReturnType; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: + | "arrayBuffer" + | "auto" + | "blob" + | "formData" + | "json" + | "stream" + | "text"; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T["throwOnError"]; +} + +export interface RequestOptions< + TResponseStyle extends ResponseStyle = "fields", + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }> { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends "data" + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record + ? TData[keyof TData] + : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends "data" + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined + : ( + | { + data: TData extends Record + ? TData[keyof TData] + : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method">, +) => RequestResult; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method"> & + Pick>, "method">, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: Pick & Options, +) => string; + +export type Client = CoreClient & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = OmitKeys< + RequestOptions, + "body" | "path" | "query" | "url" +> & + Omit; + +export type OptionsLegacyParser< + TData = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = TData extends { body?: any } + ? TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "body" | "headers" | "url" + > & + TData + : OmitKeys, "body" | "url"> & + TData & + Pick, "headers"> + : TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "headers" | "url" + > & + TData & + Pick, "body"> + : OmitKeys, "url"> & TData; diff --git a/packages/insight/src/client/client/utils.ts b/packages/insight/src/client/client/utils.ts new file mode 100644 index 00000000000..e56e804226f --- /dev/null +++ b/packages/insight/src/client/client/utils.ts @@ -0,0 +1,416 @@ +import { getAuthToken } from "../core/auth.js"; +import type { + QuerySerializer, + QuerySerializerOptions, +} from "../core/bodySerializer.js"; +import { jsonBodySerializer } from "../core/bodySerializer.js"; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer.js"; +import type { Client, ClientOptions, Config, RequestOptions } from "./types.js"; + +interface PathSerializer { + path: Record; + url: string; +} + +const PATH_PARAM_RE = /\{[^{}]+\}/g; + +type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +type MatrixStyle = "label" | "matrix" | "simple"; +type ArraySeparatorStyle = ArrayStyle | MatrixStyle; + +const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = "simple"; + + if (name.endsWith("*")) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith(".")) { + name = name.substring(1); + style = "label"; + } else if (name.startsWith(";")) { + name = name.substring(1); + style = "matrix"; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); + continue; + } + + if (typeof value === "object") { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === "matrix") { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === "label" ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const createQuerySerializer = ({ + allowReserved, + array, + object, +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === "object") { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved, + explode: true, + name, + style: "form", + value, + ...array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === "object") { + const serializedObject = serializeObjectParam({ + allowReserved, + explode: true, + name, + style: "deepObject", + value: value as Record, + ...object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join("&"); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = ( + contentType: string | null, +): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return "stream"; + } + + const cleanContent = contentType.split(";")[0]?.trim(); + + if (!cleanContent) { + return; + } + + if ( + cleanContent.startsWith("application/json") || + cleanContent.endsWith("+json") + ) { + return "json"; + } + + if (cleanContent === "multipart/form-data") { + return "formData"; + } + + if ( + ["application/", "audio/", "image/", "video/"].some((type) => + cleanContent.startsWith(type), + ) + ) { + return "blob"; + } + + if (cleanContent.startsWith("text/")) { + return "text"; + } + + return; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, "security"> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? "Authorization"; + + switch (auth.in) { + case "query": + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case "cookie": + options.headers.append("Cookie", `${name}=${token}`); + break; + default: + options.headers.set(name, token); + break; + } + + return; + } +}; + +export const buildUrl: Client["buildUrl"] = (options) => { + const url = getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === "function" + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = (baseUrl ?? "") + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ""; + if (search.startsWith("?")) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith("/")) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +export const mergeHeaders = ( + ...headers: Array["headers"] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header || typeof header !== "object") { + continue; + } + + const iterator = + header instanceof Headers ? header.entries() : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === "object" ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + _fns: (Interceptor | null)[]; + + constructor() { + this._fns = []; + } + + clear() { + this._fns = []; + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === "number") { + return this._fns[id] ? id : -1; + } else { + return this._fns.indexOf(id); + } + } + exists(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + return !!this._fns[index]; + } + + eject(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = null; + } + } + + update(id: number | Interceptor, fn: Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = fn; + return id; + } else { + return false; + } + } + + use(fn: Interceptor) { + this._fns = [...this._fns, fn]; + return this._fns.length - 1; + } +} + +// `createInterceptors()` response, meant for external use as it does not +// expose internals +export interface Middleware { + error: Pick< + Interceptors>, + "eject" | "use" + >; + request: Pick>, "eject" | "use">; + response: Pick< + Interceptors>, + "eject" | "use" + >; +} + +// do not add `Middleware` as return type so we can use _fns internally +export const createInterceptors = () => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: "form", + }, + object: { + explode: true, + style: "deepObject", + }, +}); + +const defaultHeaders = { + "Content-Type": "application/json", +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: "auto", + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/packages/insight/src/client/core/auth.ts b/packages/insight/src/client/core/auth.ts new file mode 100644 index 00000000000..70e9d5dba5e --- /dev/null +++ b/packages/insight/src/client/core/auth.ts @@ -0,0 +1,40 @@ +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: "header" | "query" | "cookie"; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: "basic" | "bearer"; + type: "apiKey" | "http"; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = + typeof callback === "function" ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === "bearer") { + return `Bearer ${token}`; + } + + if (auth.scheme === "basic") { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/packages/insight/src/client/core/bodySerializer.ts b/packages/insight/src/client/core/bodySerializer.ts new file mode 100644 index 00000000000..e68daa47a7b --- /dev/null +++ b/packages/insight/src/client/core/bodySerializer.ts @@ -0,0 +1,84 @@ +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer.js"; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +export interface QuerySerializerOptions { + allowReserved?: boolean; + array?: SerializerOptions; + object?: SerializerOptions; +} + +const serializeFormDataPair = (data: FormData, key: string, value: unknown) => { + if (typeof value === "string" || value instanceof Blob) { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +) => { + if (typeof value === "string") { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new FormData(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: T) => + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value, + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new URLSearchParams(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/packages/insight/src/client/core/params.ts b/packages/insight/src/client/core/params.ts new file mode 100644 index 00000000000..0771542b148 --- /dev/null +++ b/packages/insight/src/client/core/params.ts @@ -0,0 +1,141 @@ +type Slot = "body" | "headers" | "path" | "query"; + +export type Field = + | { + in: Exclude; + key: string; + map?: string; + } + | { + in: Extract; + key?: string; + map?: string; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: "body", + $headers_: "headers", + $path_: "path", + $query_: "query", +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + { + in: Slot; + map?: string; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ("in" in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === "object" && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ("in" in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + (params[field.in] as Record)[name] = arg; + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else { + for (const [slot, allowed] of Object.entries( + config.allowExtra ?? {}, + )) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/packages/insight/src/client/core/pathSerializer.ts b/packages/insight/src/client/core/pathSerializer.ts new file mode 100644 index 00000000000..4052ad12795 --- /dev/null +++ b/packages/insight/src/client/core/pathSerializer.ts @@ -0,0 +1,179 @@ +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = "label" | "matrix" | "simple"; +export type ObjectStyle = "form" | "deepObject"; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "form": + return ","; + case "pipeDelimited": + return "|"; + case "spaceDelimited": + return "%20"; + default: + return ","; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + case "simple": + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === "label" || style === "simple") { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ""; + } + + if (typeof value === "object") { + throw new Error( + "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== "deepObject" && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; + }); + const joinedValues = values.join(","); + switch (style) { + case "form": + return `${name}=${joinedValues}`; + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === "deepObject" ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; diff --git a/packages/insight/src/client/core/types.ts b/packages/insight/src/client/core/types.ts new file mode 100644 index 00000000000..41322e707cb --- /dev/null +++ b/packages/insight/src/client/core/types.ts @@ -0,0 +1,98 @@ +import type { Auth, AuthToken } from "./auth.js"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.js"; + +export interface Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, +> { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + connect: MethodFn; + delete: MethodFn; + get: MethodFn; + getConfig: () => Config; + head: MethodFn; + options: MethodFn; + patch: MethodFn; + post: MethodFn; + put: MethodFn; + request: RequestFn; + setConfig: (config: Config) => Config; + trace: MethodFn; +} + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit["headers"] + | Record< + string, + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: + | "CONNECT" + | "DELETE" + | "GET" + | "HEAD" + | "OPTIONS" + | "PATCH" + | "POST" + | "PUT" + | "TRACE"; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} diff --git a/packages/insight/src/client/sdk.gen.ts b/packages/insight/src/client/sdk.gen.ts index 3c73002784c..e5314509d50 100644 --- a/packages/insight/src/client/sdk.gen.ts +++ b/packages/insight/src/client/sdk.gen.ts @@ -4,124 +4,132 @@ import type { Client, Options as ClientOptions, TDataShape, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import { client as _heyApiClient } from "./client.gen.js"; import type { DeleteV1WebhooksByWebhookIdData, - DeleteV1WebhooksByWebhookIdError, - DeleteV1WebhooksByWebhookIdResponse, + DeleteV1WebhooksByWebhookIdErrors, + DeleteV1WebhooksByWebhookIdResponses, GetV1BlocksData, - GetV1BlocksError, - GetV1BlocksResponse, + GetV1BlocksErrors, + GetV1BlocksResponses, GetV1ContractsAbiByContractAddressData, - GetV1ContractsAbiByContractAddressError, - GetV1ContractsAbiByContractAddressResponse, + GetV1ContractsAbiByContractAddressErrors, + GetV1ContractsAbiByContractAddressResponses, GetV1ContractsMetadataByContractAddressData, - GetV1ContractsMetadataByContractAddressError, - GetV1ContractsMetadataByContractAddressResponse, + GetV1ContractsMetadataByContractAddressErrors, + GetV1ContractsMetadataByContractAddressResponses, GetV1EventsByContractAddressBySignatureData, - GetV1EventsByContractAddressBySignatureError, - GetV1EventsByContractAddressBySignatureResponse, + GetV1EventsByContractAddressBySignatureErrors, + GetV1EventsByContractAddressBySignatureResponses, GetV1EventsByContractAddressData, - GetV1EventsByContractAddressError, - GetV1EventsByContractAddressResponse, + GetV1EventsByContractAddressErrors, + GetV1EventsByContractAddressResponses, GetV1EventsData, - GetV1EventsError, - GetV1EventsResponse, + GetV1EventsErrors, + GetV1EventsResponses, GetV1NftsBalanceByOwnerAddressData, - GetV1NftsBalanceByOwnerAddressResponse, + GetV1NftsBalanceByOwnerAddressErrors, + GetV1NftsBalanceByOwnerAddressResponses, GetV1NftsByContractAddressByTokenIdData, - GetV1NftsByContractAddressByTokenIdError, - GetV1NftsByContractAddressByTokenIdResponse, + GetV1NftsByContractAddressByTokenIdErrors, + GetV1NftsByContractAddressByTokenIdResponses, GetV1NftsByContractAddressData, - GetV1NftsByContractAddressError, - GetV1NftsByContractAddressResponse, + GetV1NftsByContractAddressErrors, + GetV1NftsByContractAddressResponses, GetV1NftsCollectionsByContractAddressData, - GetV1NftsCollectionsByContractAddressError, - GetV1NftsCollectionsByContractAddressResponse, + GetV1NftsCollectionsByContractAddressErrors, + GetV1NftsCollectionsByContractAddressResponses, GetV1NftsData, - GetV1NftsError, + GetV1NftsErrors, GetV1NftsMetadataRefreshByContractAddressByTokenIdData, - GetV1NftsMetadataRefreshByContractAddressByTokenIdError, - GetV1NftsMetadataRefreshByContractAddressByTokenIdResponse, + GetV1NftsMetadataRefreshByContractAddressByTokenIdErrors, + GetV1NftsMetadataRefreshByContractAddressByTokenIdResponses, GetV1NftsMetadataRefreshByContractAddressData, - GetV1NftsMetadataRefreshByContractAddressError, - GetV1NftsMetadataRefreshByContractAddressResponse, + GetV1NftsMetadataRefreshByContractAddressErrors, + GetV1NftsMetadataRefreshByContractAddressResponses, GetV1NftsOwnersByContractAddressByTokenIdData, - GetV1NftsOwnersByContractAddressByTokenIdError, - GetV1NftsOwnersByContractAddressByTokenIdResponse, + GetV1NftsOwnersByContractAddressByTokenIdErrors, + GetV1NftsOwnersByContractAddressByTokenIdResponses, GetV1NftsOwnersByContractAddressData, - GetV1NftsOwnersByContractAddressError, - GetV1NftsOwnersByContractAddressResponse, - GetV1NftsResponse, + GetV1NftsOwnersByContractAddressErrors, + GetV1NftsOwnersByContractAddressResponses, + GetV1NftsResponses, GetV1NftsTransfersByContractAddressByTokenIdData, - GetV1NftsTransfersByContractAddressByTokenIdError, - GetV1NftsTransfersByContractAddressByTokenIdResponse, + GetV1NftsTransfersByContractAddressByTokenIdErrors, + GetV1NftsTransfersByContractAddressByTokenIdResponses, GetV1NftsTransfersByContractAddressData, - GetV1NftsTransfersByContractAddressError, - GetV1NftsTransfersByContractAddressResponse, + GetV1NftsTransfersByContractAddressErrors, + GetV1NftsTransfersByContractAddressResponses, GetV1NftsTransfersData, - GetV1NftsTransfersError, - GetV1NftsTransfersResponse, + GetV1NftsTransfersErrors, + GetV1NftsTransfersResponses, GetV1NftsTransfersTransactionByTransactionHashData, - GetV1NftsTransfersTransactionByTransactionHashError, - GetV1NftsTransfersTransactionByTransactionHashResponse, + GetV1NftsTransfersTransactionByTransactionHashErrors, + GetV1NftsTransfersTransactionByTransactionHashResponses, GetV1ResolveByInputData, - GetV1ResolveByInputError, - GetV1ResolveByInputResponse, + GetV1ResolveByInputErrors, + GetV1ResolveByInputResponses, GetV1TokensData, GetV1TokensErc20ByOwnerAddressData, - GetV1TokensErc20ByOwnerAddressResponse, + GetV1TokensErc20ByOwnerAddressErrors, + GetV1TokensErc20ByOwnerAddressResponses, GetV1TokensErc721ByOwnerAddressData, - GetV1TokensErc721ByOwnerAddressResponse, + GetV1TokensErc721ByOwnerAddressErrors, + GetV1TokensErc721ByOwnerAddressResponses, GetV1TokensErc1155ByOwnerAddressData, - GetV1TokensErc1155ByOwnerAddressResponse, + GetV1TokensErc1155ByOwnerAddressErrors, + GetV1TokensErc1155ByOwnerAddressResponses, + GetV1TokensErrors, GetV1TokensLookupData, - GetV1TokensLookupResponse, + GetV1TokensLookupErrors, + GetV1TokensLookupResponses, GetV1TokensOwnersData, - GetV1TokensOwnersError, - GetV1TokensOwnersResponse, + GetV1TokensOwnersErrors, + GetV1TokensOwnersResponses, GetV1TokensPriceData, - GetV1TokensPriceResponse, + GetV1TokensPriceErrors, + GetV1TokensPriceResponses, GetV1TokensPriceSupportedData, - GetV1TokensPriceSupportedResponse, - GetV1TokensResponse, + GetV1TokensPriceSupportedErrors, + GetV1TokensPriceSupportedResponses, + GetV1TokensResponses, GetV1TokensTransfersByContractAddressData, - GetV1TokensTransfersByContractAddressError, - GetV1TokensTransfersByContractAddressResponse, + GetV1TokensTransfersByContractAddressErrors, + GetV1TokensTransfersByContractAddressResponses, GetV1TokensTransfersData, - GetV1TokensTransfersError, - GetV1TokensTransfersResponse, + GetV1TokensTransfersErrors, + GetV1TokensTransfersResponses, GetV1TokensTransfersTransactionByTransactionHashData, - GetV1TokensTransfersTransactionByTransactionHashError, - GetV1TokensTransfersTransactionByTransactionHashResponse, + GetV1TokensTransfersTransactionByTransactionHashErrors, + GetV1TokensTransfersTransactionByTransactionHashResponses, GetV1TransactionsByContractAddressBySignatureData, - GetV1TransactionsByContractAddressBySignatureError, - GetV1TransactionsByContractAddressBySignatureResponse, + GetV1TransactionsByContractAddressBySignatureErrors, + GetV1TransactionsByContractAddressBySignatureResponses, GetV1TransactionsByContractAddressData, - GetV1TransactionsByContractAddressError, - GetV1TransactionsByContractAddressResponse, + GetV1TransactionsByContractAddressErrors, + GetV1TransactionsByContractAddressResponses, GetV1TransactionsData, - GetV1TransactionsError, - GetV1TransactionsResponse, + GetV1TransactionsErrors, + GetV1TransactionsResponses, GetV1WalletsByWalletAddressTransactionsData, - GetV1WalletsByWalletAddressTransactionsError, - GetV1WalletsByWalletAddressTransactionsResponse, + GetV1WalletsByWalletAddressTransactionsErrors, + GetV1WalletsByWalletAddressTransactionsResponses, GetV1WebhooksData, - GetV1WebhooksError, - GetV1WebhooksResponse, + GetV1WebhooksErrors, + GetV1WebhooksResponses, PatchV1WebhooksByWebhookIdData, - PatchV1WebhooksByWebhookIdError, - PatchV1WebhooksByWebhookIdResponse, + PatchV1WebhooksByWebhookIdErrors, + PatchV1WebhooksByWebhookIdResponses, PostV1DecodeByContractAddressData, - PostV1DecodeByContractAddressError, - PostV1DecodeByContractAddressResponse, + PostV1DecodeByContractAddressErrors, + PostV1DecodeByContractAddressResponses, PostV1WebhooksData, - PostV1WebhooksError, - PostV1WebhooksResponse, + PostV1WebhooksErrors, + PostV1WebhooksResponses, PostV1WebhooksTestData, - PostV1WebhooksTestError, - PostV1WebhooksTestResponse, + PostV1WebhooksTestErrors, + PostV1WebhooksTestResponses, } from "./types.gen.js"; export type Options< @@ -149,8 +157,8 @@ export const getV1Webhooks = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1WebhooksResponse, - GetV1WebhooksError, + GetV1WebhooksResponses, + GetV1WebhooksErrors, ThrowOnError >({ security: [ @@ -172,8 +180,8 @@ export const postV1Webhooks = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - PostV1WebhooksResponse, - PostV1WebhooksError, + PostV1WebhooksResponses, + PostV1WebhooksErrors, ThrowOnError >({ security: [ @@ -201,8 +209,8 @@ export const deleteV1WebhooksByWebhookId = < options: Options, ) => { return (options.client ?? _heyApiClient).delete< - DeleteV1WebhooksByWebhookIdResponse, - DeleteV1WebhooksByWebhookIdError, + DeleteV1WebhooksByWebhookIdResponses, + DeleteV1WebhooksByWebhookIdErrors, ThrowOnError >({ security: [ @@ -226,8 +234,8 @@ export const patchV1WebhooksByWebhookId = < options: Options, ) => { return (options.client ?? _heyApiClient).patch< - PatchV1WebhooksByWebhookIdResponse, - PatchV1WebhooksByWebhookIdError, + PatchV1WebhooksByWebhookIdResponses, + PatchV1WebhooksByWebhookIdErrors, ThrowOnError >({ security: [ @@ -240,7 +248,7 @@ export const patchV1WebhooksByWebhookId = < ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; @@ -253,8 +261,8 @@ export const postV1WebhooksTest = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - PostV1WebhooksTestResponse, - PostV1WebhooksTestError, + PostV1WebhooksTestResponses, + PostV1WebhooksTestErrors, ThrowOnError >({ security: [ @@ -280,8 +288,8 @@ export const getV1Events = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1EventsResponse, - GetV1EventsError, + GetV1EventsResponses, + GetV1EventsErrors, ThrowOnError >({ security: [ @@ -305,8 +313,8 @@ export const getV1EventsByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1EventsByContractAddressResponse, - GetV1EventsByContractAddressError, + GetV1EventsByContractAddressResponses, + GetV1EventsByContractAddressErrors, ThrowOnError >({ security: [ @@ -330,8 +338,8 @@ export const getV1EventsByContractAddressBySignature = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1EventsByContractAddressBySignatureResponse, - GetV1EventsByContractAddressBySignatureError, + GetV1EventsByContractAddressBySignatureResponses, + GetV1EventsByContractAddressBySignatureErrors, ThrowOnError >({ security: [ @@ -353,8 +361,8 @@ export const getV1Transactions = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1TransactionsResponse, - GetV1TransactionsError, + GetV1TransactionsResponses, + GetV1TransactionsErrors, ThrowOnError >({ security: [ @@ -378,8 +386,8 @@ export const getV1TransactionsByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TransactionsByContractAddressResponse, - GetV1TransactionsByContractAddressError, + GetV1TransactionsByContractAddressResponses, + GetV1TransactionsByContractAddressErrors, ThrowOnError >({ security: [ @@ -406,8 +414,8 @@ export const getV1TransactionsByContractAddressBySignature = < >, ) => { return (options.client ?? _heyApiClient).get< - GetV1TransactionsByContractAddressBySignatureResponse, - GetV1TransactionsByContractAddressBySignatureError, + GetV1TransactionsByContractAddressBySignatureResponses, + GetV1TransactionsByContractAddressBySignatureErrors, ThrowOnError >({ security: [ @@ -429,8 +437,8 @@ export const getV1TokensOwners = ( options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensOwnersResponse, - GetV1TokensOwnersError, + GetV1TokensOwnersResponses, + GetV1TokensOwnersErrors, ThrowOnError >({ security: [ @@ -457,8 +465,8 @@ export const getV1TokensTransfersTransactionByTransactionHash = < >, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensTransfersTransactionByTransactionHashResponse, - GetV1TokensTransfersTransactionByTransactionHashError, + GetV1TokensTransfersTransactionByTransactionHashResponses, + GetV1TokensTransfersTransactionByTransactionHashErrors, ThrowOnError >({ security: [ @@ -482,8 +490,8 @@ export const getV1TokensTransfersByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensTransfersByContractAddressResponse, - GetV1TokensTransfersByContractAddressError, + GetV1TokensTransfersByContractAddressResponses, + GetV1TokensTransfersByContractAddressErrors, ThrowOnError >({ security: [ @@ -505,8 +513,8 @@ export const getV1TokensTransfers = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1TokensTransfersResponse, - GetV1TokensTransfersError, + GetV1TokensTransfersResponses, + GetV1TokensTransfersErrors, ThrowOnError >({ security: [ @@ -521,9 +529,9 @@ export const getV1TokensTransfers = ( }; /** - * @deprecated * Get ERC-20 balances by address * Get ERC-20 balances for a given address. [BEING DEPRECATED IN FAVOR OF /tokens] + * @deprecated */ export const getV1TokensErc20ByOwnerAddress = < ThrowOnError extends boolean = false, @@ -531,8 +539,8 @@ export const getV1TokensErc20ByOwnerAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensErc20ByOwnerAddressResponse, - unknown, + GetV1TokensErc20ByOwnerAddressResponses, + GetV1TokensErc20ByOwnerAddressErrors, ThrowOnError >({ security: [ @@ -554,8 +562,8 @@ export const getV1Tokens = ( options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensResponse, - unknown, + GetV1TokensResponses, + GetV1TokensErrors, ThrowOnError >({ security: [ @@ -570,9 +578,9 @@ export const getV1Tokens = ( }; /** - * @deprecated * Get ERC-721 balances by address * Get ERC-721 (NFT) balances for a given address [BEING DEPRECATED IN FAVOR OF /nfts/balance] + * @deprecated */ export const getV1TokensErc721ByOwnerAddress = < ThrowOnError extends boolean = false, @@ -580,8 +588,8 @@ export const getV1TokensErc721ByOwnerAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensErc721ByOwnerAddressResponse, - unknown, + GetV1TokensErc721ByOwnerAddressResponses, + GetV1TokensErc721ByOwnerAddressErrors, ThrowOnError >({ security: [ @@ -596,9 +604,9 @@ export const getV1TokensErc721ByOwnerAddress = < }; /** - * @deprecated * Get ERC-1155 balances by address * Get ERC-1155 (Multi Token) balances for a given address [BEING DEPRECATED IN FAVOR OF /nfts/balance] + * @deprecated */ export const getV1TokensErc1155ByOwnerAddress = < ThrowOnError extends boolean = false, @@ -606,8 +614,8 @@ export const getV1TokensErc1155ByOwnerAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensErc1155ByOwnerAddressResponse, - unknown, + GetV1TokensErc1155ByOwnerAddressResponses, + GetV1TokensErc1155ByOwnerAddressErrors, ThrowOnError >({ security: [ @@ -629,8 +637,8 @@ export const getV1TokensPriceSupported = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1TokensPriceSupportedResponse, - unknown, + GetV1TokensPriceSupportedResponses, + GetV1TokensPriceSupportedErrors, ThrowOnError >({ security: [ @@ -652,8 +660,8 @@ export const getV1TokensPrice = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1TokensPriceResponse, - unknown, + GetV1TokensPriceResponses, + GetV1TokensPriceErrors, ThrowOnError >({ security: [ @@ -675,8 +683,8 @@ export const getV1TokensLookup = ( options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1TokensLookupResponse, - unknown, + GetV1TokensLookupResponses, + GetV1TokensLookupErrors, ThrowOnError >({ security: [ @@ -698,8 +706,8 @@ export const getV1ResolveByInput = ( options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1ResolveByInputResponse, - GetV1ResolveByInputError, + GetV1ResolveByInputResponses, + GetV1ResolveByInputErrors, ThrowOnError >({ security: [ @@ -721,8 +729,8 @@ export const getV1Blocks = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1BlocksResponse, - GetV1BlocksError, + GetV1BlocksResponses, + GetV1BlocksErrors, ThrowOnError >({ security: [ @@ -746,8 +754,8 @@ export const getV1ContractsAbiByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1ContractsAbiByContractAddressResponse, - GetV1ContractsAbiByContractAddressError, + GetV1ContractsAbiByContractAddressResponses, + GetV1ContractsAbiByContractAddressErrors, ThrowOnError >({ security: [ @@ -771,8 +779,8 @@ export const getV1ContractsMetadataByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1ContractsMetadataByContractAddressResponse, - GetV1ContractsMetadataByContractAddressError, + GetV1ContractsMetadataByContractAddressResponses, + GetV1ContractsMetadataByContractAddressErrors, ThrowOnError >({ security: [ @@ -796,8 +804,8 @@ export const postV1DecodeByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).post< - PostV1DecodeByContractAddressResponse, - PostV1DecodeByContractAddressError, + PostV1DecodeByContractAddressResponses, + PostV1DecodeByContractAddressErrors, ThrowOnError >({ security: [ @@ -810,7 +818,7 @@ export const postV1DecodeByContractAddress = < ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; @@ -825,8 +833,8 @@ export const getV1NftsBalanceByOwnerAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsBalanceByOwnerAddressResponse, - unknown, + GetV1NftsBalanceByOwnerAddressResponses, + GetV1NftsBalanceByOwnerAddressErrors, ThrowOnError >({ security: [ @@ -850,8 +858,8 @@ export const getV1NftsCollectionsByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsCollectionsByContractAddressResponse, - GetV1NftsCollectionsByContractAddressError, + GetV1NftsCollectionsByContractAddressResponses, + GetV1NftsCollectionsByContractAddressErrors, ThrowOnError >({ security: [ @@ -873,8 +881,8 @@ export const getV1Nfts = ( options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsResponse, - GetV1NftsError, + GetV1NftsResponses, + GetV1NftsErrors, ThrowOnError >({ security: [ @@ -898,8 +906,8 @@ export const getV1NftsOwnersByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsOwnersByContractAddressResponse, - GetV1NftsOwnersByContractAddressError, + GetV1NftsOwnersByContractAddressResponses, + GetV1NftsOwnersByContractAddressErrors, ThrowOnError >({ security: [ @@ -923,8 +931,8 @@ export const getV1NftsOwnersByContractAddressByTokenId = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsOwnersByContractAddressByTokenIdResponse, - GetV1NftsOwnersByContractAddressByTokenIdError, + GetV1NftsOwnersByContractAddressByTokenIdResponses, + GetV1NftsOwnersByContractAddressByTokenIdErrors, ThrowOnError >({ security: [ @@ -946,8 +954,8 @@ export const getV1NftsTransfers = ( options?: Options, ) => { return (options?.client ?? _heyApiClient).get< - GetV1NftsTransfersResponse, - GetV1NftsTransfersError, + GetV1NftsTransfersResponses, + GetV1NftsTransfersErrors, ThrowOnError >({ security: [ @@ -974,8 +982,8 @@ export const getV1NftsTransfersTransactionByTransactionHash = < >, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsTransfersTransactionByTransactionHashResponse, - GetV1NftsTransfersTransactionByTransactionHashError, + GetV1NftsTransfersTransactionByTransactionHashResponses, + GetV1NftsTransfersTransactionByTransactionHashErrors, ThrowOnError >({ security: [ @@ -999,8 +1007,8 @@ export const getV1NftsTransfersByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsTransfersByContractAddressResponse, - GetV1NftsTransfersByContractAddressError, + GetV1NftsTransfersByContractAddressResponses, + GetV1NftsTransfersByContractAddressErrors, ThrowOnError >({ security: [ @@ -1024,8 +1032,8 @@ export const getV1NftsByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsByContractAddressResponse, - GetV1NftsByContractAddressError, + GetV1NftsByContractAddressResponses, + GetV1NftsByContractAddressErrors, ThrowOnError >({ security: [ @@ -1052,8 +1060,8 @@ export const getV1NftsTransfersByContractAddressByTokenId = < >, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsTransfersByContractAddressByTokenIdResponse, - GetV1NftsTransfersByContractAddressByTokenIdError, + GetV1NftsTransfersByContractAddressByTokenIdResponses, + GetV1NftsTransfersByContractAddressByTokenIdErrors, ThrowOnError >({ security: [ @@ -1077,8 +1085,8 @@ export const getV1NftsByContractAddressByTokenId = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsByContractAddressByTokenIdResponse, - GetV1NftsByContractAddressByTokenIdError, + GetV1NftsByContractAddressByTokenIdResponses, + GetV1NftsByContractAddressByTokenIdErrors, ThrowOnError >({ security: [ @@ -1102,8 +1110,8 @@ export const getV1NftsMetadataRefreshByContractAddress = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsMetadataRefreshByContractAddressResponse, - GetV1NftsMetadataRefreshByContractAddressError, + GetV1NftsMetadataRefreshByContractAddressResponses, + GetV1NftsMetadataRefreshByContractAddressErrors, ThrowOnError >({ security: [ @@ -1130,8 +1138,8 @@ export const getV1NftsMetadataRefreshByContractAddressByTokenId = < >, ) => { return (options.client ?? _heyApiClient).get< - GetV1NftsMetadataRefreshByContractAddressByTokenIdResponse, - GetV1NftsMetadataRefreshByContractAddressByTokenIdError, + GetV1NftsMetadataRefreshByContractAddressByTokenIdResponses, + GetV1NftsMetadataRefreshByContractAddressByTokenIdErrors, ThrowOnError >({ security: [ @@ -1155,8 +1163,8 @@ export const getV1WalletsByWalletAddressTransactions = < options: Options, ) => { return (options.client ?? _heyApiClient).get< - GetV1WalletsByWalletAddressTransactionsResponse, - GetV1WalletsByWalletAddressTransactionsError, + GetV1WalletsByWalletAddressTransactionsResponses, + GetV1WalletsByWalletAddressTransactionsErrors, ThrowOnError >({ security: [ diff --git a/packages/insight/src/client/types.gen.ts b/packages/insight/src/client/types.gen.ts index f69d267481d..95ab16c808c 100644 --- a/packages/insight/src/client/types.gen.ts +++ b/packages/insight/src/client/types.gen.ts @@ -501,6 +501,7 @@ export type GetV1EventsData = { */ filter_topic_0?: string; /** + * address (hex or ENS) * Filter by address */ filter_address?: string; @@ -536,10 +537,10 @@ export type GetV1EventsResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; transaction_hash: string; transaction_index: number; log_index: number; @@ -576,6 +577,9 @@ export type GetV1EventsResponse = export type GetV1EventsByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; }; query?: { @@ -747,10 +751,10 @@ export type GetV1EventsByContractAddressResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; transaction_hash: string; transaction_index: number; log_index: number; @@ -787,6 +791,9 @@ export type GetV1EventsByContractAddressResponse = export type GetV1EventsByContractAddressBySignatureData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; signature: string; }; @@ -955,10 +962,10 @@ export type GetV1EventsByContractAddressBySignatureResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; transaction_hash: string; transaction_index: number; log_index: number; @@ -1096,6 +1103,7 @@ export type GetV1TransactionsData = { */ filter_hash?: string; /** + * address (hex or ENS) * Filter by from address */ filter_from_address?: string; @@ -1164,6 +1172,7 @@ export type GetV1TransactionsData = { */ filter_function_selector?: string; /** + * address (hex or ENS) * Filter by to address */ filter_to_address?: string; @@ -1200,33 +1209,34 @@ export type GetV1TransactionsResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; hash: string; nonce: number; transaction_index: number; from_address: string; to_address: string; - value: number; - gas_price: number; + value: string; + gas_price: string; gas: number; function_selector: string; data: string; - max_fee_per_gas: number; - max_priority_fee_per_gas: number; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; transaction_type: number; - r: number; - s: number; - v: number; + r: string; + s: string; + v: string; access_list_json?: string; + authorization_list_json?: string; contract_address?: string; gas_used?: number; cumulative_gas_used?: number; - effective_gas_price?: number; + effective_gas_price?: string; blob_gas_used?: number; - blob_gas_price?: number; + blob_gas_price?: string; logs_bloom?: string; status?: number; decoded?: { @@ -1236,16 +1246,6 @@ export type GetV1TransactionsResponses = { [key: string]: unknown; }; }; - /** - * @deprecated - */ - decodedData?: { - name: string; - signature: string; - inputs?: { - [key: string]: unknown; - }; - }; }>; aggregations?: unknown; meta: { @@ -1266,6 +1266,9 @@ export type GetV1TransactionsResponse = export type GetV1TransactionsByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; }; query?: { @@ -1369,6 +1372,7 @@ export type GetV1TransactionsByContractAddressData = { */ filter_hash?: string; /** + * address (hex or ENS) * Filter by from address */ filter_from_address?: string; @@ -1469,33 +1473,34 @@ export type GetV1TransactionsByContractAddressResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; hash: string; nonce: number; transaction_index: number; from_address: string; to_address: string; - value: number; - gas_price: number; + value: string; + gas_price: string; gas: number; function_selector: string; data: string; - max_fee_per_gas: number; - max_priority_fee_per_gas: number; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; transaction_type: number; - r: number; - s: number; - v: number; + r: string; + s: string; + v: string; access_list_json?: string; + authorization_list_json?: string; contract_address?: string; gas_used?: number; cumulative_gas_used?: number; - effective_gas_price?: number; + effective_gas_price?: string; blob_gas_used?: number; - blob_gas_price?: number; + blob_gas_price?: string; logs_bloom?: string; status?: number; }>; @@ -1518,6 +1523,9 @@ export type GetV1TransactionsByContractAddressResponse = export type GetV1TransactionsByContractAddressBySignatureData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; signature: string; }; @@ -1622,6 +1630,7 @@ export type GetV1TransactionsByContractAddressBySignatureData = { */ filter_hash?: string; /** + * address (hex or ENS) * Filter by from address */ filter_from_address?: string; @@ -1718,33 +1727,34 @@ export type GetV1TransactionsByContractAddressBySignatureResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; hash: string; nonce: number; transaction_index: number; from_address: string; to_address: string; - value: number; - gas_price: number; + value: string; + gas_price: string; gas: number; function_selector: string; data: string; - max_fee_per_gas: number; - max_priority_fee_per_gas: number; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; transaction_type: number; - r: number; - s: number; - v: number; + r: string; + s: string; + v: string; access_list_json?: string; + authorization_list_json?: string; contract_address?: string; gas_used?: number; cumulative_gas_used?: number; - effective_gas_price?: number; + effective_gas_price?: string; blob_gas_used?: number; - blob_gas_price?: number; + blob_gas_price?: string; logs_bloom?: string; status?: number; decoded?: { @@ -1754,16 +1764,6 @@ export type GetV1TransactionsByContractAddressBySignatureResponses = { [key: string]: unknown; }; }; - /** - * @deprecated - */ - decodedData?: { - name: string; - signature: string; - inputs?: { - [key: string]: unknown; - }; - }; }>; aggregations?: unknown; meta: { @@ -1801,6 +1801,9 @@ export type GetV1TokensOwnersData = { */ limit?: number; page?: number | null; + /** + * address (hex or ENS) + */ contract_address: string; }; url: "/v1/tokens/owners"; @@ -1835,7 +1838,13 @@ export type GetV1TokensOwnersResponses = { 200: { data: Array<{ chain_id: string; + /** + * address (hex or ENS) + */ token_address: string; + /** + * address (hex or ENS) + */ owner_address: string; balance: string; }>; @@ -1871,18 +1880,10 @@ export type GetV1TokensTransfersTransactionByTransactionHashData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; /** * The types of tokens to include in the response. Can be an empty array to include all types */ @@ -1917,6 +1918,66 @@ export type GetV1TokensTransfersTransactionByTransactionHashErrors = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -1947,6 +2008,66 @@ export type GetV1TokensTransfersTransactionByTransactionHashResponses = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -1958,6 +2079,9 @@ export type GetV1TokensTransfersTransactionByTransactionHashResponse = export type GetV1TokensTransfersByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -1981,18 +2105,10 @@ export type GetV1TokensTransfersByContractAddressData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; }; url: "/v1/tokens/transfers/{contract_address}"; }; @@ -2023,6 +2139,66 @@ export type GetV1TokensTransfersByContractAddressErrors = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -2053,6 +2229,66 @@ export type GetV1TokensTransfersByContractAddressResponses = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -2085,18 +2321,10 @@ export type GetV1TokensTransfersData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; /** * Filter by block number greater than or equal to */ @@ -2105,11 +2333,34 @@ export type GetV1TokensTransfersData = { * Filter by block number less than or equal to */ block_number_to?: number | string; + /** + * Filter by block timestamp greater than or equal to + */ + block_timestamp_from?: number; + /** + * Filter by block timestamp less than or equal to + */ + block_timestamp_to?: number; + /** + * address (hex or ENS) + */ + owner_address?: string; + /** + * Filter by contract address. Can be an array of addresses or a single address. If not provided, all contracts will be included + */ + contract_address?: Array; + /** + * Sort order (asc or desc) + */ + sort_order?: "asc" | "desc"; + /** + * Only include transfers of a certain type + */ + transfer_type?: "mint" | "transfer" | "burn"; /** * The types of tokens to include in the response. Can be an empty array to include all types */ token_types?: Array<"erc1155" | "erc721" | "erc20">; - owner_address?: string; }; url: "/v1/tokens/transfers"; }; @@ -2140,6 +2391,66 @@ export type GetV1TokensTransfersErrors = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -2170,6 +2481,66 @@ export type GetV1TokensTransfersResponses = { name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; + }; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; }; }>; }; @@ -2181,6 +2552,9 @@ export type GetV1TokensTransfersResponse = export type GetV1TokensErc20ByOwnerAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ ownerAddress: string; }; query?: { @@ -2237,6 +2611,9 @@ export type GetV1TokensErc20ByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; balance: string; name?: string; @@ -2281,6 +2658,9 @@ export type GetV1TokensData = { * Whether to include spam tokens */ include_spam?: "true" | "false"; + /** + * address (hex or ENS) + */ owner_address: string; /** * Whether to include native tokens @@ -2311,11 +2691,44 @@ export type GetV1TokensResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; balance: string; name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; }>; }; }; @@ -2326,6 +2739,9 @@ export type GetV1TokensResponse = export type GetV1TokensErc721ByOwnerAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ ownerAddress: string; }; query?: { @@ -2378,6 +2794,9 @@ export type GetV1TokensErc721ByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; token_id: string; balance: string; @@ -2420,6 +2839,9 @@ export type GetV1TokensErc721ByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -2435,6 +2857,9 @@ export type GetV1TokensErc721ByOwnerAddressResponse = export type GetV1TokensErc1155ByOwnerAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ ownerAddress: string; }; query?: { @@ -2487,6 +2912,9 @@ export type GetV1TokensErc1155ByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; token_id: string; balance: string; @@ -2529,6 +2957,9 @@ export type GetV1TokensErc1155ByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -2581,6 +3012,9 @@ export type GetV1TokensPriceSupportedResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; symbol?: string; }>; @@ -2650,6 +3084,9 @@ export type GetV1TokensPriceResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; symbol?: string; /** @@ -2746,10 +3183,43 @@ export type GetV1TokensLookupResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; name?: string; symbol?: string; decimals?: number; + price_data?: { + /** + * The price of the token in USD + */ + price_usd?: number; + /** + * The volume of the token in USD + */ + volume_24h_usd?: number; + /** + * The market cap of the token in USD + */ + market_cap_usd?: number; + /** + * The circulating supply of the token + */ + circulating_supply?: number; + /** + * The total supply of the token + */ + total_supply?: number; + /** + * The percentage change of the token in the last 24 hours + */ + percent_change_24h?: number; + /** + * The timestamp of the latest price update + */ + price_timestamp?: string; + }; }>; }; }; @@ -2761,6 +3231,7 @@ export type GetV1ResolveByInputData = { body?: never; path: { /** + * hash * Can be a block number, transaction or block hash, address, event signature or function selector */ input: string; @@ -2830,41 +3301,42 @@ export type GetV1ResolveByInputResponses = { base_fee_per_gas: number; }>; transactions?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; hash: string; nonce: number; transaction_index: number; from_address: string; to_address: string; - value: number; - gas_price: number; + value: string; + gas_price: string; gas: number; function_selector: string; data: string; - max_fee_per_gas: number; - max_priority_fee_per_gas: number; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; transaction_type: number; - r: number; - s: number; - v: number; + r: string; + s: string; + v: string; access_list_json?: string; + authorization_list_json?: string; contract_address?: string; gas_used?: number; cumulative_gas_used?: number; - effective_gas_price?: number; + effective_gas_price?: string; blob_gas_used?: number; - blob_gas_price?: number; + blob_gas_price?: string; logs_bloom?: string; status?: number; }>; events?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; transaction_hash: string; transaction_index: number; log_index: number; @@ -2872,6 +3344,9 @@ export type GetV1ResolveByInputResponses = { data: string; topics: Array; }>; + /** + * address (hex or ENS) + */ address?: string; type: | "block" @@ -3047,6 +3522,9 @@ export type GetV1BlocksResponse = export type GetV1ContractsAbiByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; }; query?: { @@ -3102,6 +3580,9 @@ export type GetV1ContractsAbiByContractAddressResponse = export type GetV1ContractsMetadataByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contractAddress: string; }; query?: { @@ -3159,6 +3640,9 @@ export type PostV1DecodeByContractAddressData = { }>; }; path: { + /** + * address (hex or ENS) + */ contractAddress: string; }; query?: { @@ -3226,6 +3710,9 @@ export type PostV1DecodeByContractAddressResponse = export type GetV1NftsBalanceByOwnerAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ ownerAddress: string; }; query?: { @@ -3282,6 +3769,9 @@ export type GetV1NftsBalanceByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ token_address: string; token_id: string; balance: string; @@ -3324,6 +3814,9 @@ export type GetV1NftsBalanceByOwnerAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -3339,6 +3832,9 @@ export type GetV1NftsBalanceByOwnerAddressResponse = export type GetV1NftsCollectionsByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -3432,6 +3928,9 @@ export type GetV1NftsData = { * Whether to resolve metadata IPFS or Arweave links */ resolve_metadata_links?: "true" | "false"; + /** + * address (hex or ENS) + */ owner_address: string; }; url: "/v1/nfts"; @@ -3496,6 +3995,9 @@ export type GetV1NftsResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -3515,6 +4017,9 @@ export type GetV1NftsResponse = GetV1NftsResponses[keyof GetV1NftsResponses]; export type GetV1NftsOwnersByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -3583,6 +4088,9 @@ export type GetV1NftsOwnersByContractAddressResponse = export type GetV1NftsOwnersByContractAddressByTokenIdData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; token_id: string; }; @@ -3673,18 +4181,10 @@ export type GetV1NftsTransfersData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; /** * Filter by block number greater than or equal to */ @@ -3694,10 +4194,37 @@ export type GetV1NftsTransfersData = { */ block_number_to?: number | string; /** - * The types of tokens to include in the response. Can be an empty array to include all types + * Filter by block timestamp greater than or equal to + */ + block_timestamp_from?: number; + /** + * Filter by block timestamp less than or equal to + */ + block_timestamp_to?: number; + /** + * address (hex or ENS) */ - token_types?: Array<"erc1155" | "erc721" | "erc20">; owner_address?: string; + /** + * Filter by contract address. Can be an array of addresses or a single address. If not provided, all contracts will be included + */ + contract_address?: Array; + /** + * Sort order (asc or desc) + */ + sort_order?: "asc" | "desc"; + /** + * Only include transfers of a certain type + */ + transfer_type?: "mint" | "transfer" | "burn" | "sale"; + /** + * Whether to include sale details for NFT transfers + */ + sales?: "true" | "false"; + /** + * Whether to resolve metadata IPFS or Arweave links + */ + resolve_metadata_links?: "true" | "false"; }; url: "/v1/nfts/transfers"; }; @@ -3777,6 +4304,9 @@ export type GetV1NftsTransfersResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -3786,19 +4316,37 @@ export type GetV1NftsTransfersResponses = { nft_sale?: { transaction_hash: string; items_sold: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; payment: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; marketplace_address: string; @@ -3837,18 +4385,10 @@ export type GetV1NftsTransfersTransactionByTransactionHashData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; /** * The types of tokens to include in the response. Can be an empty array to include all types */ @@ -3932,6 +4472,9 @@ export type GetV1NftsTransfersTransactionByTransactionHashResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -3941,19 +4484,37 @@ export type GetV1NftsTransfersTransactionByTransactionHashResponses = { nft_sale?: { transaction_hash: string; items_sold: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; payment: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; marketplace_address: string; @@ -3969,6 +4530,9 @@ export type GetV1NftsTransfersTransactionByTransactionHashResponse = export type GetV1NftsTransfersByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -3992,18 +4556,10 @@ export type GetV1NftsTransfersByContractAddressData = { * Whether to include metadata for the tokens */ metadata?: "true" | "false"; - /** - * Whether to include sale details for NFT transfers - */ - sales?: "true" | "false"; /** * Whether to include owner addresses in the NFT metadata (only if metadata is requested) */ include_owners?: "true" | "false"; - /** - * Whether to resolve metadata IPFS or Arweave links - */ - resolve_metadata_links?: "true" | "false"; }; url: "/v1/nfts/transfers/{contract_address}"; }; @@ -4083,6 +4639,9 @@ export type GetV1NftsTransfersByContractAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -4092,19 +4651,37 @@ export type GetV1NftsTransfersByContractAddressResponses = { nft_sale?: { transaction_hash: string; items_sold: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; payment: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; marketplace_address: string; @@ -4120,6 +4697,9 @@ export type GetV1NftsTransfersByContractAddressResponse = export type GetV1NftsByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -4212,6 +4792,9 @@ export type GetV1NftsByContractAddressResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -4232,6 +4815,9 @@ export type GetV1NftsByContractAddressResponse = export type GetV1NftsTransfersByContractAddressByTokenIdData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; token_id: string; }; @@ -4347,6 +4933,9 @@ export type GetV1NftsTransfersByContractAddressByTokenIdResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -4356,19 +4945,37 @@ export type GetV1NftsTransfersByContractAddressByTokenIdResponses = { nft_sale?: { transaction_hash: string; items_sold: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; payment: Array<{ + /** + * address (hex or ENS) + */ token_address: string; token_id: string; amount: string; token_type: string; + /** + * address (hex or ENS) + */ from_address?: string; + /** + * address (hex or ENS) + */ to_address?: string; }>; marketplace_address: string; @@ -4384,6 +4991,9 @@ export type GetV1NftsTransfersByContractAddressByTokenIdResponse = export type GetV1NftsByContractAddressByTokenIdData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; token_id: string; }; @@ -4472,6 +5082,9 @@ export type GetV1NftsByContractAddressByTokenIdResponses = { * The chain ID of a relevant entry */ chain_id: number; + /** + * address (hex or ENS) + */ address: string; name?: string; symbol?: string; @@ -4492,6 +5105,9 @@ export type GetV1NftsByContractAddressByTokenIdResponse = export type GetV1NftsMetadataRefreshByContractAddressData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; }; query?: { @@ -4546,6 +5162,9 @@ export type GetV1NftsMetadataRefreshByContractAddressResponse = export type GetV1NftsMetadataRefreshByContractAddressByTokenIdData = { body?: never; path: { + /** + * address (hex or ENS) + */ contract_address: string; token_id: string; }; @@ -4601,6 +5220,9 @@ export type GetV1NftsMetadataRefreshByContractAddressByTokenIdResponse = export type GetV1WalletsByWalletAddressTransactionsData = { body?: never; path: { + /** + * address (hex or ENS) + */ wallet_address: string; }; query?: { @@ -4800,33 +5422,34 @@ export type GetV1WalletsByWalletAddressTransactionsResponses = { */ 200: { data?: Array<{ - chain_id: number; - block_number: string; + chain_id: string; + block_number: number; block_hash: string; - block_timestamp: string; + block_timestamp: number; hash: string; nonce: number; transaction_index: number; from_address: string; to_address: string; - value: number; - gas_price: number; + value: string; + gas_price: string; gas: number; function_selector: string; data: string; - max_fee_per_gas: number; - max_priority_fee_per_gas: number; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; transaction_type: number; - r: number; - s: number; - v: number; + r: string; + s: string; + v: string; access_list_json?: string; + authorization_list_json?: string; contract_address?: string; gas_used?: number; cumulative_gas_used?: number; - effective_gas_price?: number; + effective_gas_price?: string; blob_gas_used?: number; - blob_gas_price?: number; + blob_gas_price?: string; logs_bloom?: string; status?: number; decoded?: { @@ -4836,16 +5459,6 @@ export type GetV1WalletsByWalletAddressTransactionsResponses = { [key: string]: unknown; }; }; - /** - * @deprecated - */ - decodedData?: { - name: string; - signature: string; - inputs?: { - [key: string]: unknown; - }; - }; }>; aggregations?: unknown; meta: { diff --git a/packages/insight/src/configure.ts b/packages/insight/src/configure.ts index a41253ccfe9..d213fe79cc0 100644 --- a/packages/insight/src/configure.ts +++ b/packages/insight/src/configure.ts @@ -1,4 +1,4 @@ -import type { Config } from "@hey-api/client-fetch"; +import type { Config } from "./client/client/index.js"; import { client } from "./client/client.gen.js"; export type InsightClientOptions = { diff --git a/packages/insight/tsconfig.base.json b/packages/insight/tsconfig.base.json index 25c55988d49..ec2b1a33e1e 100644 --- a/packages/insight/tsconfig.base.json +++ b/packages/insight/tsconfig.base.json @@ -20,7 +20,8 @@ "jsx": "react-jsx", "lib": [ "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. - "DOM" // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM", // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM.Iterable" // Adding `DOM.Iterable` for the Headers.entries() method. ], "module": "NodeNext", diff --git a/packages/nebula/openapi-ts.config.ts b/packages/nebula/openapi-ts.config.ts index 1a7cfdd4b94..c9d254e35cf 100644 --- a/packages/nebula/openapi-ts.config.ts +++ b/packages/nebula/openapi-ts.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ - input: "https://nebula-api.thirdweb-dev.com/openapi.json", - output: { format: "biome", lint: "biome", path: "src/client" }, - plugins: ["@hey-api/client-fetch"], + input: "https://nebula-api.thirdweb-dev.com/openapi.json", + output: { format: "biome", lint: "biome", path: "src/client" }, + plugins: ["@hey-api/client-fetch"], }); diff --git a/packages/nebula/package.json b/packages/nebula/package.json index 1b7cdeee0d9..f891ccf6e1f 100644 --- a/packages/nebula/package.json +++ b/packages/nebula/package.json @@ -28,12 +28,11 @@ "src/*" ], "dependencies": { - "@hey-api/client-fetch": "0.10.0", "thirdweb": "workspace:*" }, "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.72.1", + "@hey-api/openapi-ts": "0.76.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, diff --git a/packages/nebula/src/client/client.gen.ts b/packages/nebula/src/client/client.gen.ts index 942b097f334..3452237ec12 100644 --- a/packages/nebula/src/client/client.gen.ts +++ b/packages/nebula/src/client/client.gen.ts @@ -5,7 +5,7 @@ import { createClient, createConfig, type ClientOptions as DefaultClientOptions, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import type { ClientOptions } from "./types.gen.js"; /** diff --git a/packages/nebula/src/client/client/client.ts b/packages/nebula/src/client/client/client.ts new file mode 100644 index 00000000000..8cb5e5bde84 --- /dev/null +++ b/packages/nebula/src/client/client/client.ts @@ -0,0 +1,189 @@ +import type { Client, Config, RequestOptions } from "./types.js"; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from "./utils.js"; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors< + Request, + Response, + unknown, + RequestOptions + >(); + + const request: Client["request"] = async (options) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.body && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.body === "") { + opts.headers.delete("Content-Type"); + } + + const url = buildUrl(opts); + const requestInit: ReqInit = { + redirect: "follow", + ...opts, + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request._fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response = await _fetch(request); + + for (const fn of interceptors.response._fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + if ( + response.status === 204 || + response.headers.get("Content-Length") === "0" + ) { + return opts.responseStyle === "data" + ? {} + : { + data: {}, + ...result, + }; + } + + const parseAs = + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json"; + + let data: any; + switch (parseAs) { + case "arrayBuffer": + case "blob": + case "formData": + case "json": + case "text": + data = await response[parseAs](); + break; + case "stream": + return opts.responseStyle === "data" + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === "json") { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === "data" + ? data + : { + data, + ...result, + }; + } + + let error = await response.text(); + + try { + error = JSON.parse(error); + } catch { + // noop + } + + let finalError = error; + + for (const fn of interceptors.error._fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === "data" + ? undefined + : { + error: finalError, + ...result, + }; + }; + + return { + buildUrl, + connect: (options) => request({ ...options, method: "CONNECT" }), + delete: (options) => request({ ...options, method: "DELETE" }), + get: (options) => request({ ...options, method: "GET" }), + getConfig, + head: (options) => request({ ...options, method: "HEAD" }), + interceptors, + options: (options) => request({ ...options, method: "OPTIONS" }), + patch: (options) => request({ ...options, method: "PATCH" }), + post: (options) => request({ ...options, method: "POST" }), + put: (options) => request({ ...options, method: "PUT" }), + request, + setConfig, + trace: (options) => request({ ...options, method: "TRACE" }), + }; +}; diff --git a/packages/nebula/src/client/client/index.ts b/packages/nebula/src/client/client/index.ts new file mode 100644 index 00000000000..33d0123ce32 --- /dev/null +++ b/packages/nebula/src/client/client/index.ts @@ -0,0 +1,22 @@ +export type { Auth } from "../core/auth.js"; +export type { QuerySerializerOptions } from "../core/bodySerializer.js"; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from "../core/bodySerializer.js"; +export { buildClientParams } from "../core/params.js"; +export { createClient } from "./client.js"; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + OptionsLegacyParser, + RequestOptions, + RequestResult, + ResponseStyle, + TDataShape, +} from "./types.js"; +export { createConfig, mergeHeaders } from "./utils.js"; diff --git a/packages/nebula/src/client/client/types.ts b/packages/nebula/src/client/client/types.ts new file mode 100644 index 00000000000..6d37980f22f --- /dev/null +++ b/packages/nebula/src/client/client/types.ts @@ -0,0 +1,222 @@ +import type { Auth } from "../core/auth.js"; +import type { + Client as CoreClient, + Config as CoreConfig, +} from "../core/types.js"; +import type { Middleware } from "./utils.js"; + +export type ResponseStyle = "data" | "fields"; + +export interface Config + extends Omit, + CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T["baseUrl"]; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: (request: Request) => ReturnType; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: + | "arrayBuffer" + | "auto" + | "blob" + | "formData" + | "json" + | "stream" + | "text"; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T["throwOnError"]; +} + +export interface RequestOptions< + TResponseStyle extends ResponseStyle = "fields", + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }> { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends "data" + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record + ? TData[keyof TData] + : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends "data" + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined + : ( + | { + data: TData extends Record + ? TData[keyof TData] + : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method">, +) => RequestResult; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method"> & + Pick>, "method">, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: Pick & Options, +) => string; + +export type Client = CoreClient & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = OmitKeys< + RequestOptions, + "body" | "path" | "query" | "url" +> & + Omit; + +export type OptionsLegacyParser< + TData = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = TData extends { body?: any } + ? TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "body" | "headers" | "url" + > & + TData + : OmitKeys, "body" | "url"> & + TData & + Pick, "headers"> + : TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "headers" | "url" + > & + TData & + Pick, "body"> + : OmitKeys, "url"> & TData; diff --git a/packages/nebula/src/client/client/utils.ts b/packages/nebula/src/client/client/utils.ts new file mode 100644 index 00000000000..103b5315f96 --- /dev/null +++ b/packages/nebula/src/client/client/utils.ts @@ -0,0 +1,417 @@ +import { getAuthToken } from "../core/auth.js"; +import type { + QuerySerializer, + QuerySerializerOptions, +} from "../core/bodySerializer.js"; +import { jsonBodySerializer } from "../core/bodySerializer.js"; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer.js"; +import type { Client, ClientOptions, Config, RequestOptions } from "./types.js"; + +interface PathSerializer { + path: Record; + url: string; +} + +const PATH_PARAM_RE = /\{[^{}]+\}/g; + +type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +type MatrixStyle = "label" | "matrix" | "simple"; +type ArraySeparatorStyle = ArrayStyle | MatrixStyle; + +const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = "simple"; + + if (name.endsWith("*")) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith(".")) { + name = name.substring(1); + style = "label"; + } else if (name.startsWith(";")) { + name = name.substring(1); + style = "matrix"; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); + continue; + } + + if (typeof value === "object") { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === "matrix") { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === "label" ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const createQuerySerializer = ({ + allowReserved, + array, + object, +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === "object") { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved, + explode: true, + name, + style: "form", + value, + ...array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === "object") { + const serializedObject = serializeObjectParam({ + allowReserved, + explode: true, + name, + style: "deepObject", + value: value as Record, + ...object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join("&"); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = ( + contentType: string | null, +): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return "stream"; + } + + const cleanContent = contentType.split(";")[0]?.trim(); + + if (!cleanContent) { + return; + } + + if ( + cleanContent.startsWith("application/json") || + cleanContent.endsWith("+json") + ) { + return "json"; + } + + if (cleanContent === "multipart/form-data") { + return "formData"; + } + + if ( + ["application/", "audio/", "image/", "video/"].some((type) => + cleanContent.startsWith(type), + ) + ) { + return "blob"; + } + + if (cleanContent.startsWith("text/")) { + return "text"; + } + + return; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, "security"> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? "Authorization"; + + switch (auth.in) { + case "query": + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case "cookie": + options.headers.append("Cookie", `${name}=${token}`); + break; + case "header": + default: + options.headers.set(name, token); + break; + } + + return; + } +}; + +export const buildUrl: Client["buildUrl"] = (options) => { + const url = getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === "function" + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = (baseUrl ?? "") + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ""; + if (search.startsWith("?")) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith("/")) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +export const mergeHeaders = ( + ...headers: Array["headers"] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header || typeof header !== "object") { + continue; + } + + const iterator = + header instanceof Headers ? header.entries() : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === "object" ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + _fns: (Interceptor | null)[]; + + constructor() { + this._fns = []; + } + + clear() { + this._fns = []; + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === "number") { + return this._fns[id] ? id : -1; + } else { + return this._fns.indexOf(id); + } + } + exists(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + return !!this._fns[index]; + } + + eject(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = null; + } + } + + update(id: number | Interceptor, fn: Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = fn; + return id; + } else { + return false; + } + } + + use(fn: Interceptor) { + this._fns = [...this._fns, fn]; + return this._fns.length - 1; + } +} + +// `createInterceptors()` response, meant for external use as it does not +// expose internals +export interface Middleware { + error: Pick< + Interceptors>, + "eject" | "use" + >; + request: Pick>, "eject" | "use">; + response: Pick< + Interceptors>, + "eject" | "use" + >; +} + +// do not add `Middleware` as return type so we can use _fns internally +export const createInterceptors = () => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: "form", + }, + object: { + explode: true, + style: "deepObject", + }, +}); + +const defaultHeaders = { + "Content-Type": "application/json", +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: "auto", + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/packages/nebula/src/client/core/auth.ts b/packages/nebula/src/client/core/auth.ts new file mode 100644 index 00000000000..70e9d5dba5e --- /dev/null +++ b/packages/nebula/src/client/core/auth.ts @@ -0,0 +1,40 @@ +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: "header" | "query" | "cookie"; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: "basic" | "bearer"; + type: "apiKey" | "http"; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = + typeof callback === "function" ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === "bearer") { + return `Bearer ${token}`; + } + + if (auth.scheme === "basic") { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/packages/nebula/src/client/core/bodySerializer.ts b/packages/nebula/src/client/core/bodySerializer.ts new file mode 100644 index 00000000000..e68daa47a7b --- /dev/null +++ b/packages/nebula/src/client/core/bodySerializer.ts @@ -0,0 +1,84 @@ +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer.js"; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +export interface QuerySerializerOptions { + allowReserved?: boolean; + array?: SerializerOptions; + object?: SerializerOptions; +} + +const serializeFormDataPair = (data: FormData, key: string, value: unknown) => { + if (typeof value === "string" || value instanceof Blob) { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +) => { + if (typeof value === "string") { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new FormData(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: T) => + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value, + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new URLSearchParams(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/packages/nebula/src/client/core/params.ts b/packages/nebula/src/client/core/params.ts new file mode 100644 index 00000000000..0771542b148 --- /dev/null +++ b/packages/nebula/src/client/core/params.ts @@ -0,0 +1,141 @@ +type Slot = "body" | "headers" | "path" | "query"; + +export type Field = + | { + in: Exclude; + key: string; + map?: string; + } + | { + in: Extract; + key?: string; + map?: string; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: "body", + $headers_: "headers", + $path_: "path", + $query_: "query", +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + { + in: Slot; + map?: string; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ("in" in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === "object" && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ("in" in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + (params[field.in] as Record)[name] = arg; + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else { + for (const [slot, allowed] of Object.entries( + config.allowExtra ?? {}, + )) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/packages/nebula/src/client/core/pathSerializer.ts b/packages/nebula/src/client/core/pathSerializer.ts new file mode 100644 index 00000000000..4052ad12795 --- /dev/null +++ b/packages/nebula/src/client/core/pathSerializer.ts @@ -0,0 +1,179 @@ +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = "label" | "matrix" | "simple"; +export type ObjectStyle = "form" | "deepObject"; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "form": + return ","; + case "pipeDelimited": + return "|"; + case "spaceDelimited": + return "%20"; + default: + return ","; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + case "simple": + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === "label" || style === "simple") { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ""; + } + + if (typeof value === "object") { + throw new Error( + "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== "deepObject" && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; + }); + const joinedValues = values.join(","); + switch (style) { + case "form": + return `${name}=${joinedValues}`; + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === "deepObject" ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; diff --git a/packages/nebula/src/client/core/types.ts b/packages/nebula/src/client/core/types.ts new file mode 100644 index 00000000000..41322e707cb --- /dev/null +++ b/packages/nebula/src/client/core/types.ts @@ -0,0 +1,98 @@ +import type { Auth, AuthToken } from "./auth.js"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.js"; + +export interface Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, +> { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + connect: MethodFn; + delete: MethodFn; + get: MethodFn; + getConfig: () => Config; + head: MethodFn; + options: MethodFn; + patch: MethodFn; + post: MethodFn; + put: MethodFn; + request: RequestFn; + setConfig: (config: Config) => Config; + trace: MethodFn; +} + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit["headers"] + | Record< + string, + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: + | "CONNECT" + | "DELETE" + | "GET" + | "HEAD" + | "OPTIONS" + | "PATCH" + | "POST" + | "PUT" + | "TRACE"; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} diff --git a/packages/nebula/src/client/sdk.gen.ts b/packages/nebula/src/client/sdk.gen.ts index a00f41eb487..1916fd20c7d 100644 --- a/packages/nebula/src/client/sdk.gen.ts +++ b/packages/nebula/src/client/sdk.gen.ts @@ -4,7 +4,7 @@ import type { Client, Options as ClientOptions, TDataShape, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import { client as _heyApiClient } from "./client.gen.js"; import type { AuthDelegateLoginData, diff --git a/packages/nebula/src/client/types.gen.ts b/packages/nebula/src/client/types.gen.ts index d0a4485bf1b..714d08773cf 100644 --- a/packages/nebula/src/client/types.gen.ts +++ b/packages/nebula/src/client/types.gen.ts @@ -544,6 +544,10 @@ export type AgentResponse = { * Is Public */ is_public: boolean; + /** + * Summary + */ + summary?: string | null; context: AgentTaskContext; /** * Prompts @@ -750,6 +754,58 @@ export type AgentToolDataAgent = { agent_id: string; }; +/** + * AgentToolDataApi + */ +export type AgentToolDataApi = { + /** + * Type + */ + type?: "api"; + /** + * Url + */ + url: string; + /** + * Method + */ + method?: string; + /** + * Headers + */ + headers?: { + [key: string]: string; + } | null; + /** + * Params + */ + params?: { + [key: string]: unknown; + } | null; + /** + * Task Param + */ + task_param: string; + /** + * Description + */ + description: string; +}; + +/** + * AgentToolDataBuiltin + */ +export type AgentToolDataBuiltin = { + /** + * Type + */ + type?: "builtin"; + /** + * Agent Name + */ + agent_name: string; +}; + /** * AgentToolDataMcp */ @@ -762,9 +818,9 @@ export type AgentToolDataMcp = { }; /** - * AgentToolDescription + * AgentToolReference */ -export type AgentToolDescription = { +export type AgentToolReference = { /** * Agent Id */ @@ -777,6 +833,10 @@ export type AgentToolDescription = { * Description */ description: string; + /** + * Summary + */ + summary?: string | null; }; /** @@ -802,9 +862,15 @@ export type AgentToolResponse = { | ({ type: "agent"; } & AgentToolDataAgent) + | ({ + type: "builtin"; + } & AgentToolDataBuiltin) | ({ type: "mcp"; - } & AgentToolDataMcp); + } & AgentToolDataMcp) + | ({ + type: "api"; + } & AgentToolDataApi); /** * Created At */ @@ -1100,6 +1166,44 @@ export type AgentWalletResponse = { updated_at: string; }; +/** + * ApiToolConfig + */ +export type ApiToolConfig = { + /** + * Url + */ + url: string; + /** + * Method + */ + method: string; + /** + * Headers + */ + headers?: { + [key: string]: string; + } | null; + /** + * Params + */ + params?: { + [key: string]: string; + } | null; + /** + * Task Param + */ + task_param?: string | null; + /** + * Name + */ + name?: string | null; + /** + * Description + */ + description: string; +}; + /** * BlockchainEntity * Base class for all blockchain entities tracked in memory. @@ -1127,6 +1231,16 @@ export type BlockchainEntity = { last_mentioned_at?: string; }; +/** + * BuiltinAgentReference + */ +export type BuiltinAgentReference = { + /** + * Agent Name + */ + agent_name: string; +}; + /** * ChatContentImage */ @@ -1188,19 +1302,17 @@ export type ChatMessage = { /** * Content */ - content: - | string - | Array< - | ({ - type: "image"; - } & ChatContentImage) - | ({ - type: "text"; - } & ChatContentText) - | ({ - type: "transaction"; - } & ChatContentTransaction) - >; + content: Array< + | ({ + type: "image"; + } & ChatContentImage) + | ({ + type: "text"; + } & ChatContentText) + | ({ + type: "transaction"; + } & ChatContentTransaction) + >; }; /** @@ -1431,11 +1543,19 @@ export type CompletionContextInput = { /** * Mcp Tools */ - mcp_tools?: Array | null; + mcp_tools?: Array | null; /** * Agent Tools */ - agent_tools?: Array | null; + agent_tools?: Array | null; + /** + * Builtin Agents + */ + builtin_agents?: Array | null; + /** + * Api Tools + */ + api_tools?: Array | null; /** * Deployed Contracts */ @@ -1477,6 +1597,32 @@ export type CompletionContextOutput = { * Prompts */ prompts?: Array; + /** + * Mcp Tools + */ + mcp_tools?: Array | null; + /** + * Agent Tools + */ + agent_tools?: Array | null; + /** + * Builtin Agents + */ + builtin_agents?: Array | null; + /** + * Api Tools + */ + api_tools?: Array | null; + /** + * Deployed Contracts + */ + deployed_contracts?: Array; + /** + * Entities + */ + entities?: { + [key: string]: BlockchainEntity; + }; }; /** @@ -1906,9 +2052,15 @@ export type CreateAgentToolParams = { | ({ type: "agent"; } & AgentToolDataAgent) + | ({ + type: "builtin"; + } & AgentToolDataBuiltin) | ({ type: "mcp"; - } & AgentToolDataMcp); + } & AgentToolDataMcp) + | ({ + type: "api"; + } & AgentToolDataApi); /** * Description */ @@ -2147,12 +2299,16 @@ export type McpConfig = { headers?: { [key: string]: unknown; } | null; + /** + * Transport + */ + transport?: string; }; /** - * McpTool + * McpToolConfig */ -export type McpTool = { +export type McpToolConfig = { /** * Url */ @@ -2163,8 +2319,25 @@ export type McpTool = { headers?: { [key: string]: string; } | null; + /** + * Transport + */ + transport?: string; + /** + * Media Support + */ + media_support?: Array | null; + /** + * Auto Upload Media + */ + auto_upload_media?: boolean; }; +/** + * MediaOutputType + */ +export type MediaOutputType = "text" | "image" | "audio" | "json" | "binary"; + /** * Model */ @@ -2271,6 +2444,10 @@ export type RegistryAgentListResponse = { * Description */ description: string; + /** + * Summary + */ + summary?: string | null; /** * Created At */ @@ -2598,6 +2775,14 @@ export type UpdateAgentHandlerParams = { * Prompts */ prompts?: Array | null; + /** + * Triggers + */ + triggers?: Array | null; + /** + * Tools + */ + tools?: Array | null; }; /** @@ -2616,9 +2801,15 @@ export type UpdateAgentToolParams = { | ({ type: "agent"; } & AgentToolDataAgent) + | ({ + type: "builtin"; + } & AgentToolDataBuiltin) | ({ type: "mcp"; } & AgentToolDataMcp) + | ({ + type: "api"; + } & AgentToolDataApi) ) | null; /** @@ -4266,5 +4457,5 @@ export type GetRegistryAgentsResponse = GetRegistryAgentsResponses[keyof GetRegistryAgentsResponses]; export type ClientOptions = { - baseUrl: "http://localhost:4242" | (string & {}); + baseUrl: "https://nebula-api.thirdweb-dev.com" | (string & {}); }; diff --git a/packages/nebula/src/configure.ts b/packages/nebula/src/configure.ts index 0c532036462..bb1cd5ea30c 100644 --- a/packages/nebula/src/configure.ts +++ b/packages/nebula/src/configure.ts @@ -1,5 +1,9 @@ -import { type Config, createClient, createConfig } from "@hey-api/client-fetch"; import type { ThirdwebClient } from "thirdweb"; +import { + type Config, + createClient, + createConfig, +} from "./client/client/index.js"; import { client } from "./client/client.gen.js"; export type NebulaClientOptions = { diff --git a/packages/nebula/tsconfig.base.json b/packages/nebula/tsconfig.base.json index 25c55988d49..ec2b1a33e1e 100644 --- a/packages/nebula/tsconfig.base.json +++ b/packages/nebula/tsconfig.base.json @@ -20,7 +20,8 @@ "jsx": "react-jsx", "lib": [ "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. - "DOM" // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM", // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM.Iterable" // Adding `DOM.Iterable` for the Headers.entries() method. ], "module": "NodeNext", diff --git a/packages/thirdweb/.size-limit.json b/packages/thirdweb/.size-limit.json index 2d3d5c9f839..2c26e77d672 100644 --- a/packages/thirdweb/.size-limit.json +++ b/packages/thirdweb/.size-limit.json @@ -1,7 +1,7 @@ [ { "import": "*", - "limit": "65 kB", + "limit": "68 kB", "name": "thirdweb (esm)", "path": "./dist/esm/exports/thirdweb.js" }, diff --git a/packages/thirdweb/src/transaction/transaction-store.ts b/packages/thirdweb/src/transaction/transaction-store.ts index f24349134a5..970efb8db31 100644 --- a/packages/thirdweb/src/transaction/transaction-store.ts +++ b/packages/thirdweb/src/transaction/transaction-store.ts @@ -85,7 +85,10 @@ export async function getPastTransactions(options: { walletAddress, }); return result.map((tx) => ({ - chainId: tx.chain_id, + chainId: + typeof tx.chain_id === "string" + ? Number(tx.chain_id) + : (tx.chain_id as number), receipt: { status: tx.status === 1 ? "success" : "failed", to: tx.to_address, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7aae982a80..5597629df12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,7 +135,7 @@ importers: version: 0.6.19(@hyperjump/browser@1.3.1)(axios@1.9.0)(idb-keyval@6.2.2)(nprogress@0.2.0)(qrcode@1.5.4)(react@19.1.0)(tailwindcss@3.4.17)(typescript@5.8.3) '@sentry/nextjs': specifier: 9.29.0 - version: 9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9) + version: 9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9(esbuild@0.25.5)) '@shazow/whatsabi': specifier: 0.22.2 version: 0.22.2(@noble/hashes@1.8.0)(typescript@5.8.3)(zod@3.25.62) @@ -337,7 +337,7 @@ importers: version: 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) '@storybook/nextjs': specifier: 9.0.8 - version: 9.0.8(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9) + version: 9.0.8(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5)) '@types/color': specifier: 4.2.0 version: 4.2.0 @@ -1053,9 +1053,6 @@ importers: packages/engine: dependencies: - '@hey-api/client-fetch': - specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1064,8 +1061,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.72.1 - version: 0.72.1(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.76.0 + version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -1075,9 +1072,6 @@ importers: packages/insight: dependencies: - '@hey-api/client-fetch': - specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1086,8 +1080,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.72.1 - version: 0.72.1(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.76.0 + version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -1097,9 +1091,6 @@ importers: packages/nebula: dependencies: - '@hey-api/client-fetch': - specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3)) thirdweb: specifier: workspace:* version: link:../thirdweb @@ -1111,8 +1102,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.72.1 - version: 0.72.1(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.76.0 + version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -1337,7 +1328,7 @@ importers: version: 2.2.0(react-native@0.78.1(@babel/core@7.27.4)(@babel/preset-env@7.27.2(@babel/core@7.27.4))(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)) '@size-limit/preset-big-lib': specifier: 11.2.0 - version: 11.2.0(bufferutil@4.0.9)(esbuild@0.25.5)(size-limit@11.2.0)(utf-8-validate@5.0.10) + version: 11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10) '@storybook/addon-docs': specifier: 9.0.8 version: 9.0.8(@types/react@19.1.8)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) @@ -3430,18 +3421,12 @@ packages: peerDependencies: react: '>= 16 || ^19.0.0-rc' - '@hey-api/client-fetch@0.10.0': - resolution: {integrity: sha512-C7vzj4t52qPiHCqjn1l8cRTI2p4pZCd7ViLtJDTHr5ZwI4sWOYC1tmv6bd529qqY6HFFbhGCz4TAZSwKAMJncg==} - deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. - peerDependencies: - '@hey-api/openapi-ts': < 2 - '@hey-api/json-schema-ref-parser@1.0.6': resolution: {integrity: sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w==} engines: {node: '>= 16'} - '@hey-api/openapi-ts@0.72.1': - resolution: {integrity: sha512-PR0w9IJ5Zft9RM9jNDn7NZCX2juDetvs+n6c8wiNw2nC7os8LCowXZDS/yP2rfb9mruQlr9GFGDEWMY1Ie1tpQ==} + '@hey-api/openapi-ts@0.76.0': + resolution: {integrity: sha512-zNSZX6pqOULV0znt8UFTLLNKT5ArBXAXcIQiVMZLOCNmwyQ7c23B0QsjboRYOrb3NzVwYehT/5Nj65axDkxXOw==} engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} hasBin: true peerDependencies: @@ -19356,10 +19341,6 @@ snapshots: dependencies: react: 19.1.0 - '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3))': - dependencies: - '@hey-api/openapi-ts': 0.72.1(magicast@0.3.5)(typescript@5.8.3) - '@hey-api/json-schema-ref-parser@1.0.6': dependencies: '@jsdevtools/ono': 7.1.3 @@ -19367,7 +19348,7 @@ snapshots: js-yaml: 4.1.0 lodash: 4.17.21 - '@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3)': + '@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3)': dependencies: '@hey-api/json-schema-ref-parser': 1.0.6 ansi-colors: 4.1.3 @@ -20801,6 +20782,21 @@ snapshots: dependencies: playwright: 1.53.0 + '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))': + dependencies: + ansi-html: 0.0.9 + core-js-pure: 3.43.0 + error-stack-parser: 2.1.4 + html-entities: 2.6.0 + loader-utils: 2.0.4 + react-refresh: 0.14.2 + schema-utils: 4.3.2 + source-map: 0.7.4 + webpack: 5.99.9(esbuild@0.25.5) + optionalDependencies: + type-fest: 4.41.0 + webpack-hot-middleware: 2.26.1 + '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9)': dependencies: ansi-html: 0.0.9 @@ -23138,7 +23134,7 @@ snapshots: '@sentry/core@9.29.0': {} - '@sentry/nextjs@9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9)': + '@sentry/nextjs@9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9(esbuild@0.25.5))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.34.0 @@ -23149,7 +23145,7 @@ snapshots: '@sentry/opentelemetry': 9.29.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0) '@sentry/react': 9.29.0(react@19.1.0) '@sentry/vercel-edge': 9.29.0 - '@sentry/webpack-plugin': 3.5.0(encoding@0.1.13)(webpack@5.99.9) + '@sentry/webpack-plugin': 3.5.0(encoding@0.1.13)(webpack@5.99.9(esbuild@0.25.5)) chalk: 3.0.0 next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) resolve: 1.22.8 @@ -23226,12 +23222,12 @@ snapshots: '@opentelemetry/api': 1.9.0 '@sentry/core': 9.29.0 - '@sentry/webpack-plugin@3.5.0(encoding@0.1.13)(webpack@5.99.9)': + '@sentry/webpack-plugin@3.5.0(encoding@0.1.13)(webpack@5.99.9(esbuild@0.25.5))': dependencies: '@sentry/bundler-plugin-core': 3.5.0(encoding@0.1.13) unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.99.9 + webpack: 5.99.9(esbuild@0.25.5) transitivePeerDependencies: - encoding - supports-color @@ -23324,11 +23320,11 @@ snapshots: dependencies: size-limit: 11.2.0 - '@size-limit/preset-big-lib@11.2.0(bufferutil@4.0.9)(esbuild@0.25.5)(size-limit@11.2.0)(utf-8-validate@5.0.10)': + '@size-limit/preset-big-lib@11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10)': dependencies: '@size-limit/file': 11.2.0(size-limit@11.2.0) '@size-limit/time': 11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10) - '@size-limit/webpack': 11.2.0(esbuild@0.25.5)(size-limit@11.2.0) + '@size-limit/webpack': 11.2.0(size-limit@11.2.0) size-limit: 11.2.0 transitivePeerDependencies: - '@swc/core' @@ -23350,11 +23346,11 @@ snapshots: - supports-color - utf-8-validate - '@size-limit/webpack@11.2.0(esbuild@0.25.5)(size-limit@11.2.0)': + '@size-limit/webpack@11.2.0(size-limit@11.2.0)': dependencies: nanoid: 5.1.5 size-limit: 11.2.0 - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 transitivePeerDependencies: - '@swc/core' - esbuild @@ -24074,22 +24070,22 @@ snapshots: ts-dedent: 2.2.0 vite: 6.3.5(@types/node@24.0.3)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(tsx@4.20.1)(yaml@2.8.0) - '@storybook/builder-webpack5@9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': + '@storybook/builder-webpack5@9.0.8(esbuild@0.25.5)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 - css-loader: 6.11.0(webpack@5.99.9) + css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5)) es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9) - html-webpack-plugin: 5.6.3(webpack@5.99.9) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) + html-webpack-plugin: 5.6.3(webpack@5.99.9(esbuild@0.25.5)) magic-string: 0.30.17 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.99.9) - terser-webpack-plugin: 5.3.14(webpack@5.99.9) + style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5)) + terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5)) ts-dedent: 2.2.0 - webpack: 5.99.9 - webpack-dev-middleware: 6.1.3(webpack@5.99.9) + webpack: 5.99.9(esbuild@0.25.5) + webpack-dev-middleware: 6.1.3(webpack@5.99.9(esbuild@0.25.5)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -24155,7 +24151,7 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@storybook/nextjs@9.0.8(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9)': + '@storybook/nextjs@9.0.8(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))': dependencies: '@babel/core': 7.27.4 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.4) @@ -24170,33 +24166,33 @@ snapshots: '@babel/preset-react': 7.27.1(@babel/core@7.27.4) '@babel/preset-typescript': 7.27.1(@babel/core@7.27.4) '@babel/runtime': 7.27.6 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9) - '@storybook/builder-webpack5': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - '@storybook/preset-react-webpack': 9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5)) + '@storybook/builder-webpack5': 9.0.8(esbuild@0.25.5)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) + '@storybook/preset-react-webpack': 9.0.8(esbuild@0.25.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) '@storybook/react': 9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) '@types/semver': 7.7.0 - babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9) - css-loader: 6.11.0(webpack@5.99.9) + babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5)) + css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5)) image-size: 2.0.2 loader-utils: 3.3.1 next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9(esbuild@0.25.5)) postcss: 8.5.5 - postcss-loader: 8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9) + postcss-loader: 8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 14.2.1(webpack@5.99.9) + sass-loader: 14.2.1(webpack@5.99.9(esbuild@0.25.5)) semver: 7.7.2 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.99.9) + style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5)) styled-jsx: 5.1.7(@babel/core@7.27.4)(react@19.1.0) tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 optionalDependencies: typescript: 5.8.3 - webpack: 5.99.9 + webpack: 5.99.9(esbuild@0.25.5) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -24275,10 +24271,10 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': + '@storybook/preset-react-webpack@9.0.8(esbuild@0.25.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) '@types/semver': 7.7.0 find-up: 5.0.0 magic-string: 0.30.17 @@ -24289,7 +24285,7 @@ snapshots: semver: 7.7.2 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) tsconfig-paths: 4.2.0 - webpack: 5.99.9 + webpack: 5.99.9(esbuild@0.25.5) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -24323,6 +24319,20 @@ snapshots: - uglify-js - webpack-cli + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))': + dependencies: + debug: 4.4.1(supports-color@8.1.1) + endent: 2.1.0 + find-cache-dir: 3.3.2 + flat-cache: 3.2.0 + micromatch: 4.0.8 + react-docgen-typescript: 2.4.0(typescript@5.8.3) + tslib: 2.8.1 + typescript: 5.8.3 + webpack: 5.99.9(esbuild@0.25.5) + transitivePeerDependencies: + - supports-color + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9)': dependencies: debug: 4.4.1(supports-color@8.1.1) @@ -27404,6 +27414,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + '@babel/core': 7.27.4 + find-cache-dir: 4.0.0 + schema-utils: 4.3.2 + webpack: 5.99.9(esbuild@0.25.5) + babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9): dependencies: '@babel/core': 7.27.4 @@ -28414,6 +28431,19 @@ snapshots: css-gradient-parser@0.0.16: {} + css-loader@6.11.0(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + icss-utils: 5.1.0(postcss@8.5.5) + postcss: 8.5.5 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.5) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.5) + postcss-modules-scope: 3.2.1(postcss@8.5.5) + postcss-modules-values: 4.0.0(postcss@8.5.5) + postcss-value-parser: 4.2.0 + semver: 7.7.2 + optionalDependencies: + webpack: 5.99.9(esbuild@0.25.5) + css-loader@6.11.0(webpack@5.99.9): dependencies: icss-utils: 5.1.0(postcss@8.5.5) @@ -29127,8 +29157,8 @@ snapshots: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.8.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-react: 7.37.5(eslint@8.57.0) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.0) @@ -29147,7 +29177,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1(supports-color@8.1.1) @@ -29158,7 +29188,7 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.9.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -29183,18 +29213,18 @@ snapshots: - bluebird - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.8.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -29205,7 +29235,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -29960,6 +29990,23 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + '@babel/code-frame': 7.27.1 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 7.1.0 + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.7.2 + tapable: 2.2.2 + typescript: 5.8.3 + webpack: 5.99.9(esbuild@0.25.5) + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9): dependencies: '@babel/code-frame': 7.27.1 @@ -30562,6 +30609,16 @@ snapshots: html-void-elements@3.0.0: {} + html-webpack-plugin@5.6.3(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + '@types/html-minifier-terser': 6.1.0 + html-minifier-terser: 6.1.0 + lodash: 4.17.21 + pretty-error: 4.0.0 + tapable: 2.2.2 + optionalDependencies: + webpack: 5.99.9(esbuild@0.25.5) + html-webpack-plugin@5.6.3(webpack@5.99.9): dependencies: '@types/html-minifier-terser': 6.1.0 @@ -32710,6 +32767,35 @@ snapshots: node-int64@0.4.0: {} + node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + assert: 2.1.0 + browserify-zlib: 0.2.0 + buffer: 6.0.3 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.1 + domain-browser: 4.23.0 + events: 3.3.0 + filter-obj: 2.0.2 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + process: 0.11.10 + punycode: 2.3.1 + querystring-es3: 0.2.1 + readable-stream: 4.7.0 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + type-fest: 2.19.0 + url: 0.11.4 + util: 0.12.5 + vm-browserify: 1.1.2 + webpack: 5.99.9(esbuild@0.25.5) + node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9): dependencies: assert: 2.1.0 @@ -33519,6 +33605,17 @@ snapshots: tsx: 4.20.1 yaml: 2.8.0 + postcss-loader@8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + cosmiconfig: 9.0.0(typescript@5.8.3) + jiti: 1.21.7 + postcss: 8.5.5 + semver: 7.7.2 + optionalDependencies: + webpack: 5.99.9(esbuild@0.25.5) + transitivePeerDependencies: + - typescript + postcss-loader@8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9): dependencies: cosmiconfig: 9.0.0(typescript@5.8.3) @@ -34720,6 +34817,12 @@ snapshots: safer-buffer@2.1.2: {} + sass-loader@14.2.1(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + neo-async: 2.6.2 + optionalDependencies: + webpack: 5.99.9(esbuild@0.25.5) + sass-loader@14.2.1(webpack@5.99.9): dependencies: neo-async: 2.6.2 @@ -35389,6 +35492,10 @@ snapshots: structured-headers@0.4.1: {} + style-loader@3.3.4(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + webpack: 5.99.9(esbuild@0.25.5) + style-loader@3.3.4(webpack@5.99.9): dependencies: webpack: 5.99.9 @@ -36787,6 +36894,16 @@ snapshots: - bufferutil - utf-8-validate + webpack-dev-middleware@6.1.3(webpack@5.99.9(esbuild@0.25.5)): + dependencies: + colorette: 2.0.20 + memfs: 3.5.3 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.3.2 + optionalDependencies: + webpack: 5.99.9(esbuild@0.25.5) + webpack-dev-middleware@6.1.3(webpack@5.99.9): dependencies: colorette: 2.0.20