Skip to content

Commit 4961d84

Browse files
Init API wrapper package
1 parent 7562952 commit 4961d84

24 files changed

+5901
-0
lines changed

.changeset/great-flowers-boil.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/api": patch
3+
---
4+
5+
Init api wrapper

packages/api/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# thirdweb API OpenAPI TypeScript wrapper
2+
3+
This package is a thin OpenAPI wrapper for the thirdweb API
4+
5+
## Configuration
6+
7+
```ts
8+
import { configure } from "@thirdweb-dev/api";
9+
10+
// call this once at the startup of your application
11+
configure({
12+
secretKey: "<PROJECT_SECRET_KEY>",
13+
});
14+
```
15+
16+
## Example Usage
17+
18+
```ts
19+
import { writeContract } from "@thirdweb-dev/api";
20+
21+
const result = await writeContract({
22+
headers: {
23+
"x-secret-key": "<PROJECT-SECRET-KEY>",
24+
},
25+
body: {
26+
from: "0x1234567891234567891234567891234567891234",
27+
chainId: "1",
28+
calls: [
29+
{
30+
contractAddress: "0x1234567890123456789012345678901234567890",
31+
method: "function transfer(address to, uint256 amount)",
32+
params: [
33+
"0x1234567890123456789012345678901234567890",
34+
"1000000000000000000",
35+
],
36+
},
37+
],
38+
},
39+
});
40+
```
41+
42+
This package was autogenerated from the [thirdweb openAPI spec](https://api.thirdweb.com/reference) using [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)

packages/api/biome.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
3+
"linter": {
4+
"rules": {
5+
"correctness": {
6+
"useImportExtensions": {
7+
"fix": "safe",
8+
"level": "error",
9+
"options": {
10+
"forceJsExtensions": true
11+
}
12+
}
13+
}
14+
}
15+
},
16+
"overrides": [
17+
{
18+
"assist": {
19+
"actions": {
20+
"source": {
21+
"useSortedKeys": "off"
22+
}
23+
}
24+
},
25+
"includes": ["package.json"]
26+
}
27+
]
28+
}

packages/api/openapi-ts.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from "@hey-api/openapi-ts";
2+
3+
export default defineConfig({
4+
input: "https://api.thirdweb.com/openapi.json",
5+
output: { format: "biome", lint: "biome", path: "src/client" },
6+
});

