@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/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { cosmiconfig } from 'cosmiconfig';
|
|
2
|
-
import path6 from 'path';
|
|
3
|
-
import ky, { HTTPError } from 'ky';
|
|
4
|
-
import { createJiti } from 'jiti';
|
|
5
|
-
import fs5 from 'fs/promises';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
|
|
8
1
|
// src/config/schema.ts
|
|
9
2
|
function defineConfig(config) {
|
|
10
3
|
return config;
|
|
@@ -15,6 +8,10 @@ function defineEndpoint(config) {
|
|
|
15
8
|
function defineEndpoints(endpoints) {
|
|
16
9
|
return endpoints;
|
|
17
10
|
}
|
|
11
|
+
|
|
12
|
+
// src/config/index.ts
|
|
13
|
+
import { cosmiconfig } from "cosmiconfig";
|
|
14
|
+
import path from "path";
|
|
18
15
|
var explorer = cosmiconfig("api-codegen", {
|
|
19
16
|
searchPlaces: [
|
|
20
17
|
"api-codegen.config.js",
|
|
@@ -33,9 +30,9 @@ async function loadConfig(configPath) {
|
|
|
33
30
|
return null;
|
|
34
31
|
}
|
|
35
32
|
const userConfig = result.config;
|
|
36
|
-
const rootDir =
|
|
37
|
-
const endpointsPath =
|
|
38
|
-
const outputDir =
|
|
33
|
+
const rootDir = path.dirname(result.filepath);
|
|
34
|
+
const endpointsPath = path.resolve(rootDir, userConfig.endpoints);
|
|
35
|
+
const outputDir = path.resolve(rootDir, userConfig.output);
|
|
39
36
|
const generateHooks = userConfig.generateHooks ?? true;
|
|
40
37
|
const generateServerActions = userConfig.generateServerActions ?? userConfig.provider === "nextjs";
|
|
41
38
|
const generateServerQueries = userConfig.generateServerQueries ?? userConfig.provider === "nextjs";
|
|
@@ -76,6 +73,9 @@ function validateConfig(config) {
|
|
|
76
73
|
throw new Error('Config error: "output" directory is required');
|
|
77
74
|
}
|
|
78
75
|
}
|
|
76
|
+
|
|
77
|
+
// src/runtime/client.ts
|
|
78
|
+
import ky, { HTTPError } from "ky";
|
|
79
79
|
var APIError = class extends Error {
|
|
80
80
|
constructor(message, status, response) {
|
|
81
81
|
super(message);
|
|
@@ -185,9 +185,9 @@ var APIClient = class {
|
|
|
185
185
|
})();
|
|
186
186
|
return this.refreshPromise;
|
|
187
187
|
}
|
|
188
|
-
buildPath(
|
|
189
|
-
if (!params) return
|
|
190
|
-
let finalPath =
|
|
188
|
+
buildPath(path10, params) {
|
|
189
|
+
if (!params) return path10;
|
|
190
|
+
let finalPath = path10;
|
|
191
191
|
Object.entries(params).forEach(([key, value]) => {
|
|
192
192
|
finalPath = finalPath.replace(
|
|
193
193
|
`:${key}`,
|
|
@@ -219,7 +219,7 @@ var APIClient = class {
|
|
|
219
219
|
}
|
|
220
220
|
async request(endpoint, params, query, body) {
|
|
221
221
|
try {
|
|
222
|
-
const
|
|
222
|
+
const path10 = this.buildPath(endpoint.path, params);
|
|
223
223
|
const client = this.getClientForEndpoint(endpoint);
|
|
224
224
|
const options = {
|
|
225
225
|
method: endpoint.method
|
|
@@ -243,7 +243,7 @@ var APIClient = class {
|
|
|
243
243
|
options.json = body;
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
-
const response = await client(
|
|
246
|
+
const response = await client(path10, options);
|
|
247
247
|
const data = await response.json();
|
|
248
248
|
if (endpoint.response) {
|
|
249
249
|
return endpoint.response.parse(data);
|
|
@@ -330,6 +330,13 @@ function createAPIClient(config, authCallbacks) {
|
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
+
// src/core/codegen.ts
|
|
334
|
+
import { createJiti } from "jiti";
|
|
335
|
+
|
|
336
|
+
// src/generators/hooks.ts
|
|
337
|
+
import fs from "fs/promises";
|
|
338
|
+
import path2 from "path";
|
|
339
|
+
|
|
333
340
|
// src/generators/base.ts
|
|
334
341
|
var BaseGenerator = class {
|
|
335
342
|
constructor(context) {
|
|
@@ -434,15 +441,15 @@ var BaseGenerator = class {
|
|
|
434
441
|
var HooksGenerator = class extends BaseGenerator {
|
|
435
442
|
async generate() {
|
|
436
443
|
const content = this.generateContent();
|
|
437
|
-
const outputPath =
|
|
438
|
-
await
|
|
439
|
-
await
|
|
444
|
+
const outputPath = path2.join(this.context.config.outputDir, "hooks.ts");
|
|
445
|
+
await fs.mkdir(path2.dirname(outputPath), { recursive: true });
|
|
446
|
+
await fs.writeFile(outputPath, content, "utf-8");
|
|
440
447
|
}
|
|
441
448
|
generateContent() {
|
|
442
449
|
const useClientDirective = this.context.config.options?.useClientDirective ?? true;
|
|
443
|
-
const outputPath =
|
|
444
|
-
const endpointsPath =
|
|
445
|
-
const relativePath =
|
|
450
|
+
const outputPath = path2.join(this.context.config.outputDir, "types.ts");
|
|
451
|
+
const endpointsPath = path2.join(this.context.config.endpointsPath);
|
|
452
|
+
const relativePath = path2.relative(path2.dirname(outputPath), endpointsPath).replace(/\\/g, "/");
|
|
446
453
|
const content = `${useClientDirective ? "'use client';\n" : ""}
|
|
447
454
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
448
455
|
import { apiClient } from "./client";
|
|
@@ -568,12 +575,16 @@ export function ${hookName}(${params.join(",\n ")}) {
|
|
|
568
575
|
}`;
|
|
569
576
|
}
|
|
570
577
|
};
|
|
578
|
+
|
|
579
|
+
// src/generators/actions.ts
|
|
580
|
+
import fs2 from "fs/promises";
|
|
581
|
+
import path3 from "path";
|
|
571
582
|
var ServerActionsGenerator = class extends BaseGenerator {
|
|
572
583
|
async generate() {
|
|
573
584
|
const content = this.generateContent();
|
|
574
|
-
const outputPath =
|
|
575
|
-
await
|
|
576
|
-
await
|
|
585
|
+
const outputPath = path3.join(this.context.config.outputDir, "actions.ts");
|
|
586
|
+
await fs2.mkdir(path3.dirname(outputPath), { recursive: true });
|
|
587
|
+
await fs2.writeFile(outputPath, content, "utf-8");
|
|
577
588
|
}
|
|
578
589
|
generateContent() {
|
|
579
590
|
const imports = `'use server';
|
|
@@ -641,12 +652,16 @@ ${revalidateStatements}
|
|
|
641
652
|
}`;
|
|
642
653
|
}
|
|
643
654
|
};
|
|
655
|
+
|
|
656
|
+
// src/generators/queries.ts
|
|
657
|
+
import fs3 from "fs/promises";
|
|
658
|
+
import path4 from "path";
|
|
644
659
|
var ServerQueriesGenerator = class extends BaseGenerator {
|
|
645
660
|
async generate() {
|
|
646
661
|
const content = this.generateContent();
|
|
647
|
-
const outputPath =
|
|
648
|
-
await
|
|
649
|
-
await
|
|
662
|
+
const outputPath = path4.join(this.context.config.outputDir, "queries.ts");
|
|
663
|
+
await fs3.mkdir(path4.dirname(outputPath), { recursive: true });
|
|
664
|
+
await fs3.writeFile(outputPath, content, "utf-8");
|
|
650
665
|
}
|
|
651
666
|
generateContent() {
|
|
652
667
|
const imports = `import { cache } from 'react';
|
|
@@ -700,17 +715,21 @@ export const ${queryName} = cache(async (
|
|
|
700
715
|
});`;
|
|
701
716
|
}
|
|
702
717
|
};
|
|
718
|
+
|
|
719
|
+
// src/generators/types.ts
|
|
720
|
+
import fs4 from "fs/promises";
|
|
721
|
+
import path5 from "path";
|
|
703
722
|
var TypesGenerator = class extends BaseGenerator {
|
|
704
723
|
async generate() {
|
|
705
724
|
const content = this.generateContent();
|
|
706
|
-
const outputPath =
|
|
707
|
-
await
|
|
708
|
-
await
|
|
725
|
+
const outputPath = path5.join(this.context.config.outputDir, "types.ts");
|
|
726
|
+
await fs4.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
727
|
+
await fs4.writeFile(outputPath, content, "utf-8");
|
|
709
728
|
}
|
|
710
729
|
generateContent() {
|
|
711
|
-
const outputPath =
|
|
712
|
-
const endpointsPath =
|
|
713
|
-
const relativePath =
|
|
730
|
+
const outputPath = path5.join(this.context.config.outputDir, "types.ts");
|
|
731
|
+
const endpointsPath = path5.join(this.context.config.endpointsPath);
|
|
732
|
+
const relativePath = path5.relative(path5.dirname(outputPath), endpointsPath).replace(/\\/g, "/");
|
|
714
733
|
return `// Auto-generated type definitions
|
|
715
734
|
// Do not edit this file manually
|
|
716
735
|
|
|
@@ -784,6 +803,10 @@ ${this.generateEndpointTypes()}
|
|
|
784
803
|
return types.join("\n");
|
|
785
804
|
}
|
|
786
805
|
};
|
|
806
|
+
|
|
807
|
+
// src/generators/client.ts
|
|
808
|
+
import fs5 from "fs/promises";
|
|
809
|
+
import path6 from "path";
|
|
787
810
|
var ClientGenerator = class extends BaseGenerator {
|
|
788
811
|
async generate() {
|
|
789
812
|
await this.generateClientFile();
|
|
@@ -969,20 +992,24 @@ export const serverClient = createAPIClient(apiConfig) as APIClientMethods;
|
|
|
969
992
|
return methods.join("\n");
|
|
970
993
|
}
|
|
971
994
|
};
|
|
995
|
+
|
|
996
|
+
// src/generators/query-keys.ts
|
|
997
|
+
import fs6 from "fs/promises";
|
|
998
|
+
import path7 from "path";
|
|
972
999
|
var QueryKeysGenerator = class extends BaseGenerator {
|
|
973
1000
|
async generate() {
|
|
974
1001
|
const content = this.generateContent();
|
|
975
|
-
const outputPath =
|
|
1002
|
+
const outputPath = path7.join(
|
|
976
1003
|
this.context.config.outputDir,
|
|
977
1004
|
"query-keys.ts"
|
|
978
1005
|
);
|
|
979
|
-
await
|
|
980
|
-
await
|
|
1006
|
+
await fs6.mkdir(path7.dirname(outputPath), { recursive: true });
|
|
1007
|
+
await fs6.writeFile(outputPath, content, "utf-8");
|
|
981
1008
|
}
|
|
982
1009
|
generateContent() {
|
|
983
|
-
const outputPath =
|
|
984
|
-
const endpointsPath =
|
|
985
|
-
const relativePath =
|
|
1010
|
+
const outputPath = path7.join(this.context.config.outputDir, "types.ts");
|
|
1011
|
+
const endpointsPath = path7.join(this.context.config.endpointsPath);
|
|
1012
|
+
const relativePath = path7.relative(path7.dirname(outputPath), endpointsPath).replace(/\\/g, "/");
|
|
986
1013
|
const content = `// Auto-generated query keys
|
|
987
1014
|
import { z } from 'zod';
|
|
988
1015
|
import { apiConfig } from '${relativePath}';
|
|
@@ -1032,20 +1059,24 @@ ${resourceKeys.join("\n")}
|
|
|
1032
1059
|
return keys.join("\n");
|
|
1033
1060
|
}
|
|
1034
1061
|
};
|
|
1062
|
+
|
|
1063
|
+
// src/generators/query-options.ts
|
|
1064
|
+
import fs7 from "fs/promises";
|
|
1065
|
+
import path8 from "path";
|
|
1035
1066
|
var QueryOptionsGenerator = class extends BaseGenerator {
|
|
1036
1067
|
async generate() {
|
|
1037
1068
|
const content = this.generateContent();
|
|
1038
|
-
const outputPath =
|
|
1069
|
+
const outputPath = path8.join(
|
|
1039
1070
|
this.context.config.outputDir,
|
|
1040
1071
|
"query-options.ts"
|
|
1041
1072
|
);
|
|
1042
|
-
await
|
|
1043
|
-
await
|
|
1073
|
+
await fs7.mkdir(path8.dirname(outputPath), { recursive: true });
|
|
1074
|
+
await fs7.writeFile(outputPath, content, "utf-8");
|
|
1044
1075
|
}
|
|
1045
1076
|
generateContent() {
|
|
1046
|
-
const outputPath =
|
|
1047
|
-
const endpointsPath =
|
|
1048
|
-
const relativePath =
|
|
1077
|
+
const outputPath = path8.join(this.context.config.outputDir, "types.ts");
|
|
1078
|
+
const endpointsPath = path8.join(this.context.config.endpointsPath);
|
|
1079
|
+
const relativePath = path8.relative(path8.dirname(outputPath), endpointsPath).replace(/\\/g, "/");
|
|
1049
1080
|
const content = `// Auto-generated query options
|
|
1050
1081
|
import { queryOptions } from '@tanstack/react-query';
|
|
1051
1082
|
import { apiClient } from './client';
|
|
@@ -1114,22 +1145,26 @@ ${resourceOptions.join("\n")}
|
|
|
1114
1145
|
}
|
|
1115
1146
|
generateQueryOptionsExports() {
|
|
1116
1147
|
const groups = this.groupEndpointsByResource();
|
|
1117
|
-
const exports
|
|
1148
|
+
const exports = [];
|
|
1118
1149
|
Object.keys(groups).forEach((resource) => {
|
|
1119
1150
|
const hasQueries = groups[resource].some(
|
|
1120
1151
|
({ endpoint }) => endpoint.method === "GET"
|
|
1121
1152
|
);
|
|
1122
|
-
if (hasQueries) exports
|
|
1153
|
+
if (hasQueries) exports.push(` ${resource}: ${resource}QueryOptions,`);
|
|
1123
1154
|
});
|
|
1124
|
-
return exports
|
|
1155
|
+
return exports.join("\n");
|
|
1125
1156
|
}
|
|
1126
1157
|
};
|
|
1158
|
+
|
|
1159
|
+
// src/generators/prefetch.ts
|
|
1160
|
+
import fs8 from "fs/promises";
|
|
1161
|
+
import path9 from "path";
|
|
1127
1162
|
var PrefetchGenerator = class extends BaseGenerator {
|
|
1128
1163
|
async generate() {
|
|
1129
1164
|
const content = this.generateContent();
|
|
1130
|
-
const outputPath =
|
|
1131
|
-
await
|
|
1132
|
-
await
|
|
1165
|
+
const outputPath = path9.join(this.context.config.outputDir, "prefetchs.ts");
|
|
1166
|
+
await fs8.mkdir(path9.dirname(outputPath), { recursive: true });
|
|
1167
|
+
await fs8.writeFile(outputPath, content, "utf-8");
|
|
1133
1168
|
}
|
|
1134
1169
|
generateContent() {
|
|
1135
1170
|
const content = `// Auto-generated prefetch utilities
|
|
@@ -1177,419 +1212,6 @@ ${this.generatePrefetchFunctions()}
|
|
|
1177
1212
|
};`;
|
|
1178
1213
|
}
|
|
1179
1214
|
};
|
|
1180
|
-
var SchemaGenerator = class extends BaseGenerator {
|
|
1181
|
-
async generate() {
|
|
1182
|
-
const content = this.generateContent();
|
|
1183
|
-
const outputPath = path6.join(this.context.config.outputDir, "schema.ts");
|
|
1184
|
-
await fs5.mkdir(path6.dirname(outputPath), { recursive: true });
|
|
1185
|
-
await fs5.writeFile(outputPath, content, "utf-8");
|
|
1186
|
-
}
|
|
1187
|
-
generateContent() {
|
|
1188
|
-
const content = `// Auto-generated schema definitions
|
|
1189
|
-
|
|
1190
|
-
import type { z } from 'zod';
|
|
1191
|
-
|
|
1192
|
-
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
1193
|
-
|
|
1194
|
-
export interface APIEndpoint {
|
|
1195
|
-
path: string;
|
|
1196
|
-
method: HTTPMethod;
|
|
1197
|
-
baseUrl?: string;
|
|
1198
|
-
params?: z.ZodType<any>;
|
|
1199
|
-
query?: z.ZodType<any>;
|
|
1200
|
-
body?: z.ZodType<any>;
|
|
1201
|
-
response: z.ZodType<any>;
|
|
1202
|
-
tags?: string[];
|
|
1203
|
-
description?: string;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
export interface APIConfig {
|
|
1207
|
-
baseUrl?: string;
|
|
1208
|
-
endpoints: Record<string, APIEndpoint>;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
export type EndpointConfig<
|
|
1212
|
-
TPath extends string = string,
|
|
1213
|
-
TMethod extends HTTPMethod = HTTPMethod,
|
|
1214
|
-
TParams = undefined,
|
|
1215
|
-
TQuery = undefined,
|
|
1216
|
-
TBody = undefined,
|
|
1217
|
-
TResponse = any,
|
|
1218
|
-
> = {
|
|
1219
|
-
path: TPath;
|
|
1220
|
-
method: TMethod;
|
|
1221
|
-
baseUrl?: string;
|
|
1222
|
-
params?: z.ZodType<TParams>;
|
|
1223
|
-
query?: z.ZodType<TQuery>;
|
|
1224
|
-
body?: z.ZodType<TBody>;
|
|
1225
|
-
response: z.ZodType<TResponse>;
|
|
1226
|
-
tags?: string[];
|
|
1227
|
-
description?: string;
|
|
1228
|
-
};
|
|
1229
|
-
|
|
1230
|
-
/**
|
|
1231
|
-
* Helper function to define API configuration with type safety
|
|
1232
|
-
*/
|
|
1233
|
-
export function defineConfig<T extends APIConfig>(config: T): T {
|
|
1234
|
-
return config;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
/**
|
|
1238
|
-
* Helper function to define a single endpoint with type inference
|
|
1239
|
-
*/
|
|
1240
|
-
export function defineEndpoint<
|
|
1241
|
-
TPath extends string,
|
|
1242
|
-
TMethod extends HTTPMethod,
|
|
1243
|
-
TParams = undefined,
|
|
1244
|
-
TQuery = undefined,
|
|
1245
|
-
TBody = undefined,
|
|
1246
|
-
TResponse = any,
|
|
1247
|
-
>(
|
|
1248
|
-
config: EndpointConfig<TPath, TMethod, TParams, TQuery, TBody, TResponse>,
|
|
1249
|
-
): EndpointConfig<TPath, TMethod, TParams, TQuery, TBody, TResponse> {
|
|
1250
|
-
return config;
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
/**
|
|
1254
|
-
* Helper to define multiple endpoints
|
|
1255
|
-
*/
|
|
1256
|
-
export function defineEndpoints<
|
|
1257
|
-
T extends Record<string, APIEndpoint>,
|
|
1258
|
-
>(endpoints: T): T {
|
|
1259
|
-
return endpoints;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
`;
|
|
1263
|
-
return content;
|
|
1264
|
-
}
|
|
1265
|
-
};
|
|
1266
|
-
var CoreGenerator = class extends BaseGenerator {
|
|
1267
|
-
async generate() {
|
|
1268
|
-
const content = this.generateContent();
|
|
1269
|
-
const outputPath = path6.join(this.context.config.outputDir, "core.ts");
|
|
1270
|
-
await fs5.mkdir(path6.dirname(outputPath), { recursive: true });
|
|
1271
|
-
await fs5.writeFile(outputPath, content, "utf-8");
|
|
1272
|
-
}
|
|
1273
|
-
generateContent() {
|
|
1274
|
-
const content = `// Auto-generated schema definitions
|
|
1275
|
-
|
|
1276
|
-
import ky, { HTTPError } from "ky";
|
|
1277
|
-
import type { APIConfig, APIEndpoint } from "../config/schema.js";
|
|
1278
|
-
|
|
1279
|
-
export interface AuthTokens {
|
|
1280
|
-
accessToken: string;
|
|
1281
|
-
refreshToken?: string;
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
export interface AuthCallbacks {
|
|
1285
|
-
getTokens: () => Promise<AuthTokens | null>;
|
|
1286
|
-
onAuthError?: () => void;
|
|
1287
|
-
onRefreshToken?: () => Promise<void>;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
export class APIError extends Error {
|
|
1291
|
-
constructor(
|
|
1292
|
-
message: string,
|
|
1293
|
-
public status: number,
|
|
1294
|
-
public response?: any,
|
|
1295
|
-
) {
|
|
1296
|
-
super(message);
|
|
1297
|
-
this.name = "APIError";
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
export class AuthError extends APIError {
|
|
1302
|
-
constructor(message: string = "Authentication failed") {
|
|
1303
|
-
super(message, 401);
|
|
1304
|
-
this.name = "AuthError";
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
export class APIClient {
|
|
1309
|
-
private client: typeof ky;
|
|
1310
|
-
private isRefreshing = false;
|
|
1311
|
-
private refreshPromise: Promise<void> | null = null;
|
|
1312
|
-
private hooks: any;
|
|
1313
|
-
|
|
1314
|
-
constructor(
|
|
1315
|
-
private config: APIConfig,
|
|
1316
|
-
private authCallbacks?: AuthCallbacks,
|
|
1317
|
-
) {
|
|
1318
|
-
this.hooks = {
|
|
1319
|
-
beforeRequest: [
|
|
1320
|
-
async (request: Request) => {
|
|
1321
|
-
const tokens = await this.authCallbacks?.getTokens();
|
|
1322
|
-
if (tokens?.accessToken) {
|
|
1323
|
-
request.headers.set(
|
|
1324
|
-
"Authorization",
|
|
1325
|
-
\`Bearer \${tokens.accessToken}\`,
|
|
1326
|
-
);
|
|
1327
|
-
}
|
|
1328
|
-
},
|
|
1329
|
-
],
|
|
1330
|
-
beforeRetry: [
|
|
1331
|
-
async ({ request, error, retryCount }: any) => {
|
|
1332
|
-
if (error instanceof HTTPError && error.response.status === 401) {
|
|
1333
|
-
if (retryCount === 1 && this.authCallbacks) {
|
|
1334
|
-
try {
|
|
1335
|
-
await this.refreshTokens();
|
|
1336
|
-
const tokens = await this.authCallbacks.getTokens();
|
|
1337
|
-
if (tokens?.accessToken) {
|
|
1338
|
-
request.headers.set(
|
|
1339
|
-
"Authorization",
|
|
1340
|
-
\`Bearer \${tokens.accessToken}\`,
|
|
1341
|
-
);
|
|
1342
|
-
}
|
|
1343
|
-
} catch (refreshError) {
|
|
1344
|
-
this.authCallbacks.onAuthError?.();
|
|
1345
|
-
throw new AuthError();
|
|
1346
|
-
}
|
|
1347
|
-
} else {
|
|
1348
|
-
this.authCallbacks?.onAuthError?.();
|
|
1349
|
-
throw new AuthError();
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
},
|
|
1353
|
-
],
|
|
1354
|
-
beforeError: [
|
|
1355
|
-
async (error: any) => {
|
|
1356
|
-
const { response } = error;
|
|
1357
|
-
if (response?.body) {
|
|
1358
|
-
try {
|
|
1359
|
-
const body = await response.json();
|
|
1360
|
-
error.message =
|
|
1361
|
-
(body as Error).message || \`HTTP \${response.status}\`;
|
|
1362
|
-
} catch {
|
|
1363
|
-
// Keep original message
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
return error;
|
|
1367
|
-
},
|
|
1368
|
-
],
|
|
1369
|
-
};
|
|
1370
|
-
|
|
1371
|
-
this.client = ky.create({
|
|
1372
|
-
prefixUrl: this.config.baseUrl,
|
|
1373
|
-
headers: {
|
|
1374
|
-
"Content-Type": "application/json",
|
|
1375
|
-
},
|
|
1376
|
-
retry: {
|
|
1377
|
-
limit: 2,
|
|
1378
|
-
methods: ["get", "post", "put", "delete", "patch"],
|
|
1379
|
-
statusCodes: [401],
|
|
1380
|
-
},
|
|
1381
|
-
hooks: this.hooks,
|
|
1382
|
-
});
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
private async refreshTokens(): Promise<void> {
|
|
1386
|
-
if (!this.authCallbacks) {
|
|
1387
|
-
throw new AuthError("No auth callbacks provided");
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
if (this.isRefreshing && this.refreshPromise) {
|
|
1391
|
-
return this.refreshPromise;
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
this.isRefreshing = true;
|
|
1395
|
-
|
|
1396
|
-
this.refreshPromise = (async () => {
|
|
1397
|
-
try {
|
|
1398
|
-
if (this.authCallbacks?.onRefreshToken) {
|
|
1399
|
-
await this.authCallbacks.onRefreshToken();
|
|
1400
|
-
} else {
|
|
1401
|
-
throw new AuthError("No refresh token handler provided");
|
|
1402
|
-
}
|
|
1403
|
-
} catch (error) {
|
|
1404
|
-
throw error;
|
|
1405
|
-
} finally {
|
|
1406
|
-
this.isRefreshing = false;
|
|
1407
|
-
this.refreshPromise = null;
|
|
1408
|
-
}
|
|
1409
|
-
})();
|
|
1410
|
-
|
|
1411
|
-
return this.refreshPromise;
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
private buildPath(path: string, params?: Record<string, any>): string {
|
|
1415
|
-
if (!params) return path;
|
|
1416
|
-
|
|
1417
|
-
let finalPath = path;
|
|
1418
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
1419
|
-
finalPath = finalPath.replace(
|
|
1420
|
-
\`:\${key}\`,
|
|
1421
|
-
encodeURIComponent(String(value)),
|
|
1422
|
-
);
|
|
1423
|
-
});
|
|
1424
|
-
|
|
1425
|
-
return finalPath;
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
private getEndpointBaseUrl(endpoint: APIEndpoint): string {
|
|
1429
|
-
return endpoint.baseUrl || this.config.baseUrl!;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
private getClientForEndpoint(endpoint: APIEndpoint): typeof ky {
|
|
1433
|
-
const endpointBaseUrl = this.getEndpointBaseUrl(endpoint);
|
|
1434
|
-
|
|
1435
|
-
if (endpointBaseUrl === this.config.baseUrl) {
|
|
1436
|
-
return this.client;
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
return ky.create({
|
|
1440
|
-
prefixUrl: endpointBaseUrl,
|
|
1441
|
-
headers: {
|
|
1442
|
-
"Content-Type": "application/json",
|
|
1443
|
-
},
|
|
1444
|
-
retry: {
|
|
1445
|
-
limit: 2,
|
|
1446
|
-
methods: ["get", "post", "put", "delete", "patch"],
|
|
1447
|
-
statusCodes: [401],
|
|
1448
|
-
},
|
|
1449
|
-
hooks: this.hooks,
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
async request<T>(
|
|
1454
|
-
endpoint: APIEndpoint,
|
|
1455
|
-
params?: Record<string, any>,
|
|
1456
|
-
query?: Record<string, any>,
|
|
1457
|
-
body?: any,
|
|
1458
|
-
): Promise<T> {
|
|
1459
|
-
try {
|
|
1460
|
-
const path = this.buildPath(endpoint.path, params);
|
|
1461
|
-
const client = this.getClientForEndpoint(endpoint);
|
|
1462
|
-
|
|
1463
|
-
const options: Record<string, any> = {
|
|
1464
|
-
method: endpoint.method,
|
|
1465
|
-
};
|
|
1466
|
-
|
|
1467
|
-
if (query && Object.keys(query).length > 0) {
|
|
1468
|
-
const searchParams = new URLSearchParams();
|
|
1469
|
-
Object.entries(query).forEach(([key, value]) => {
|
|
1470
|
-
if (value !== undefined && value !== null) {
|
|
1471
|
-
searchParams.append(key, String(value));
|
|
1472
|
-
}
|
|
1473
|
-
});
|
|
1474
|
-
if (searchParams.toString()) {
|
|
1475
|
-
options.searchParams = searchParams;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
if (body && endpoint.method !== "GET") {
|
|
1480
|
-
if (endpoint.body) {
|
|
1481
|
-
const validatedBody = endpoint.body.parse(body);
|
|
1482
|
-
options.json = validatedBody;
|
|
1483
|
-
} else {
|
|
1484
|
-
options.json = body;
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
const response = await client(path, options);
|
|
1489
|
-
const data = await response.json();
|
|
1490
|
-
|
|
1491
|
-
if (endpoint.response) {
|
|
1492
|
-
return endpoint.response.parse(data);
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
return data as T;
|
|
1496
|
-
} catch (error) {
|
|
1497
|
-
if (error instanceof HTTPError) {
|
|
1498
|
-
const errorData = await error.response.json().catch(() => ({}));
|
|
1499
|
-
throw new APIError(
|
|
1500
|
-
errorData.message || error.message,
|
|
1501
|
-
error.response.status,
|
|
1502
|
-
errorData,
|
|
1503
|
-
);
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
if (error instanceof AuthError) {
|
|
1507
|
-
throw error;
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
throw new APIError(
|
|
1511
|
-
error instanceof Error ? error.message : "Network error",
|
|
1512
|
-
0,
|
|
1513
|
-
);
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
updateAuthCallbacks(authCallbacks: AuthCallbacks) {
|
|
1518
|
-
this.authCallbacks = authCallbacks;
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
async refreshAuth(): Promise<void> {
|
|
1522
|
-
if (!this.authCallbacks) {
|
|
1523
|
-
throw new AuthError("No auth callbacks provided");
|
|
1524
|
-
}
|
|
1525
|
-
await this.refreshTokens();
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
generateMethods() {
|
|
1529
|
-
const methods: any = {};
|
|
1530
|
-
|
|
1531
|
-
Object.entries(this.config.endpoints).forEach(([name, endpoint]) => {
|
|
1532
|
-
if (endpoint.method === "GET") {
|
|
1533
|
-
if (endpoint.params && endpoint.query) {
|
|
1534
|
-
methods[name] = (params: any, query?: any): Promise<any> => {
|
|
1535
|
-
return this.request(endpoint, params, query);
|
|
1536
|
-
};
|
|
1537
|
-
} else if (endpoint.params) {
|
|
1538
|
-
methods[name] = (params: any): Promise<any> => {
|
|
1539
|
-
return this.request(endpoint, params);
|
|
1540
|
-
};
|
|
1541
|
-
} else if (endpoint.query) {
|
|
1542
|
-
methods[name] = (query?: any): Promise<any> => {
|
|
1543
|
-
return this.request(endpoint, undefined, query);
|
|
1544
|
-
};
|
|
1545
|
-
} else {
|
|
1546
|
-
methods[name] = (): Promise<any> => {
|
|
1547
|
-
return this.request(endpoint);
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
} else {
|
|
1551
|
-
if (endpoint.params && endpoint.body) {
|
|
1552
|
-
methods[name] = (params: any, body: any): Promise<any> => {
|
|
1553
|
-
return this.request(endpoint, params, undefined, body);
|
|
1554
|
-
};
|
|
1555
|
-
} else if (endpoint.params) {
|
|
1556
|
-
methods[name] = (params: any): Promise<any> => {
|
|
1557
|
-
return this.request(endpoint, params);
|
|
1558
|
-
};
|
|
1559
|
-
} else if (endpoint.body) {
|
|
1560
|
-
methods[name] = (body: any): Promise<any> => {
|
|
1561
|
-
return this.request(endpoint, undefined, undefined, body);
|
|
1562
|
-
};
|
|
1563
|
-
} else {
|
|
1564
|
-
methods[name] = (): Promise<any> => {
|
|
1565
|
-
return this.request(endpoint);
|
|
1566
|
-
};
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
});
|
|
1570
|
-
|
|
1571
|
-
return methods;
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
export function createAPIClient(
|
|
1576
|
-
config: APIConfig,
|
|
1577
|
-
authCallbacks?: AuthCallbacks,
|
|
1578
|
-
) {
|
|
1579
|
-
const instance = new APIClient(config, authCallbacks);
|
|
1580
|
-
const methods = instance.generateMethods();
|
|
1581
|
-
|
|
1582
|
-
return {
|
|
1583
|
-
...methods,
|
|
1584
|
-
refreshAuth: () => instance.refreshAuth(),
|
|
1585
|
-
updateAuthCallbacks: (newCallbacks: AuthCallbacks) =>
|
|
1586
|
-
instance.updateAuthCallbacks(newCallbacks),
|
|
1587
|
-
};
|
|
1588
|
-
}
|
|
1589
|
-
`;
|
|
1590
|
-
return content;
|
|
1591
|
-
}
|
|
1592
|
-
};
|
|
1593
1215
|
|
|
1594
1216
|
// src/generators/index.ts
|
|
1595
1217
|
var CodeGenerator = class {
|
|
@@ -1605,8 +1227,6 @@ var CodeGenerator = class {
|
|
|
1605
1227
|
getGenerators() {
|
|
1606
1228
|
const generators = [];
|
|
1607
1229
|
generators.push(new TypesGenerator(this.context));
|
|
1608
|
-
generators.push(new SchemaGenerator(this.context));
|
|
1609
|
-
generators.push(new CoreGenerator(this.context));
|
|
1610
1230
|
if (this.context.config.generateClient) {
|
|
1611
1231
|
generators.push(new ClientGenerator(this.context));
|
|
1612
1232
|
}
|
|
@@ -1627,6 +1247,9 @@ var CodeGenerator = class {
|
|
|
1627
1247
|
return generators;
|
|
1628
1248
|
}
|
|
1629
1249
|
};
|
|
1250
|
+
|
|
1251
|
+
// src/core/codegen.ts
|
|
1252
|
+
import { fileURLToPath } from "url";
|
|
1630
1253
|
var CodegenCore = class {
|
|
1631
1254
|
constructor(config) {
|
|
1632
1255
|
this.config = config;
|
|
@@ -1660,7 +1283,16 @@ var CodegenCore = class {
|
|
|
1660
1283
|
}
|
|
1661
1284
|
}
|
|
1662
1285
|
};
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1286
|
+
export {
|
|
1287
|
+
APIError,
|
|
1288
|
+
AuthError,
|
|
1289
|
+
CodeGenerator,
|
|
1290
|
+
CodegenCore,
|
|
1291
|
+
createAPIClient,
|
|
1292
|
+
defineConfig,
|
|
1293
|
+
defineEndpoint,
|
|
1294
|
+
defineEndpoints,
|
|
1295
|
+
loadConfig,
|
|
1296
|
+
validateConfig
|
|
1297
|
+
};
|
|
1666
1298
|
//# sourceMappingURL=index.js.map
|