@cushin/api-codegen 1.1.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +100 -612
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +141 -7
- package/dist/index.js +101 -469
- package/dist/index.js.map +1 -1
- package/package.json +14 -19
- package/README.md +0 -435
- package/dist/cli.d.ts +0 -1
- package/dist/config/index.d.ts +0 -84
- package/dist/config/index.js +0 -69
- package/dist/config/index.js.map +0 -1
- package/dist/config/schema.d.ts +0 -43
- package/dist/config/schema.js +0 -14
- package/dist/config/schema.js.map +0 -1
- package/dist/runtime/client.d.ts +0 -40
- package/dist/runtime/client.js +0 -260
- package/dist/runtime/client.js.map +0 -1
package/dist/runtime/client.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { APIConfig, APIEndpoint } from '../config/schema.js';
|
|
2
|
-
import 'zod';
|
|
3
|
-
|
|
4
|
-
interface AuthTokens {
|
|
5
|
-
accessToken: string;
|
|
6
|
-
refreshToken?: string;
|
|
7
|
-
}
|
|
8
|
-
interface AuthCallbacks {
|
|
9
|
-
getTokens: () => Promise<AuthTokens | null>;
|
|
10
|
-
onAuthError?: () => void;
|
|
11
|
-
onRefreshToken?: () => Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
declare class APIError extends Error {
|
|
14
|
-
status: number;
|
|
15
|
-
response?: any | undefined;
|
|
16
|
-
constructor(message: string, status: number, response?: any | undefined);
|
|
17
|
-
}
|
|
18
|
-
declare class AuthError extends APIError {
|
|
19
|
-
constructor(message?: string);
|
|
20
|
-
}
|
|
21
|
-
declare class APIClient {
|
|
22
|
-
private config;
|
|
23
|
-
private authCallbacks?;
|
|
24
|
-
private client;
|
|
25
|
-
private isRefreshing;
|
|
26
|
-
private refreshPromise;
|
|
27
|
-
private hooks;
|
|
28
|
-
constructor(config: APIConfig, authCallbacks?: AuthCallbacks | undefined);
|
|
29
|
-
private refreshTokens;
|
|
30
|
-
private buildPath;
|
|
31
|
-
private getEndpointBaseUrl;
|
|
32
|
-
private getClientForEndpoint;
|
|
33
|
-
request<T>(endpoint: APIEndpoint, params?: Record<string, any>, query?: Record<string, any>, body?: any): Promise<T>;
|
|
34
|
-
updateAuthCallbacks(authCallbacks: AuthCallbacks): void;
|
|
35
|
-
refreshAuth(): Promise<void>;
|
|
36
|
-
generateMethods(): any;
|
|
37
|
-
}
|
|
38
|
-
declare function createAPIClient(config: APIConfig, authCallbacks?: AuthCallbacks): any;
|
|
39
|
-
|
|
40
|
-
export { APIClient, APIError, type AuthCallbacks, AuthError, type AuthTokens, createAPIClient };
|
package/dist/runtime/client.js
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import ky, { HTTPError } from 'ky';
|
|
2
|
-
|
|
3
|
-
// src/runtime/client.ts
|
|
4
|
-
var APIError = class extends Error {
|
|
5
|
-
constructor(message, status, response) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.status = status;
|
|
8
|
-
this.response = response;
|
|
9
|
-
this.name = "APIError";
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
var AuthError = class extends APIError {
|
|
13
|
-
constructor(message = "Authentication failed") {
|
|
14
|
-
super(message, 401);
|
|
15
|
-
this.name = "AuthError";
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var APIClient = class {
|
|
19
|
-
constructor(config, authCallbacks) {
|
|
20
|
-
this.config = config;
|
|
21
|
-
this.authCallbacks = authCallbacks;
|
|
22
|
-
this.hooks = {
|
|
23
|
-
beforeRequest: [
|
|
24
|
-
async (request) => {
|
|
25
|
-
const tokens = await this.authCallbacks?.getTokens();
|
|
26
|
-
if (tokens?.accessToken) {
|
|
27
|
-
request.headers.set(
|
|
28
|
-
"Authorization",
|
|
29
|
-
`Bearer ${tokens.accessToken}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
beforeRetry: [
|
|
35
|
-
async ({ request, error, retryCount }) => {
|
|
36
|
-
if (error instanceof HTTPError && error.response.status === 401) {
|
|
37
|
-
if (retryCount === 1 && this.authCallbacks) {
|
|
38
|
-
try {
|
|
39
|
-
await this.refreshTokens();
|
|
40
|
-
const tokens = await this.authCallbacks.getTokens();
|
|
41
|
-
if (tokens?.accessToken) {
|
|
42
|
-
request.headers.set(
|
|
43
|
-
"Authorization",
|
|
44
|
-
`Bearer ${tokens.accessToken}`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
} catch (refreshError) {
|
|
48
|
-
this.authCallbacks.onAuthError?.();
|
|
49
|
-
throw new AuthError();
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
this.authCallbacks?.onAuthError?.();
|
|
53
|
-
throw new AuthError();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
|
-
beforeError: [
|
|
59
|
-
async (error) => {
|
|
60
|
-
const { response } = error;
|
|
61
|
-
if (response?.body) {
|
|
62
|
-
try {
|
|
63
|
-
const body = await response.json();
|
|
64
|
-
error.message = body.message || `HTTP ${response.status}`;
|
|
65
|
-
} catch {
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return error;
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
};
|
|
72
|
-
this.client = ky.create({
|
|
73
|
-
prefixUrl: this.config.baseUrl,
|
|
74
|
-
headers: {
|
|
75
|
-
"Content-Type": "application/json"
|
|
76
|
-
},
|
|
77
|
-
retry: {
|
|
78
|
-
limit: 2,
|
|
79
|
-
methods: ["get", "post", "put", "delete", "patch"],
|
|
80
|
-
statusCodes: [401]
|
|
81
|
-
},
|
|
82
|
-
hooks: this.hooks
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
client;
|
|
86
|
-
isRefreshing = false;
|
|
87
|
-
refreshPromise = null;
|
|
88
|
-
hooks;
|
|
89
|
-
async refreshTokens() {
|
|
90
|
-
if (!this.authCallbacks) {
|
|
91
|
-
throw new AuthError("No auth callbacks provided");
|
|
92
|
-
}
|
|
93
|
-
if (this.isRefreshing && this.refreshPromise) {
|
|
94
|
-
return this.refreshPromise;
|
|
95
|
-
}
|
|
96
|
-
this.isRefreshing = true;
|
|
97
|
-
this.refreshPromise = (async () => {
|
|
98
|
-
try {
|
|
99
|
-
if (this.authCallbacks?.onRefreshToken) {
|
|
100
|
-
await this.authCallbacks.onRefreshToken();
|
|
101
|
-
} else {
|
|
102
|
-
throw new AuthError("No refresh token handler provided");
|
|
103
|
-
}
|
|
104
|
-
} catch (error) {
|
|
105
|
-
throw error;
|
|
106
|
-
} finally {
|
|
107
|
-
this.isRefreshing = false;
|
|
108
|
-
this.refreshPromise = null;
|
|
109
|
-
}
|
|
110
|
-
})();
|
|
111
|
-
return this.refreshPromise;
|
|
112
|
-
}
|
|
113
|
-
buildPath(path, params) {
|
|
114
|
-
if (!params) return path;
|
|
115
|
-
let finalPath = path;
|
|
116
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
117
|
-
finalPath = finalPath.replace(
|
|
118
|
-
`:${key}`,
|
|
119
|
-
encodeURIComponent(String(value))
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
return finalPath;
|
|
123
|
-
}
|
|
124
|
-
getEndpointBaseUrl(endpoint) {
|
|
125
|
-
return endpoint.baseUrl || this.config.baseUrl;
|
|
126
|
-
}
|
|
127
|
-
getClientForEndpoint(endpoint) {
|
|
128
|
-
const endpointBaseUrl = this.getEndpointBaseUrl(endpoint);
|
|
129
|
-
if (endpointBaseUrl === this.config.baseUrl) {
|
|
130
|
-
return this.client;
|
|
131
|
-
}
|
|
132
|
-
return ky.create({
|
|
133
|
-
prefixUrl: endpointBaseUrl,
|
|
134
|
-
headers: {
|
|
135
|
-
"Content-Type": "application/json"
|
|
136
|
-
},
|
|
137
|
-
retry: {
|
|
138
|
-
limit: 2,
|
|
139
|
-
methods: ["get", "post", "put", "delete", "patch"],
|
|
140
|
-
statusCodes: [401]
|
|
141
|
-
},
|
|
142
|
-
hooks: this.hooks
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
async request(endpoint, params, query, body) {
|
|
146
|
-
try {
|
|
147
|
-
const path = this.buildPath(endpoint.path, params);
|
|
148
|
-
const client = this.getClientForEndpoint(endpoint);
|
|
149
|
-
const options = {
|
|
150
|
-
method: endpoint.method
|
|
151
|
-
};
|
|
152
|
-
if (query && Object.keys(query).length > 0) {
|
|
153
|
-
const searchParams = new URLSearchParams();
|
|
154
|
-
Object.entries(query).forEach(([key, value]) => {
|
|
155
|
-
if (value !== void 0 && value !== null) {
|
|
156
|
-
searchParams.append(key, String(value));
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
if (searchParams.toString()) {
|
|
160
|
-
options.searchParams = searchParams;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (body && endpoint.method !== "GET") {
|
|
164
|
-
if (endpoint.body) {
|
|
165
|
-
const validatedBody = endpoint.body.parse(body);
|
|
166
|
-
options.json = validatedBody;
|
|
167
|
-
} else {
|
|
168
|
-
options.json = body;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
const response = await client(path, options);
|
|
172
|
-
const data = await response.json();
|
|
173
|
-
if (endpoint.response) {
|
|
174
|
-
return endpoint.response.parse(data);
|
|
175
|
-
}
|
|
176
|
-
return data;
|
|
177
|
-
} catch (error) {
|
|
178
|
-
if (error instanceof HTTPError) {
|
|
179
|
-
const errorData = await error.response.json().catch(() => ({}));
|
|
180
|
-
throw new APIError(
|
|
181
|
-
errorData.message || error.message,
|
|
182
|
-
error.response.status,
|
|
183
|
-
errorData
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
if (error instanceof AuthError) {
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
throw new APIError(
|
|
190
|
-
error instanceof Error ? error.message : "Network error",
|
|
191
|
-
0
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
updateAuthCallbacks(authCallbacks) {
|
|
196
|
-
this.authCallbacks = authCallbacks;
|
|
197
|
-
}
|
|
198
|
-
async refreshAuth() {
|
|
199
|
-
if (!this.authCallbacks) {
|
|
200
|
-
throw new AuthError("No auth callbacks provided");
|
|
201
|
-
}
|
|
202
|
-
await this.refreshTokens();
|
|
203
|
-
}
|
|
204
|
-
generateMethods() {
|
|
205
|
-
const methods = {};
|
|
206
|
-
Object.entries(this.config.endpoints).forEach(([name, endpoint]) => {
|
|
207
|
-
if (endpoint.method === "GET") {
|
|
208
|
-
if (endpoint.params && endpoint.query) {
|
|
209
|
-
methods[name] = (params, query) => {
|
|
210
|
-
return this.request(endpoint, params, query);
|
|
211
|
-
};
|
|
212
|
-
} else if (endpoint.params) {
|
|
213
|
-
methods[name] = (params) => {
|
|
214
|
-
return this.request(endpoint, params);
|
|
215
|
-
};
|
|
216
|
-
} else if (endpoint.query) {
|
|
217
|
-
methods[name] = (query) => {
|
|
218
|
-
return this.request(endpoint, void 0, query);
|
|
219
|
-
};
|
|
220
|
-
} else {
|
|
221
|
-
methods[name] = () => {
|
|
222
|
-
return this.request(endpoint);
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
if (endpoint.params && endpoint.body) {
|
|
227
|
-
methods[name] = (params, body) => {
|
|
228
|
-
return this.request(endpoint, params, void 0, body);
|
|
229
|
-
};
|
|
230
|
-
} else if (endpoint.params) {
|
|
231
|
-
methods[name] = (params) => {
|
|
232
|
-
return this.request(endpoint, params);
|
|
233
|
-
};
|
|
234
|
-
} else if (endpoint.body) {
|
|
235
|
-
methods[name] = (body) => {
|
|
236
|
-
return this.request(endpoint, void 0, void 0, body);
|
|
237
|
-
};
|
|
238
|
-
} else {
|
|
239
|
-
methods[name] = () => {
|
|
240
|
-
return this.request(endpoint);
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
return methods;
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
function createAPIClient(config, authCallbacks) {
|
|
249
|
-
const instance = new APIClient(config, authCallbacks);
|
|
250
|
-
const methods = instance.generateMethods();
|
|
251
|
-
return {
|
|
252
|
-
...methods,
|
|
253
|
-
refreshAuth: () => instance.refreshAuth(),
|
|
254
|
-
updateAuthCallbacks: (newCallbacks) => instance.updateAuthCallbacks(newCallbacks)
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
export { APIClient, APIError, AuthError, createAPIClient };
|
|
259
|
-
//# sourceMappingURL=client.js.map
|
|
260
|
-
//# sourceMappingURL=client.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["import ky, { HTTPError } from \"ky\";\nimport type { APIConfig, APIEndpoint } from \"../config/schema.js\";\n\nexport interface AuthTokens {\n accessToken: string;\n refreshToken?: string;\n}\n\nexport interface AuthCallbacks {\n getTokens: () => Promise<AuthTokens | null>;\n onAuthError?: () => void;\n onRefreshToken?: () => Promise<void>;\n}\n\nexport class APIError extends Error {\n constructor(\n message: string,\n public status: number,\n public response?: any,\n ) {\n super(message);\n this.name = \"APIError\";\n }\n}\n\nexport class AuthError extends APIError {\n constructor(message: string = \"Authentication failed\") {\n super(message, 401);\n this.name = \"AuthError\";\n }\n}\n\nexport class APIClient {\n private client: typeof ky;\n private isRefreshing = false;\n private refreshPromise: Promise<void> | null = null;\n private hooks: any;\n\n constructor(\n private config: APIConfig,\n private authCallbacks?: AuthCallbacks,\n ) {\n this.hooks = {\n beforeRequest: [\n async (request: Request) => {\n const tokens = await this.authCallbacks?.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n },\n ],\n beforeRetry: [\n async ({ request, error, retryCount }: any) => {\n if (error instanceof HTTPError && error.response.status === 401) {\n if (retryCount === 1 && this.authCallbacks) {\n try {\n await this.refreshTokens();\n const tokens = await this.authCallbacks.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n } catch (refreshError) {\n this.authCallbacks.onAuthError?.();\n throw new AuthError();\n }\n } else {\n this.authCallbacks?.onAuthError?.();\n throw new AuthError();\n }\n }\n },\n ],\n beforeError: [\n async (error: any) => {\n const { response } = error;\n if (response?.body) {\n try {\n const body = await response.json();\n error.message =\n (body as Error).message || `HTTP ${response.status}`;\n } catch {\n // Keep original message\n }\n }\n return error;\n },\n ],\n };\n\n this.client = ky.create({\n prefixUrl: this.config.baseUrl,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n private async refreshTokens(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n\n if (this.isRefreshing && this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.isRefreshing = true;\n\n this.refreshPromise = (async () => {\n try {\n if (this.authCallbacks?.onRefreshToken) {\n await this.authCallbacks.onRefreshToken();\n } else {\n throw new AuthError(\"No refresh token handler provided\");\n }\n } catch (error) {\n throw error;\n } finally {\n this.isRefreshing = false;\n this.refreshPromise = null;\n }\n })();\n\n return this.refreshPromise;\n }\n\n private buildPath(path: string, params?: Record<string, any>): string {\n if (!params) return path;\n\n let finalPath = path;\n Object.entries(params).forEach(([key, value]) => {\n finalPath = finalPath.replace(\n `:${key}`,\n encodeURIComponent(String(value)),\n );\n });\n\n return finalPath;\n }\n\n private getEndpointBaseUrl(endpoint: APIEndpoint): string {\n return endpoint.baseUrl || this.config.baseUrl!;\n }\n\n private getClientForEndpoint(endpoint: APIEndpoint): typeof ky {\n const endpointBaseUrl = this.getEndpointBaseUrl(endpoint);\n\n if (endpointBaseUrl === this.config.baseUrl) {\n return this.client;\n }\n\n return ky.create({\n prefixUrl: endpointBaseUrl,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n async request<T>(\n endpoint: APIEndpoint,\n params?: Record<string, any>,\n query?: Record<string, any>,\n body?: any,\n ): Promise<T> {\n try {\n const path = this.buildPath(endpoint.path, params);\n const client = this.getClientForEndpoint(endpoint);\n\n const options: Record<string, any> = {\n method: endpoint.method,\n };\n\n if (query && Object.keys(query).length > 0) {\n const searchParams = new URLSearchParams();\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n searchParams.append(key, String(value));\n }\n });\n if (searchParams.toString()) {\n options.searchParams = searchParams;\n }\n }\n\n if (body && endpoint.method !== \"GET\") {\n if (endpoint.body) {\n const validatedBody = endpoint.body.parse(body);\n options.json = validatedBody;\n } else {\n options.json = body;\n }\n }\n\n const response = await client(path, options);\n const data = await response.json();\n\n if (endpoint.response) {\n return endpoint.response.parse(data);\n }\n\n return data as T;\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorData = await error.response.json().catch(() => ({}));\n throw new APIError(\n errorData.message || error.message,\n error.response.status,\n errorData,\n );\n }\n\n if (error instanceof AuthError) {\n throw error;\n }\n\n throw new APIError(\n error instanceof Error ? error.message : \"Network error\",\n 0,\n );\n }\n }\n\n updateAuthCallbacks(authCallbacks: AuthCallbacks) {\n this.authCallbacks = authCallbacks;\n }\n\n async refreshAuth(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n await this.refreshTokens();\n }\n\n generateMethods() {\n const methods: any = {};\n\n Object.entries(this.config.endpoints).forEach(([name, endpoint]) => {\n if (endpoint.method === \"GET\") {\n if (endpoint.params && endpoint.query) {\n methods[name] = (params: any, query?: any): Promise<any> => {\n return this.request(endpoint, params, query);\n };\n } else if (endpoint.params) {\n methods[name] = (params: any): Promise<any> => {\n return this.request(endpoint, params);\n };\n } else if (endpoint.query) {\n methods[name] = (query?: any): Promise<any> => {\n return this.request(endpoint, undefined, query);\n };\n } else {\n methods[name] = (): Promise<any> => {\n return this.request(endpoint);\n };\n }\n } else {\n if (endpoint.params && endpoint.body) {\n methods[name] = (params: any, body: any): Promise<any> => {\n return this.request(endpoint, params, undefined, body);\n };\n } else if (endpoint.params) {\n methods[name] = (params: any): Promise<any> => {\n return this.request(endpoint, params);\n };\n } else if (endpoint.body) {\n methods[name] = (body: any): Promise<any> => {\n return this.request(endpoint, undefined, undefined, body);\n };\n } else {\n methods[name] = (): Promise<any> => {\n return this.request(endpoint);\n };\n }\n }\n });\n\n return methods;\n }\n}\n\nexport function createAPIClient(\n config: APIConfig,\n authCallbacks?: AuthCallbacks,\n) {\n const instance = new APIClient(config, authCallbacks);\n const methods = instance.generateMethods();\n\n return {\n ...methods,\n refreshAuth: () => instance.refreshAuth(),\n updateAuthCallbacks: (newCallbacks: AuthCallbacks) =>\n instance.updateAuthCallbacks(newCallbacks),\n };\n}\n"]}
|