packages/api/package.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"name": "@thirdweb-dev/api",
3+
"version": "0.0.1",
4+
"repository": {
5+
"type": "git",
6+
"url": "git+https://github.com/thirdweb-dev/js.git#main"
7+
},
8+
"author": "thirdweb eng <[email protected]>",
9+
"type": "module",
10+
"main": "./dist/cjs/exports/thirdweb.js",
11+
"module": "./dist/esm/exports/thirdweb.js",
12+
"types": "./dist/types/exports/thirdweb.d.ts",
13+
"typings": "./dist/types/exports/thirdweb.d.ts",
14+
"license": "Apache-2.0",
15+
"bugs": {
16+
"url": "https://github.com/thirdweb-dev/js/issues"
17+
},
18+
"dependencies": {
19+
"@hey-api/client-fetch": "0.10.0"
20+
},
21+
"engines": {
22+
"node": ">=18"
23+
},
24+
"exports": {
25+
".": {
26+
"types": "./dist/types/exports/thirdweb.d.ts",
27+
"import": "./dist/esm/exports/thirdweb.js",
28+
"default": "./dist/cjs/exports/thirdweb.js"
29+
},
30+
"./package.json": "./package.json"
31+
},
32+
"files": [
33+
"dist/*",
34+
"src/*"
35+
],
36+
"devDependencies": {
37+
"@biomejs/biome": "2.0.6",
38+
"@hey-api/openapi-ts": "0.76.0",
39+
"rimraf": "6.0.1",
40+
"tslib": "^2.8.1"
41+
},
42+
"peerDependencies": {
43+
"typescript": ">=5.0.4"
44+
},
45+
"peerDependenciesMeta": {
46+
"typescript": {
47+
"optional": true
48+
}
49+
},
50+
"scripts": {
51+
"build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types",
52+
"build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json",
53+
"build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
54+
"build:generate": "openapi-ts && pnpm format && pnpm fix",
55+
"build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
56+
"clean": "rimraf dist",
57+
"fix": "biome check --write ./src",
58+
"format": "biome format --write ./src",
59+
"lint": "biome check ./src"
60+
}
61+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import {
4+
type Config,
5+
createClient,
6+
createConfig,
7+
type ClientOptions as DefaultClientOptions,
8+
} from "./client/index.js";
9+
import type { ClientOptions } from "./types.gen.js";
10+
11+
/**
12+
* The `createClientConfig()` function will be called on client initialization
13+
* and the returned object will become the client's initial configuration.
14+
*
15+
* You may want to initialize your client this way instead of calling
16+
* `setConfig()`. This is useful for example if you're using Next.js
17+
* to ensure your client always has the correct values.
18+
*/
19+
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> =
20+
(
21+
override?: Config<DefaultClientOptions & T>,
22+
) => Config<Required<DefaultClientOptions> & T>;
23+
24+
export const client = createClient(
25+
createConfig<ClientOptions>({
26+
baseUrl: "https://api.thirdweb.com",
27+
}),
28+
);
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import type { Client, Config, RequestOptions } from "./types.js";
2+
import {
3+
buildUrl,
4+
createConfig,
5+
createInterceptors,
6+
getParseAs,
7+
mergeConfigs,
8+
mergeHeaders,
9+
setAuthParams,
10+
} from "./utils.js";
11+
12+
type ReqInit = Omit<RequestInit, "body" | "headers"> & {
13+
body?: any;
14+
headers: ReturnType<typeof mergeHeaders>;
15+
};
16+
17+
export const createClient = (config: Config = {}): Client => {
18+
let _config = mergeConfigs(createConfig(), config);
19+
20+
const getConfig = (): Config => ({ ..._config });
21+
22+
const setConfig = (config: Config): Config => {
23+
_config = mergeConfigs(_config, config);
24+
return getConfig();
25+
};
26+
27+
const interceptors = createInterceptors<
28+
Request,
29+
Response,
30+
unknown,
31+
RequestOptions
32+
>();
33+
34+
const request: Client["request"] = async (options) => {
35+
const opts = {
36+
..._config,
37+
...options,
38+
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
39+
headers: mergeHeaders(_config.headers, options.headers),
40+
};
41+
42+
if (opts.security) {
43+
await setAuthParams({
44+
...opts,
45+
security: opts.security,
46+
});
47+
}
48+
49+
if (opts.body && opts.bodySerializer) {
50+
opts.body = opts.bodySerializer(opts.body);
51+
}
52+
53+
// remove Content-Type header if body is empty to avoid sending invalid requests
54+
if (opts.body === undefined || opts.body === "") {
55+
opts.headers.delete("Content-Type");
56+
}
57+
58+
const url = buildUrl(opts);
59+
const requestInit: ReqInit = {
60+
redirect: "follow",
61+
...opts,
62+
};
63+
64+
let request = new Request(url, requestInit);
65+
66+
for (const fn of interceptors.request._fns) {
67+
if (fn) {
68+
request = await fn(request, opts);
69+
}
70+
}
71+
72+
// fetch must be assigned here, otherwise it would throw the error:
73+
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
74+
const _fetch = opts.fetch!;
75+
let response = await _fetch(request);
76+
77+
for (const fn of interceptors.response._fns) {
78+
if (fn) {
79+
response = await fn(response, request, opts);
80+
}
81+
}
82+
83+
const result = {
84+
request,
85+
response,
86+
};
87+
88+
if (response.ok) {
89+
if (
90+
response.status === 204 ||
91+
response.headers.get("Content-Length") === "0"
92+
) {
93+
return opts.responseStyle === "data"
94+
? {}
95+
: {
96+
data: {},
97+
...result,
98+
};
99+
}
100+
101+
const parseAs =
102+
(opts.parseAs === "auto"
103+
? getParseAs(response.headers.get("Content-Type"))
104+
: opts.parseAs) ?? "json";
105+
106+
let data: any;
107+
switch (parseAs) {
108+
case "arrayBuffer":
109+
case "blob":
110+
case "formData":
111+
case "json":
112+
case "text":
113+
data = await response[parseAs]();
114+
break;
115+
case "stream":
116+
return opts.responseStyle === "data"
117+
? response.body
118+
: {
119+
data: response.body,
120+
...result,
121+
};
122+
}
123+
124+
if (parseAs === "json") {
125+
if (opts.responseValidator) {
126+
await opts.responseValidator(data);
127+
}
128+
129+
if (opts.responseTransformer) {
130+
data = await opts.responseTransformer(data);
131+
}
132+
}
133+
134+
return opts.responseStyle === "data"
135+
? data
136+
: {
137+
data,
138+
...result,
139+
};
140+
}
141+
142+
let error = await response.text();
143+
144+
try {
145+
error = JSON.parse(error);
146+
} catch {
147+
// noop
148+
}
149+
150+
let finalError = error;
151+
152+
for (const fn of interceptors.error._fns) {
153+
if (fn) {
154+
finalError = (await fn(error, response, request, opts)) as string;
155+
}
156+
}
157+
158+
finalError = finalError || ({} as string);
159+
160+
if (opts.throwOnError) {
161+
throw finalError;
162+
}
163+
164+
// TODO: we probably want to return error and improve types
165+
return opts.responseStyle === "data"
166+
? undefined
167+
: {
168+
error: finalError,
169+
...result,
170+
};
171+
};
172+
173+
return {
174+
buildUrl,
175+
connect: (options) => request({ ...options, method: "CONNECT" }),
176+
delete: (options) => request({ ...options, method: "DELETE" }),
177+
get: (options) => request({ ...options, method: "GET" }),
178+
getConfig,
179+
head: (options) => request({ ...options, method: "HEAD" }),
180+
interceptors,
181+
options: (options) => request({ ...options, method: "OPTIONS" }),
182+
patch: (options) => request({ ...options, method: "PATCH" }),
183+
post: (options) => request({ ...options, method: "POST" }),
184+
put: (options) => request({ ...options, method: "PUT" }),
185+
request,
186+
setConfig,
187+
trace: (options) => request({ ...options, method: "TRACE" }),
188+
};
189+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export type { Auth } from "../core/auth.js";
2+
export type { QuerySerializerOptions } from "../core/bodySerializer.js";
3+
export {
4+
formDataBodySerializer,
5+
jsonBodySerializer,
6+
urlSearchParamsBodySerializer,
7+
} from "../core/bodySerializer.js";
8+
export { buildClientParams } from "../core/params.js";
9+
export { createClient } from "./client.js";
10+
export type {
11+
Client,
12+
ClientOptions,
13+
Config,
14+
CreateClientConfig,
15+
Options,
16+
OptionsLegacyParser,
17+
RequestOptions,
18+
RequestResult,
19+
ResponseStyle,
20+
TDataShape,
21+
} from "./types.js";
22+
export { createConfig, mergeHeaders } from "./utils.js";

0 commit comments

Comments
 (0)