@geekmidas/cli 0.6.2 → 0.7.0
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/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/index.cjs +2561 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2556 -29
- package/dist/index.mjs.map +1 -1
- package/dist/openapi-Mwy2_R4W.mjs +957 -0
- package/dist/openapi-Mwy2_R4W.mjs.map +1 -0
- package/dist/{openapi-react-query-_-B3s8v_.mjs → openapi-react-query-CcciaVu5.mjs} +1 -1
- package/dist/{openapi-react-query-_-B3s8v_.mjs.map → openapi-react-query-CcciaVu5.mjs.map} +1 -1
- package/dist/{openapi-react-query-Cp-w8_05.cjs → openapi-react-query-o5iMi8tz.cjs} +1 -1
- package/dist/{openapi-react-query-Cp-w8_05.cjs.map → openapi-react-query-o5iMi8tz.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi-tAIbJJU_.cjs +993 -0
- package/dist/openapi-tAIbJJU_.cjs.map +1 -0
- package/dist/openapi.cjs +1 -4
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -4
- package/dist/{types-Bi7VzDUZ.d.mts → types-B3TXoj7v.d.mts} +21 -53
- package/dist/{types-KmjzMgu8.d.cts → types-C0hwnSjm.d.cts} +21 -53
- package/package.json +5 -5
- package/src/build/types.ts +13 -0
- package/src/dev/index.ts +71 -8
- package/src/generators/EndpointGenerator.ts +46 -5
- package/src/generators/__tests__/EndpointGenerator.spec.ts +1 -1
- package/src/init/generators/config.ts +6 -1
- package/src/init/generators/package.ts +5 -1
- package/src/init/index.ts +9 -1
- package/src/init/templates/api.ts +31 -0
- package/src/init/templates/index.ts +1 -0
- package/src/init/templates/minimal.ts +83 -0
- package/src/types.ts +19 -0
- package/tsdown.config.ts +6 -0
- package/dist/CronGenerator-CCRYptuT.mjs +0 -55
- package/dist/CronGenerator-CCRYptuT.mjs.map +0 -1
- package/dist/CronGenerator-D4TWXQbh.cjs +0 -61
- package/dist/CronGenerator-D4TWXQbh.cjs.map +0 -1
- package/dist/CronGenerator-DWS3CCZt.d.cts +0 -14
- package/dist/CronGenerator-DZjdkEjI.d.mts +0 -14
- package/dist/EndpointGenerator-DGivkPLT.mjs +0 -335
- package/dist/EndpointGenerator-DGivkPLT.mjs.map +0 -1
- package/dist/EndpointGenerator-Dh7kMtuL.d.mts +0 -19
- package/dist/EndpointGenerator-npWEDoK2.cjs +0 -341
- package/dist/EndpointGenerator-npWEDoK2.cjs.map +0 -1
- package/dist/EndpointGenerator-zBsie_7s.d.cts +0 -19
- package/dist/FunctionGenerator-BmDHo27U.d.mts +0 -14
- package/dist/FunctionGenerator-CVk0h8tO.mjs +0 -54
- package/dist/FunctionGenerator-CVk0h8tO.mjs.map +0 -1
- package/dist/FunctionGenerator-DXjXBxUd.d.cts +0 -14
- package/dist/FunctionGenerator-DYTnyr4c.cjs +0 -60
- package/dist/FunctionGenerator-DYTnyr4c.cjs.map +0 -1
- package/dist/Generator-BGY-2dgI.d.cts +0 -27
- package/dist/Generator-CDt4pB3W.mjs +0 -41
- package/dist/Generator-CDt4pB3W.mjs.map +0 -1
- package/dist/Generator-CLVplqm2.cjs +0 -47
- package/dist/Generator-CLVplqm2.cjs.map +0 -1
- package/dist/Generator-yi9DH5TN.d.mts +0 -27
- package/dist/OpenApiTsGenerator-BVS4pOH7.mjs +0 -495
- package/dist/OpenApiTsGenerator-BVS4pOH7.mjs.map +0 -1
- package/dist/OpenApiTsGenerator-gPIIyppX.cjs +0 -501
- package/dist/OpenApiTsGenerator-gPIIyppX.cjs.map +0 -1
- package/dist/SubscriberGenerator-Bb-z3Kvx.d.cts +0 -15
- package/dist/SubscriberGenerator-CwsXqCpS.d.mts +0 -15
- package/dist/SubscriberGenerator-DABaJXML.mjs +0 -200
- package/dist/SubscriberGenerator-DABaJXML.mjs.map +0 -1
- package/dist/SubscriberGenerator-D_zpNGFr.cjs +0 -206
- package/dist/SubscriberGenerator-D_zpNGFr.cjs.map +0 -1
- package/dist/api-Bp5TIl1R.mjs +0 -167
- package/dist/api-Bp5TIl1R.mjs.map +0 -1
- package/dist/api-D4W9-tdZ.cjs +0 -173
- package/dist/api-D4W9-tdZ.cjs.map +0 -1
- package/dist/build/index.cjs +0 -15
- package/dist/build/index.d.cts +0 -7
- package/dist/build/index.d.mts +0 -7
- package/dist/build/index.mjs +0 -15
- package/dist/build/manifests.cjs +0 -4
- package/dist/build/manifests.d.cts +0 -13
- package/dist/build/manifests.d.mts +0 -13
- package/dist/build/manifests.mjs +0 -3
- package/dist/build/providerResolver.cjs +0 -5
- package/dist/build/providerResolver.d.cts +0 -23
- package/dist/build/providerResolver.d.mts +0 -23
- package/dist/build/providerResolver.mjs +0 -3
- package/dist/build/types.cjs +0 -0
- package/dist/build/types.d.cts +0 -3
- package/dist/build/types.d.mts +0 -3
- package/dist/build/types.mjs +0 -0
- package/dist/build-Cu6Mi0Lf.mjs +0 -87
- package/dist/build-Cu6Mi0Lf.mjs.map +0 -1
- package/dist/build-wmt8ZcmA.cjs +0 -93
- package/dist/build-wmt8ZcmA.cjs.map +0 -1
- package/dist/config-BP1IZynR.cjs +0 -168
- package/dist/config-BP1IZynR.cjs.map +0 -1
- package/dist/config-CIzRhm_D.d.mts +0 -11
- package/dist/config-CvehIYsb.d.cts +0 -11
- package/dist/config-UCK12Lrr.mjs +0 -162
- package/dist/config-UCK12Lrr.mjs.map +0 -1
- package/dist/dev/index.cjs +0 -17
- package/dist/dev/index.d.cts +0 -36
- package/dist/dev/index.d.mts +0 -36
- package/dist/dev/index.mjs +0 -13
- package/dist/dev-BBPWSllq.mjs +0 -348
- package/dist/dev-BBPWSllq.mjs.map +0 -1
- package/dist/dev-C2lCgE53.cjs +0 -378
- package/dist/dev-C2lCgE53.cjs.map +0 -1
- package/dist/docker-2-ipZDOJ.cjs +0 -119
- package/dist/docker-2-ipZDOJ.cjs.map +0 -1
- package/dist/docker-31GNwU3F.mjs +0 -113
- package/dist/docker-31GNwU3F.mjs.map +0 -1
- package/dist/env-CQ3hXAAW.d.mts +0 -11
- package/dist/env-CS0jvg7k.cjs +0 -144
- package/dist/env-CS0jvg7k.cjs.map +0 -1
- package/dist/env-D4YFgMqo.d.cts +0 -11
- package/dist/env-DEeVOvVu.mjs +0 -138
- package/dist/env-DEeVOvVu.mjs.map +0 -1
- package/dist/generators/CronGenerator.cjs +0 -4
- package/dist/generators/CronGenerator.d.cts +0 -5
- package/dist/generators/CronGenerator.d.mts +0 -5
- package/dist/generators/CronGenerator.mjs +0 -4
- package/dist/generators/EndpointGenerator.cjs +0 -4
- package/dist/generators/EndpointGenerator.d.cts +0 -5
- package/dist/generators/EndpointGenerator.d.mts +0 -5
- package/dist/generators/EndpointGenerator.mjs +0 -4
- package/dist/generators/FunctionGenerator.cjs +0 -4
- package/dist/generators/FunctionGenerator.d.cts +0 -5
- package/dist/generators/FunctionGenerator.d.mts +0 -5
- package/dist/generators/FunctionGenerator.mjs +0 -4
- package/dist/generators/Generator.cjs +0 -3
- package/dist/generators/Generator.d.cts +0 -4
- package/dist/generators/Generator.d.mts +0 -4
- package/dist/generators/Generator.mjs +0 -3
- package/dist/generators/OpenApiTsGenerator.cjs +0 -3
- package/dist/generators/OpenApiTsGenerator.d.cts +0 -44
- package/dist/generators/OpenApiTsGenerator.d.mts +0 -44
- package/dist/generators/OpenApiTsGenerator.mjs +0 -3
- package/dist/generators/SubscriberGenerator.cjs +0 -4
- package/dist/generators/SubscriberGenerator.d.cts +0 -5
- package/dist/generators/SubscriberGenerator.d.mts +0 -5
- package/dist/generators/SubscriberGenerator.mjs +0 -4
- package/dist/generators/index.cjs +0 -12
- package/dist/generators/index.d.cts +0 -8
- package/dist/generators/index.d.mts +0 -8
- package/dist/generators/index.mjs +0 -8
- package/dist/generators-3IemvCLk.cjs +0 -0
- package/dist/generators-FNpdfN6J.mjs +0 -0
- package/dist/index-DG6xNQMH.d.cts +0 -81
- package/dist/index-DZgrOOOW.d.mts +0 -81
- package/dist/init/generators/config.cjs +0 -3
- package/dist/init/generators/config.d.cts +0 -3
- package/dist/init/generators/config.d.mts +0 -3
- package/dist/init/generators/config.mjs +0 -3
- package/dist/init/generators/docker.cjs +0 -3
- package/dist/init/generators/docker.d.cts +0 -11
- package/dist/init/generators/docker.d.mts +0 -11
- package/dist/init/generators/docker.mjs +0 -3
- package/dist/init/generators/env.cjs +0 -3
- package/dist/init/generators/env.d.cts +0 -3
- package/dist/init/generators/env.d.mts +0 -3
- package/dist/init/generators/env.mjs +0 -3
- package/dist/init/generators/index.cjs +0 -14
- package/dist/init/generators/index.d.cts +0 -6
- package/dist/init/generators/index.d.mts +0 -6
- package/dist/init/generators/index.mjs +0 -11
- package/dist/init/generators/models.cjs +0 -3
- package/dist/init/generators/models.d.cts +0 -11
- package/dist/init/generators/models.d.mts +0 -11
- package/dist/init/generators/models.mjs +0 -3
- package/dist/init/generators/monorepo.cjs +0 -3
- package/dist/init/generators/monorepo.d.cts +0 -11
- package/dist/init/generators/monorepo.d.mts +0 -11
- package/dist/init/generators/monorepo.mjs +0 -3
- package/dist/init/generators/package.cjs +0 -8
- package/dist/init/generators/package.d.cts +0 -3
- package/dist/init/generators/package.d.mts +0 -3
- package/dist/init/generators/package.mjs +0 -8
- package/dist/init/generators/source.cjs +0 -3
- package/dist/init/generators/source.d.cts +0 -3
- package/dist/init/generators/source.d.mts +0 -3
- package/dist/init/generators/source.mjs +0 -3
- package/dist/init/index.cjs +0 -16
- package/dist/init/index.d.cts +0 -17
- package/dist/init/index.d.mts +0 -17
- package/dist/init/index.mjs +0 -16
- package/dist/init/templates/api.cjs +0 -3
- package/dist/init/templates/api.d.cts +0 -7
- package/dist/init/templates/api.d.mts +0 -7
- package/dist/init/templates/api.mjs +0 -3
- package/dist/init/templates/index.cjs +0 -12
- package/dist/init/templates/index.d.cts +0 -2
- package/dist/init/templates/index.d.mts +0 -2
- package/dist/init/templates/index.mjs +0 -7
- package/dist/init/templates/minimal.cjs +0 -3
- package/dist/init/templates/minimal.d.cts +0 -7
- package/dist/init/templates/minimal.d.mts +0 -7
- package/dist/init/templates/minimal.mjs +0 -3
- package/dist/init/templates/serverless.cjs +0 -3
- package/dist/init/templates/serverless.d.cts +0 -7
- package/dist/init/templates/serverless.d.mts +0 -7
- package/dist/init/templates/serverless.mjs +0 -3
- package/dist/init/templates/worker.cjs +0 -3
- package/dist/init/templates/worker.d.cts +0 -7
- package/dist/init/templates/worker.d.mts +0 -7
- package/dist/init/templates/worker.mjs +0 -3
- package/dist/init/utils.cjs +0 -7
- package/dist/init/utils.d.cts +0 -25
- package/dist/init/utils.d.mts +0 -25
- package/dist/init/utils.mjs +0 -3
- package/dist/init-BMA7xi8r.mjs +0 -161
- package/dist/init-BMA7xi8r.mjs.map +0 -1
- package/dist/init-D-7WEk-b.cjs +0 -167
- package/dist/init-D-7WEk-b.cjs.map +0 -1
- package/dist/manifests-BNKG6AXf.mjs +0 -68
- package/dist/manifests-BNKG6AXf.mjs.map +0 -1
- package/dist/manifests-D13Ej8AE.cjs +0 -80
- package/dist/manifests-D13Ej8AE.cjs.map +0 -1
- package/dist/minimal-BkyASH_C.mjs +0 -93
- package/dist/minimal-BkyASH_C.mjs.map +0 -1
- package/dist/minimal-CSFggzdH.cjs +0 -99
- package/dist/minimal-CSFggzdH.cjs.map +0 -1
- package/dist/models-BWlDfviw.mjs +0 -115
- package/dist/models-BWlDfviw.mjs.map +0 -1
- package/dist/models-BapGSoHC.cjs +0 -121
- package/dist/models-BapGSoHC.cjs.map +0 -1
- package/dist/monorepo-BBOWhkcd.mjs +0 -184
- package/dist/monorepo-BBOWhkcd.mjs.map +0 -1
- package/dist/monorepo-CFtxHeDh.cjs +0 -190
- package/dist/monorepo-CFtxHeDh.cjs.map +0 -1
- package/dist/openapi-DA9RkPJl.mjs +0 -74
- package/dist/openapi-DA9RkPJl.mjs.map +0 -1
- package/dist/openapi-DZH6RQHk.cjs +0 -98
- package/dist/openapi-DZH6RQHk.cjs.map +0 -1
- package/dist/package-6h-7QfJZ.d.cts +0 -11
- package/dist/package-BCe_KvGv.d.mts +0 -11
- package/dist/package-C3If80n1.mjs +0 -57
- package/dist/package-C3If80n1.mjs.map +0 -1
- package/dist/package-Dk8IMBOB.cjs +0 -62
- package/dist/package-Dk8IMBOB.cjs.map +0 -1
- package/dist/providerResolver-DEVKngbC.mjs +0 -96
- package/dist/providerResolver-DEVKngbC.mjs.map +0 -1
- package/dist/providerResolver-DOTbN9jo.cjs +0 -114
- package/dist/providerResolver-DOTbN9jo.cjs.map +0 -1
- package/dist/serverless-AGOS-l3G.cjs +0 -119
- package/dist/serverless-AGOS-l3G.cjs.map +0 -1
- package/dist/serverless-D5HjJByU.mjs +0 -113
- package/dist/serverless-D5HjJByU.mjs.map +0 -1
- package/dist/source-C1cyfHcF.cjs +0 -17
- package/dist/source-C1cyfHcF.cjs.map +0 -1
- package/dist/source-C3LiNUV9.d.mts +0 -11
- package/dist/source-CkQHBpwu.mjs +0 -11
- package/dist/source-CkQHBpwu.mjs.map +0 -1
- package/dist/source-Dtcjbokc.d.cts +0 -11
- package/dist/templates-C0EMmhwb.mjs +0 -88
- package/dist/templates-C0EMmhwb.mjs.map +0 -1
- package/dist/templates-CbgQ9dw0.cjs +0 -123
- package/dist/templates-CbgQ9dw0.cjs.map +0 -1
- package/dist/types-D2xYkOal.d.mts +0 -51
- package/dist/types-DA-r8HWZ.d.cts +0 -51
- package/dist/types.cjs +0 -0
- package/dist/types.d.cts +0 -2
- package/dist/types.d.mts +0 -2
- package/dist/types.mjs +0 -0
- package/dist/utils-CKEzCxc1.mjs +0 -69
- package/dist/utils-CKEzCxc1.mjs.map +0 -1
- package/dist/utils-DSdN2MTt.cjs +0 -99
- package/dist/utils-DSdN2MTt.cjs.map +0 -1
- package/dist/worker-CGhlqNH-.cjs +0 -156
- package/dist/worker-CGhlqNH-.cjs.map +0 -1
- package/dist/worker-CiP420As.mjs +0 -150
- package/dist/worker-CiP420As.mjs.map +0 -1
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
+
const require_config = require('./config-CFls09Ey.cjs');
|
|
3
|
+
const path = require_chunk.__toESM(require("path"));
|
|
4
|
+
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
5
|
+
const node_path = require_chunk.__toESM(require("node:path"));
|
|
6
|
+
const fast_glob = require_chunk.__toESM(require("fast-glob"));
|
|
7
|
+
const lodash_kebabcase = require_chunk.__toESM(require("lodash.kebabcase"));
|
|
8
|
+
const __geekmidas_constructs_endpoints = require_chunk.__toESM(require("@geekmidas/constructs/endpoints"));
|
|
9
|
+
const __geekmidas_schema_conversion = require_chunk.__toESM(require("@geekmidas/schema/conversion"));
|
|
10
|
+
|
|
11
|
+
//#region src/generators/Generator.ts
|
|
12
|
+
var ConstructGenerator = class {
|
|
13
|
+
static async build(context, outputDir, generator, patterns, options) {
|
|
14
|
+
const constructs = await generator.load(patterns);
|
|
15
|
+
return generator.build(context, constructs, outputDir, options);
|
|
16
|
+
}
|
|
17
|
+
async load(patterns, cwd = process.cwd()) {
|
|
18
|
+
const logger = console;
|
|
19
|
+
const globPatterns = Array.isArray(patterns) ? patterns : patterns ? [patterns] : [];
|
|
20
|
+
const files = fast_glob.default.stream(globPatterns, {
|
|
21
|
+
cwd,
|
|
22
|
+
absolute: true
|
|
23
|
+
});
|
|
24
|
+
const constructs = [];
|
|
25
|
+
for await (const f of files) try {
|
|
26
|
+
const file = f.toString();
|
|
27
|
+
const module$1 = await import(file);
|
|
28
|
+
for (const [key, construct] of Object.entries(module$1)) if (this.isConstruct(construct)) constructs.push({
|
|
29
|
+
key,
|
|
30
|
+
name: (0, lodash_kebabcase.default)(key),
|
|
31
|
+
construct,
|
|
32
|
+
path: {
|
|
33
|
+
absolute: file,
|
|
34
|
+
relative: (0, path.relative)(process.cwd(), file)
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.warn(`Failed to load ${f}:`, error.message);
|
|
39
|
+
throw new Error("Failed to load constructs. Please check the logs for details.");
|
|
40
|
+
}
|
|
41
|
+
return constructs;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/generators/EndpointGenerator.ts
|
|
47
|
+
var EndpointGenerator = class extends ConstructGenerator {
|
|
48
|
+
isConstruct(value) {
|
|
49
|
+
return __geekmidas_constructs_endpoints.Endpoint.isEndpoint(value);
|
|
50
|
+
}
|
|
51
|
+
async build(context, constructs, outputDir, options) {
|
|
52
|
+
const provider = options?.provider || "aws-apigatewayv2";
|
|
53
|
+
const enableOpenApi = options?.enableOpenApi || false;
|
|
54
|
+
const logger = console;
|
|
55
|
+
const routes = [];
|
|
56
|
+
if (constructs.length === 0) return routes;
|
|
57
|
+
if (provider === "server") {
|
|
58
|
+
await this.generateEndpointsFile(outputDir, constructs, context);
|
|
59
|
+
const appFile = await this.generateAppFile(outputDir, context);
|
|
60
|
+
routes.push({
|
|
61
|
+
path: "*",
|
|
62
|
+
method: "ALL",
|
|
63
|
+
handler: (0, node_path.relative)(process.cwd(), appFile),
|
|
64
|
+
authorizer: "none"
|
|
65
|
+
});
|
|
66
|
+
logger.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
|
|
67
|
+
} else if (provider === "aws-lambda") {
|
|
68
|
+
const routesDir = (0, node_path.join)(outputDir, "routes");
|
|
69
|
+
await (0, node_fs_promises.mkdir)(routesDir, { recursive: true });
|
|
70
|
+
for (const { key, construct, path: path$1 } of constructs) {
|
|
71
|
+
const handlerFile = await this.generateHandlerFile(routesDir, path$1.relative, key, "aws-apigatewayv2", construct, context);
|
|
72
|
+
const routeInfo = {
|
|
73
|
+
path: construct._path,
|
|
74
|
+
method: construct.method,
|
|
75
|
+
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
76
|
+
timeout: construct.timeout,
|
|
77
|
+
memorySize: construct.memorySize,
|
|
78
|
+
environment: await construct.getEnvironment(),
|
|
79
|
+
authorizer: construct.authorizer?.name ?? "none"
|
|
80
|
+
};
|
|
81
|
+
routes.push(routeInfo);
|
|
82
|
+
logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
83
|
+
}
|
|
84
|
+
} else for (const { key, construct, path: path$1 } of constructs) {
|
|
85
|
+
const handlerFile = await this.generateHandlerFile(outputDir, path$1.relative, key, provider, construct, context);
|
|
86
|
+
const routeInfo = {
|
|
87
|
+
path: construct._path,
|
|
88
|
+
method: construct.method,
|
|
89
|
+
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
90
|
+
timeout: construct.timeout,
|
|
91
|
+
memorySize: construct.memorySize,
|
|
92
|
+
environment: await construct.getEnvironment(),
|
|
93
|
+
authorizer: construct.authorizer?.name ?? "none"
|
|
94
|
+
};
|
|
95
|
+
routes.push(routeInfo);
|
|
96
|
+
logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
97
|
+
}
|
|
98
|
+
return routes;
|
|
99
|
+
}
|
|
100
|
+
async generateHandlerFile(outputDir, sourceFile, exportName, provider, _endpoint, context) {
|
|
101
|
+
const handlerFileName = `${exportName}.ts`;
|
|
102
|
+
const handlerPath = (0, node_path.join)(outputDir, handlerFileName);
|
|
103
|
+
const relativePath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile);
|
|
104
|
+
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
105
|
+
const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), context.envParserPath);
|
|
106
|
+
let content;
|
|
107
|
+
switch (provider) {
|
|
108
|
+
case "aws-apigatewayv1":
|
|
109
|
+
content = this.generateAWSApiGatewayV1Handler(importPath, exportName, relativeEnvParserPath, context.envParserImportPattern);
|
|
110
|
+
break;
|
|
111
|
+
case "aws-apigatewayv2":
|
|
112
|
+
content = this.generateAWSApiGatewayV2Handler(importPath, exportName, relativeEnvParserPath, context.envParserImportPattern);
|
|
113
|
+
break;
|
|
114
|
+
case "server":
|
|
115
|
+
content = this.generateServerHandler(importPath, exportName);
|
|
116
|
+
break;
|
|
117
|
+
default: throw new Error(`Unsupported provider: ${provider}`);
|
|
118
|
+
}
|
|
119
|
+
await (0, node_fs_promises.writeFile)(handlerPath, content);
|
|
120
|
+
return handlerPath;
|
|
121
|
+
}
|
|
122
|
+
async generateEndpointsFile(outputDir, endpoints, _context) {
|
|
123
|
+
const endpointsFileName = "endpoints.ts";
|
|
124
|
+
const endpointsPath = (0, node_path.join)(outputDir, endpointsFileName);
|
|
125
|
+
const importsByFile = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const { path: path$1, key } of endpoints) {
|
|
127
|
+
const relativePath = (0, node_path.relative)((0, node_path.dirname)(endpointsPath), path$1.relative);
|
|
128
|
+
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
129
|
+
if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
|
|
130
|
+
importsByFile.get(importPath).push(key);
|
|
131
|
+
}
|
|
132
|
+
const imports = Array.from(importsByFile.entries()).map(([importPath, exports$1]) => `import { ${exports$1.join(", ")} } from '${importPath}';`).join("\n");
|
|
133
|
+
const allExportNames = endpoints.map(({ key }) => key);
|
|
134
|
+
const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
|
|
135
|
+
import type { Logger } from '@geekmidas/logger';
|
|
136
|
+
import { HonoEndpoint } from '@geekmidas/constructs/hono';
|
|
137
|
+
import { Endpoint } from '@geekmidas/constructs/endpoints';
|
|
138
|
+
import { ServiceDiscovery } from '@geekmidas/services';
|
|
139
|
+
import type { Hono } from 'hono';
|
|
140
|
+
${imports}
|
|
141
|
+
|
|
142
|
+
const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any, any, any>[] = [
|
|
143
|
+
${allExportNames.join(",\n ")}
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
export async function setupEndpoints(
|
|
147
|
+
app: Hono,
|
|
148
|
+
envParser: EnvironmentParser<any>,
|
|
149
|
+
logger: Logger,
|
|
150
|
+
enableOpenApi: boolean = true,
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
const serviceDiscovery = ServiceDiscovery.getInstance(
|
|
153
|
+
logger,
|
|
154
|
+
envParser
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Configure OpenAPI options based on enableOpenApi flag
|
|
158
|
+
const openApiOptions: any = enableOpenApi ? {
|
|
159
|
+
docsPath: '/__docs',
|
|
160
|
+
openApiOptions: {
|
|
161
|
+
title: 'API Documentation',
|
|
162
|
+
version: '1.0.0',
|
|
163
|
+
description: 'Generated API documentation'
|
|
164
|
+
}
|
|
165
|
+
} : { docsPath: false };
|
|
166
|
+
|
|
167
|
+
HonoEndpoint.addRoutes(endpoints, serviceDiscovery, app, openApiOptions);
|
|
168
|
+
|
|
169
|
+
// Add Swagger UI if OpenAPI is enabled
|
|
170
|
+
if (enableOpenApi) {
|
|
171
|
+
try {
|
|
172
|
+
const { swaggerUI } = await import('@hono/swagger-ui');
|
|
173
|
+
app.get('/__docs/ui', swaggerUI({ url: '/__docs' }));
|
|
174
|
+
} catch {
|
|
175
|
+
// @hono/swagger-ui not installed, skip Swagger UI
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
await (0, node_fs_promises.writeFile)(endpointsPath, content);
|
|
181
|
+
return endpointsPath;
|
|
182
|
+
}
|
|
183
|
+
async generateAppFile(outputDir, context) {
|
|
184
|
+
const appFileName = "app.ts";
|
|
185
|
+
const appPath = (0, node_path.join)(outputDir, appFileName);
|
|
186
|
+
const relativeLoggerPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.loggerPath);
|
|
187
|
+
const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.envParserPath);
|
|
188
|
+
const telescopeEnabled = context.telescope?.enabled;
|
|
189
|
+
const telescopeWebSocketEnabled = context.telescope?.websocket;
|
|
190
|
+
const usesExternalTelescope = !!context.telescope?.telescopePath;
|
|
191
|
+
const studioEnabled = context.studio?.enabled;
|
|
192
|
+
const usesExternalStudio = !!context.studio?.studioPath;
|
|
193
|
+
let telescopeImports = "";
|
|
194
|
+
if (telescopeEnabled) if (usesExternalTelescope) {
|
|
195
|
+
const relativeTelescopePath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.telescope.telescopePath);
|
|
196
|
+
telescopeImports = `import ${context.telescope.telescopeImportPattern} from '${relativeTelescopePath}';
|
|
197
|
+
import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
|
|
198
|
+
} else telescopeImports = `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
|
|
199
|
+
import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
|
|
200
|
+
let studioImports = "";
|
|
201
|
+
if (studioEnabled) if (usesExternalStudio) {
|
|
202
|
+
const relativeStudioPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.studio.studioPath);
|
|
203
|
+
studioImports = `import ${context.studio.studioImportPattern} from '${relativeStudioPath}';
|
|
204
|
+
import { createStudioApp } from '@geekmidas/studio/server/hono';`;
|
|
205
|
+
} else studioImports = `// Studio requires a configured instance - use studio config path
|
|
206
|
+
// import { createStudioApp } from '@geekmidas/studio/server/hono';`;
|
|
207
|
+
const telescopeWebSocketSetupCode = telescopeWebSocketEnabled ? `
|
|
208
|
+
// Setup WebSocket for real-time telescope updates
|
|
209
|
+
try {
|
|
210
|
+
const { createNodeWebSocket } = await import('@hono/node-ws');
|
|
211
|
+
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: honoApp });
|
|
212
|
+
// Add WebSocket route directly to main app (sub-app routes don't support WS upgrade)
|
|
213
|
+
honoApp.get('${context.telescope.path}/ws', upgradeWebSocket(() => ({
|
|
214
|
+
onOpen: (_event: Event, ws: any) => {
|
|
215
|
+
telescope.addWsClient(ws);
|
|
216
|
+
},
|
|
217
|
+
onClose: (_event: Event, ws: any) => {
|
|
218
|
+
telescope.removeWsClient(ws);
|
|
219
|
+
},
|
|
220
|
+
onMessage: (event: MessageEvent, ws: any) => {
|
|
221
|
+
try {
|
|
222
|
+
const data = JSON.parse(event.data);
|
|
223
|
+
if (data.type === 'ping') {
|
|
224
|
+
ws.send(JSON.stringify({ type: 'pong' }));
|
|
225
|
+
}
|
|
226
|
+
} catch {
|
|
227
|
+
// Ignore invalid messages
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
})));
|
|
231
|
+
// Store injectWebSocket for server entry to call after serve()
|
|
232
|
+
(honoApp as any).__injectWebSocket = injectWebSocket;
|
|
233
|
+
logger.info('Telescope WebSocket enabled');
|
|
234
|
+
} catch (e) {
|
|
235
|
+
logger.warn({ error: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
|
|
236
|
+
}
|
|
237
|
+
` : "";
|
|
238
|
+
let telescopeSetup = "";
|
|
239
|
+
if (telescopeEnabled) if (usesExternalTelescope) telescopeSetup = `
|
|
240
|
+
${telescopeWebSocketSetupCode}
|
|
241
|
+
// Add telescope middleware (before endpoints to capture all requests)
|
|
242
|
+
honoApp.use('*', createMiddleware(telescope));
|
|
243
|
+
|
|
244
|
+
// Mount telescope UI
|
|
245
|
+
const telescopeUI = createUI(telescope);
|
|
246
|
+
honoApp.route('${context.telescope.path}', telescopeUI);
|
|
247
|
+
`;
|
|
248
|
+
else telescopeSetup = `
|
|
249
|
+
// Setup Telescope for debugging/monitoring
|
|
250
|
+
const telescopeStorage = new InMemoryStorage({ maxEntries: ${context.telescope.maxEntries} });
|
|
251
|
+
const telescope = new Telescope({
|
|
252
|
+
enabled: true,
|
|
253
|
+
path: '${context.telescope.path}',
|
|
254
|
+
ignorePatterns: ${JSON.stringify(context.telescope.ignore)},
|
|
255
|
+
recordBody: ${context.telescope.recordBody},
|
|
256
|
+
storage: telescopeStorage,
|
|
257
|
+
});
|
|
258
|
+
${telescopeWebSocketSetupCode}
|
|
259
|
+
// Add telescope middleware (before endpoints to capture all requests)
|
|
260
|
+
honoApp.use('*', createMiddleware(telescope));
|
|
261
|
+
|
|
262
|
+
// Mount telescope UI
|
|
263
|
+
const telescopeUI = createUI(telescope);
|
|
264
|
+
honoApp.route('${context.telescope.path}', telescopeUI);
|
|
265
|
+
`;
|
|
266
|
+
let studioSetup = "";
|
|
267
|
+
if (studioEnabled && usesExternalStudio) studioSetup = `
|
|
268
|
+
// Mount Studio data browser UI
|
|
269
|
+
const studioApp = createStudioApp(studio);
|
|
270
|
+
honoApp.route('${context.studio.path}', studioApp);
|
|
271
|
+
`;
|
|
272
|
+
const content = `/**
|
|
273
|
+
* Generated server application
|
|
274
|
+
*
|
|
275
|
+
* ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY
|
|
276
|
+
* The subscriber polling mechanism is not production-ready.
|
|
277
|
+
* For production, use AWS Lambda with SQS/SNS event sources.
|
|
278
|
+
*/
|
|
279
|
+
import { Hono } from 'hono';
|
|
280
|
+
import type { Hono as HonoType } from 'hono';
|
|
281
|
+
import { setupEndpoints } from './endpoints.js';
|
|
282
|
+
import { setupSubscribers } from './subscribers.js';
|
|
283
|
+
import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
|
|
284
|
+
import ${context.loggerImportPattern} from '${relativeLoggerPath}';
|
|
285
|
+
${telescopeImports}
|
|
286
|
+
${studioImports}
|
|
287
|
+
|
|
288
|
+
export interface ServerApp {
|
|
289
|
+
app: HonoType;
|
|
290
|
+
start: (options?: {
|
|
291
|
+
port?: number;
|
|
292
|
+
serve: (app: HonoType, port: number) => void | Promise<void>;
|
|
293
|
+
}) => Promise<void>;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Create and configure the Hono application
|
|
298
|
+
*
|
|
299
|
+
* @param app - Optional Hono app instance to configure (creates new one if not provided)
|
|
300
|
+
* @param enableOpenApi - Enable OpenAPI documentation (default: true)
|
|
301
|
+
* @returns Server app with configured Hono app and start function
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* // With Bun
|
|
305
|
+
* import { createApp } from './.gkm/server/app.js';
|
|
306
|
+
*
|
|
307
|
+
* const { app, start } = await createApp();
|
|
308
|
+
*
|
|
309
|
+
* await start({
|
|
310
|
+
* port: 3000,
|
|
311
|
+
* serve: (app, port) => {
|
|
312
|
+
* Bun.serve({ port, fetch: app.fetch });
|
|
313
|
+
* }
|
|
314
|
+
* });
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* // With Node.js (using @hono/node-server)
|
|
318
|
+
* import { serve } from '@hono/node-server';
|
|
319
|
+
* import { createApp } from './.gkm/server/app.js';
|
|
320
|
+
*
|
|
321
|
+
* const { app, start } = await createApp();
|
|
322
|
+
*
|
|
323
|
+
* await start({
|
|
324
|
+
* port: 3000,
|
|
325
|
+
* serve: (app, port) => {
|
|
326
|
+
* serve({ fetch: app.fetch, port });
|
|
327
|
+
* }
|
|
328
|
+
* });
|
|
329
|
+
*/
|
|
330
|
+
export async function createApp(app?: HonoType, enableOpenApi: boolean = true): Promise<ServerApp> {
|
|
331
|
+
const honoApp = app || new Hono();
|
|
332
|
+
${telescopeSetup}${studioSetup}
|
|
333
|
+
// Setup HTTP endpoints
|
|
334
|
+
await setupEndpoints(honoApp, envParser, logger, enableOpenApi);
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
app: honoApp,
|
|
338
|
+
async start(options) {
|
|
339
|
+
if (!options?.serve) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
'serve function is required. Pass a serve function for your runtime:\\n' +
|
|
342
|
+
' - Bun: (app, port) => Bun.serve({ port, fetch: app.fetch })\\n' +
|
|
343
|
+
' - Node: (app, port) => serve({ fetch: app.fetch, port })'
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const port = options.port ?? 3000;
|
|
348
|
+
|
|
349
|
+
// Start subscribers in background (non-blocking, local development only)
|
|
350
|
+
await setupSubscribers(envParser, logger).catch((error) => {
|
|
351
|
+
logger.error({ error }, 'Failed to start subscribers');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
logger.info({ port }, 'Starting server');
|
|
355
|
+
|
|
356
|
+
// Start HTTP server using provided serve function
|
|
357
|
+
await options.serve(honoApp, port);
|
|
358
|
+
|
|
359
|
+
logger.info({ port }, 'Server started');
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Default export for convenience
|
|
365
|
+
export default createApp;
|
|
366
|
+
`;
|
|
367
|
+
await (0, node_fs_promises.writeFile)(appPath, content);
|
|
368
|
+
return appPath;
|
|
369
|
+
}
|
|
370
|
+
generateAWSApiGatewayV1Handler(importPath, exportName, envParserPath, envParserImportPattern) {
|
|
371
|
+
return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
|
|
372
|
+
import { ${exportName} } from '${importPath}';
|
|
373
|
+
import ${envParserImportPattern} from '${envParserPath}';
|
|
374
|
+
|
|
375
|
+
const adapter = new AmazonApiGatewayV1Endpoint(envParser, ${exportName});
|
|
376
|
+
|
|
377
|
+
export const handler = adapter.handler;
|
|
378
|
+
`;
|
|
379
|
+
}
|
|
380
|
+
generateAWSApiGatewayV2Handler(importPath, exportName, envParserPath, envParserImportPattern) {
|
|
381
|
+
return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
|
|
382
|
+
import { ${exportName} } from '${importPath}';
|
|
383
|
+
import ${envParserImportPattern} from '${envParserPath}';
|
|
384
|
+
|
|
385
|
+
const adapter = new AmazonApiGatewayV2Endpoint(envParser, ${exportName});
|
|
386
|
+
|
|
387
|
+
export const handler = adapter.handler;
|
|
388
|
+
`;
|
|
389
|
+
}
|
|
390
|
+
generateServerHandler(importPath, exportName) {
|
|
391
|
+
return `import { ${exportName} } from '${importPath}';
|
|
392
|
+
|
|
393
|
+
// Server handler - implement based on your server framework
|
|
394
|
+
export const handler = ${exportName};
|
|
395
|
+
`;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/generators/OpenApiTsGenerator.ts
|
|
401
|
+
/**
|
|
402
|
+
* Generates TypeScript OpenAPI module from endpoints.
|
|
403
|
+
* Outputs:
|
|
404
|
+
* - securitySchemes: typed security scheme definitions
|
|
405
|
+
* - endpointAuth: runtime map of endpoints to auth requirements
|
|
406
|
+
* - paths: TypeScript interface for type-safe fetcher
|
|
407
|
+
* - schema interfaces: reusable TypeScript types from Zod/Valibot schemas
|
|
408
|
+
*/
|
|
409
|
+
var OpenApiTsGenerator = class {
|
|
410
|
+
async generate(endpoints, options = {}) {
|
|
411
|
+
const { title = "API", version = "1.0.0", description } = options;
|
|
412
|
+
const endpointInfos = await this.extractEndpointInfos(endpoints);
|
|
413
|
+
const securitySchemes = this.collectSecuritySchemes(endpointInfos);
|
|
414
|
+
const endpointAuth = this.buildEndpointAuthMap(endpointInfos);
|
|
415
|
+
const schemaInterfaces = await this.generateSchemaInterfaces(endpointInfos);
|
|
416
|
+
const pathsInterface = await this.generatePathsInterface(endpointInfos);
|
|
417
|
+
return this.buildModule({
|
|
418
|
+
title,
|
|
419
|
+
version,
|
|
420
|
+
description,
|
|
421
|
+
securitySchemes,
|
|
422
|
+
endpointAuth,
|
|
423
|
+
schemaInterfaces,
|
|
424
|
+
pathsInterface
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
async extractEndpointInfos(endpoints) {
|
|
428
|
+
return endpoints.map((ep) => {
|
|
429
|
+
const route = ep.route.replace(/:(\w+)/g, "{$1}");
|
|
430
|
+
const method = ep.method.toUpperCase();
|
|
431
|
+
const securityScheme = ep.authorizer?.securityScheme;
|
|
432
|
+
return {
|
|
433
|
+
endpoint: `${method} ${route}`,
|
|
434
|
+
route,
|
|
435
|
+
method,
|
|
436
|
+
authorizerName: ep.authorizer?.name ?? null,
|
|
437
|
+
authorizerType: ep.authorizer?.type ?? null,
|
|
438
|
+
securityScheme: securityScheme ?? null,
|
|
439
|
+
input: ep.input,
|
|
440
|
+
output: ep.outputSchema,
|
|
441
|
+
description: ep.description,
|
|
442
|
+
tags: ep.tags,
|
|
443
|
+
operationId: ep.operationId
|
|
444
|
+
};
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
collectSecuritySchemes(endpointInfos) {
|
|
448
|
+
const schemes = /* @__PURE__ */ new Map();
|
|
449
|
+
for (const info of endpointInfos) if (info.authorizerName && !schemes.has(info.authorizerName)) {
|
|
450
|
+
const scheme = info.securityScheme ?? (info.authorizerType ? this.mapAuthorizerToSecurityScheme(info.authorizerType, info.authorizerName) : null);
|
|
451
|
+
if (scheme) schemes.set(info.authorizerName, {
|
|
452
|
+
name: info.authorizerName,
|
|
453
|
+
type: scheme.type,
|
|
454
|
+
scheme
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
return Array.from(schemes.values());
|
|
458
|
+
}
|
|
459
|
+
mapAuthorizerToSecurityScheme(type, _name) {
|
|
460
|
+
switch (type.toLowerCase()) {
|
|
461
|
+
case "jwt":
|
|
462
|
+
case "bearer": return {
|
|
463
|
+
type: "http",
|
|
464
|
+
scheme: "bearer",
|
|
465
|
+
bearerFormat: "JWT"
|
|
466
|
+
};
|
|
467
|
+
case "iam":
|
|
468
|
+
case "aws-sigv4":
|
|
469
|
+
case "sigv4": return {
|
|
470
|
+
type: "apiKey",
|
|
471
|
+
in: "header",
|
|
472
|
+
name: "Authorization",
|
|
473
|
+
"x-amazon-apigateway-authtype": "awsSigv4"
|
|
474
|
+
};
|
|
475
|
+
case "apikey":
|
|
476
|
+
case "api-key": return {
|
|
477
|
+
type: "apiKey",
|
|
478
|
+
in: "header",
|
|
479
|
+
name: "X-API-Key"
|
|
480
|
+
};
|
|
481
|
+
case "oauth2": return {
|
|
482
|
+
type: "oauth2",
|
|
483
|
+
flows: {}
|
|
484
|
+
};
|
|
485
|
+
case "oidc":
|
|
486
|
+
case "openidconnect": return {
|
|
487
|
+
type: "openIdConnect",
|
|
488
|
+
openIdConnectUrl: ""
|
|
489
|
+
};
|
|
490
|
+
default: return {
|
|
491
|
+
type: "http",
|
|
492
|
+
scheme: "bearer"
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
buildEndpointAuthMap(endpointInfos) {
|
|
497
|
+
const authMap = {};
|
|
498
|
+
for (const info of endpointInfos) authMap[info.endpoint] = info.authorizerName;
|
|
499
|
+
return authMap;
|
|
500
|
+
}
|
|
501
|
+
async generateSchemaInterfaces(endpointInfos) {
|
|
502
|
+
const interfaces = [];
|
|
503
|
+
const generatedNames = /* @__PURE__ */ new Set();
|
|
504
|
+
const collectedDefs = /* @__PURE__ */ new Map();
|
|
505
|
+
for (const info of endpointInfos) {
|
|
506
|
+
const baseName = this.getSchemaBaseName(info);
|
|
507
|
+
if (info.input?.body) {
|
|
508
|
+
const name = await this.getSchemaName(info.input.body, `${baseName}Input`);
|
|
509
|
+
if (!generatedNames.has(name)) {
|
|
510
|
+
const schema = await this.schemaToInterfaceWithDefs(info.input.body, name, collectedDefs);
|
|
511
|
+
if (schema) {
|
|
512
|
+
interfaces.push(schema);
|
|
513
|
+
generatedNames.add(name);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (info.input?.params) {
|
|
518
|
+
const name = await this.getSchemaName(info.input.params, `${baseName}Params`);
|
|
519
|
+
if (!generatedNames.has(name)) {
|
|
520
|
+
const schema = await this.schemaToInterfaceWithDefs(info.input.params, name, collectedDefs);
|
|
521
|
+
if (schema) {
|
|
522
|
+
interfaces.push(schema);
|
|
523
|
+
generatedNames.add(name);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (info.input?.query) {
|
|
528
|
+
const name = await this.getSchemaName(info.input.query, `${baseName}Query`);
|
|
529
|
+
if (!generatedNames.has(name)) {
|
|
530
|
+
const schema = await this.schemaToInterfaceWithDefs(info.input.query, name, collectedDefs);
|
|
531
|
+
if (schema) {
|
|
532
|
+
interfaces.push(schema);
|
|
533
|
+
generatedNames.add(name);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (info.output) {
|
|
538
|
+
const name = await this.getSchemaName(info.output, `${baseName}Output`);
|
|
539
|
+
if (!generatedNames.has(name)) {
|
|
540
|
+
const schema = await this.schemaToInterfaceWithDefs(info.output, name, collectedDefs);
|
|
541
|
+
if (schema) {
|
|
542
|
+
interfaces.push(schema);
|
|
543
|
+
generatedNames.add(name);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (const [defName, defSchema] of collectedDefs) if (!generatedNames.has(defName)) {
|
|
549
|
+
const interfaceStr = this.jsonSchemaToInterface(defSchema, defName);
|
|
550
|
+
interfaces.push(interfaceStr);
|
|
551
|
+
generatedNames.add(defName);
|
|
552
|
+
}
|
|
553
|
+
return interfaces.join("\n\n");
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Get the name for a schema, using metadata `id` if available,
|
|
557
|
+
* otherwise falling back to the provided default name.
|
|
558
|
+
*/
|
|
559
|
+
async getSchemaName(schema, defaultName) {
|
|
560
|
+
try {
|
|
561
|
+
const metadata = await (0, __geekmidas_schema_conversion.getSchemaMetadata)(schema);
|
|
562
|
+
if (metadata?.id) return this.pascalCase(metadata.id);
|
|
563
|
+
} catch {}
|
|
564
|
+
return defaultName;
|
|
565
|
+
}
|
|
566
|
+
getSchemaBaseName(info) {
|
|
567
|
+
if (info.operationId) return this.pascalCase(info.operationId);
|
|
568
|
+
const routeParts = info.route.replace(/[{}]/g, "").split("/").filter(Boolean).map((part) => this.pascalCase(part));
|
|
569
|
+
return `${this.pascalCase(info.method.toLowerCase())}${routeParts.join("")}`;
|
|
570
|
+
}
|
|
571
|
+
pascalCase(str) {
|
|
572
|
+
return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase());
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Convert schema to interface while collecting $defs for nested schemas
|
|
576
|
+
* with .meta({ id: 'X' }).
|
|
577
|
+
*/
|
|
578
|
+
async schemaToInterfaceWithDefs(schema, name, collectedDefs) {
|
|
579
|
+
try {
|
|
580
|
+
const vendor = schema["~standard"]?.vendor;
|
|
581
|
+
if (!vendor || !(vendor in __geekmidas_schema_conversion.StandardSchemaJsonSchema)) return null;
|
|
582
|
+
const toJsonSchema = __geekmidas_schema_conversion.StandardSchemaJsonSchema[vendor];
|
|
583
|
+
const jsonSchema = await toJsonSchema(schema);
|
|
584
|
+
if (!jsonSchema) return null;
|
|
585
|
+
if (jsonSchema.$defs && typeof jsonSchema.$defs === "object") {
|
|
586
|
+
for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) if (!collectedDefs.has(defName)) {
|
|
587
|
+
const { id,...schemaWithoutId } = defSchema;
|
|
588
|
+
collectedDefs.set(defName, schemaWithoutId);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const { $defs,...schemaWithoutDefs } = jsonSchema;
|
|
592
|
+
return this.jsonSchemaToInterface(schemaWithoutDefs, name);
|
|
593
|
+
} catch {
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
jsonSchemaToInterface(schema, name) {
|
|
598
|
+
if (schema.type !== "object" || !schema.properties) {
|
|
599
|
+
const typeStr = this.jsonSchemaTypeToTs(schema);
|
|
600
|
+
return `export type ${name} = ${typeStr};`;
|
|
601
|
+
}
|
|
602
|
+
const props = [];
|
|
603
|
+
const required = new Set(schema.required || []);
|
|
604
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
605
|
+
const isRequired = required.has(propName);
|
|
606
|
+
const typeStr = this.jsonSchemaTypeToTs(propSchema);
|
|
607
|
+
const optionalMark = isRequired ? "" : "?";
|
|
608
|
+
props.push(` ${propName}${optionalMark}: ${typeStr};`);
|
|
609
|
+
}
|
|
610
|
+
return `export interface ${name} {\n${props.join("\n")}\n}`;
|
|
611
|
+
}
|
|
612
|
+
jsonSchemaTypeToTs(schema) {
|
|
613
|
+
if (!schema) return "unknown";
|
|
614
|
+
if (schema.$ref) {
|
|
615
|
+
const refName = schema.$ref.split("/").pop() || "unknown";
|
|
616
|
+
return refName;
|
|
617
|
+
}
|
|
618
|
+
if (schema.anyOf) return schema.anyOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
|
|
619
|
+
if (schema.oneOf) return schema.oneOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
|
|
620
|
+
if (schema.allOf) return schema.allOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" & ");
|
|
621
|
+
switch (schema.type) {
|
|
622
|
+
case "string":
|
|
623
|
+
if (schema.enum) return schema.enum.map((e) => `'${e}'`).join(" | ");
|
|
624
|
+
return "string";
|
|
625
|
+
case "number":
|
|
626
|
+
case "integer": return "number";
|
|
627
|
+
case "boolean": return "boolean";
|
|
628
|
+
case "null": return "null";
|
|
629
|
+
case "array":
|
|
630
|
+
if (schema.items) return `Array<${this.jsonSchemaTypeToTs(schema.items)}>`;
|
|
631
|
+
return "Array<unknown>";
|
|
632
|
+
case "object":
|
|
633
|
+
if (schema.properties) {
|
|
634
|
+
const props = [];
|
|
635
|
+
const required = new Set(schema.required || []);
|
|
636
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
637
|
+
const isRequired = required.has(propName);
|
|
638
|
+
const typeStr = this.jsonSchemaTypeToTs(propSchema);
|
|
639
|
+
const optionalMark = isRequired ? "" : "?";
|
|
640
|
+
props.push(`${propName}${optionalMark}: ${typeStr}`);
|
|
641
|
+
}
|
|
642
|
+
return `{ ${props.join("; ")} }`;
|
|
643
|
+
}
|
|
644
|
+
if (schema.additionalProperties) {
|
|
645
|
+
const valueType = this.jsonSchemaTypeToTs(schema.additionalProperties);
|
|
646
|
+
return `Record<string, ${valueType}>`;
|
|
647
|
+
}
|
|
648
|
+
return "Record<string, unknown>";
|
|
649
|
+
default: return "unknown";
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async generatePathsInterface(endpointInfos) {
|
|
653
|
+
const pathGroups = /* @__PURE__ */ new Map();
|
|
654
|
+
for (const info of endpointInfos) {
|
|
655
|
+
const existing = pathGroups.get(info.route) || [];
|
|
656
|
+
existing.push(info);
|
|
657
|
+
pathGroups.set(info.route, existing);
|
|
658
|
+
}
|
|
659
|
+
const pathEntries = [];
|
|
660
|
+
for (const [route, infos] of pathGroups) {
|
|
661
|
+
const methodEntries = [];
|
|
662
|
+
for (const info of infos) {
|
|
663
|
+
const methodDef = await this.generateMethodDefinition(info);
|
|
664
|
+
methodEntries.push(` ${info.method.toLowerCase()}: ${methodDef};`);
|
|
665
|
+
}
|
|
666
|
+
const firstWithParams = infos.find((i) => i.input?.params);
|
|
667
|
+
let paramsEntry = "";
|
|
668
|
+
if (firstWithParams?.input?.params) {
|
|
669
|
+
const paramsName = await this.getSchemaName(firstWithParams.input.params, `${this.getSchemaBaseName(firstWithParams)}Params`);
|
|
670
|
+
paramsEntry = `\n parameters: {\n path: ${paramsName};\n };`;
|
|
671
|
+
}
|
|
672
|
+
pathEntries.push(` '${route}': {${paramsEntry}\n${methodEntries.join("\n")}\n };`);
|
|
673
|
+
}
|
|
674
|
+
return `export interface paths {\n${pathEntries.join("\n")}\n}`;
|
|
675
|
+
}
|
|
676
|
+
async generateMethodDefinition(info) {
|
|
677
|
+
const parts = [];
|
|
678
|
+
const baseName = this.getSchemaBaseName(info);
|
|
679
|
+
if (info.input?.body) {
|
|
680
|
+
const bodyName = await this.getSchemaName(info.input.body, `${baseName}Input`);
|
|
681
|
+
parts.push(`requestBody: {
|
|
682
|
+
content: {
|
|
683
|
+
'application/json': ${bodyName};
|
|
684
|
+
};
|
|
685
|
+
}`);
|
|
686
|
+
}
|
|
687
|
+
if (info.input?.query) {
|
|
688
|
+
const queryName = await this.getSchemaName(info.input.query, `${baseName}Query`);
|
|
689
|
+
parts.push(`parameters: {
|
|
690
|
+
query: ${queryName};
|
|
691
|
+
}`);
|
|
692
|
+
}
|
|
693
|
+
const outputName = info.output ? await this.getSchemaName(info.output, `${baseName}Output`) : "unknown";
|
|
694
|
+
parts.push(`responses: {
|
|
695
|
+
200: {
|
|
696
|
+
content: {
|
|
697
|
+
'application/json': ${outputName};
|
|
698
|
+
};
|
|
699
|
+
};
|
|
700
|
+
}`);
|
|
701
|
+
return `{\n ${parts.join(";\n ")};\n }`;
|
|
702
|
+
}
|
|
703
|
+
buildModule(params) {
|
|
704
|
+
const { title, version, description, securitySchemes, endpointAuth, schemaInterfaces, pathsInterface } = params;
|
|
705
|
+
const securitySchemesObj = securitySchemes.reduce((acc, s) => {
|
|
706
|
+
acc[s.name] = s.scheme;
|
|
707
|
+
return acc;
|
|
708
|
+
}, {});
|
|
709
|
+
const schemeNames = securitySchemes.map((s) => `'${s.name}'`).join(" | ");
|
|
710
|
+
const hasSecuritySchemes = schemeNames.length > 0;
|
|
711
|
+
const createApiSection = hasSecuritySchemes ? `
|
|
712
|
+
// ============================================================
|
|
713
|
+
// API Client Factory
|
|
714
|
+
// ============================================================
|
|
715
|
+
|
|
716
|
+
import {
|
|
717
|
+
createAuthAwareFetcher,
|
|
718
|
+
type AuthStrategy,
|
|
719
|
+
} from '@geekmidas/client/auth-fetcher';
|
|
720
|
+
import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
|
|
721
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Options for creating the API client.
|
|
725
|
+
*/
|
|
726
|
+
export interface CreateApiOptions {
|
|
727
|
+
/** Base URL for all API requests (required) */
|
|
728
|
+
baseURL: string;
|
|
729
|
+
/** Auth strategies for each security scheme used in this API */
|
|
730
|
+
authStrategies: Record<SecuritySchemeId, AuthStrategy>;
|
|
731
|
+
/** Optional React Query client instance */
|
|
732
|
+
queryClient?: QueryClient;
|
|
733
|
+
/** Optional request interceptor */
|
|
734
|
+
onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Create a type-safe API client with authentication and React Query hooks.
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* \`\`\`typescript
|
|
742
|
+
* const api = createApi({
|
|
743
|
+
* baseURL: 'https://api.example.com',
|
|
744
|
+
* authStrategies: {
|
|
745
|
+
* jwt: { type: 'bearer', tokenProvider },
|
|
746
|
+
* },
|
|
747
|
+
* });
|
|
748
|
+
*
|
|
749
|
+
* // Imperative fetch
|
|
750
|
+
* const user = await api('GET /users/{id}', { params: { id: '123' } });
|
|
751
|
+
*
|
|
752
|
+
* // React Query hooks
|
|
753
|
+
* const { data } = api.useQuery('GET /users/{id}', { params: { id: '123' } });
|
|
754
|
+
* const mutation = api.useMutation('POST /users');
|
|
755
|
+
* \`\`\`
|
|
756
|
+
*/
|
|
757
|
+
export function createApi(options: CreateApiOptions) {
|
|
758
|
+
const fetcher = createAuthAwareFetcher<paths, typeof endpointAuth, typeof securitySchemes>({
|
|
759
|
+
baseURL: options.baseURL,
|
|
760
|
+
endpointAuth,
|
|
761
|
+
securitySchemes,
|
|
762
|
+
authStrategies: options.authStrategies,
|
|
763
|
+
onRequest: options.onRequest,
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
const hooks = createEndpointHooks<paths>(fetcher, { queryClient: options.queryClient });
|
|
767
|
+
|
|
768
|
+
return Object.assign(fetcher, hooks);
|
|
769
|
+
}
|
|
770
|
+
` : `
|
|
771
|
+
// ============================================================
|
|
772
|
+
// API Client Factory
|
|
773
|
+
// ============================================================
|
|
774
|
+
|
|
775
|
+
import { TypedFetcher, type FetcherOptions } from '@geekmidas/client/fetcher';
|
|
776
|
+
import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
|
|
777
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Options for creating the API client.
|
|
781
|
+
*/
|
|
782
|
+
export interface CreateApiOptions extends Omit<FetcherOptions, 'baseURL'> {
|
|
783
|
+
/** Base URL for all API requests (required) */
|
|
784
|
+
baseURL: string;
|
|
785
|
+
/** Optional React Query client instance */
|
|
786
|
+
queryClient?: QueryClient;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Create a type-safe API client with React Query hooks.
|
|
791
|
+
*
|
|
792
|
+
* @example
|
|
793
|
+
* \`\`\`typescript
|
|
794
|
+
* const api = createApi({
|
|
795
|
+
* baseURL: 'https://api.example.com',
|
|
796
|
+
* });
|
|
797
|
+
*
|
|
798
|
+
* // Imperative fetch
|
|
799
|
+
* const data = await api('GET /health');
|
|
800
|
+
*
|
|
801
|
+
* // React Query hooks
|
|
802
|
+
* const { data } = api.useQuery('GET /health');
|
|
803
|
+
* \`\`\`
|
|
804
|
+
*/
|
|
805
|
+
export function createApi(options: CreateApiOptions) {
|
|
806
|
+
const { queryClient, ...fetcherOptions } = options;
|
|
807
|
+
const fetcher = new TypedFetcher<paths>(fetcherOptions);
|
|
808
|
+
|
|
809
|
+
const hooks = createEndpointHooks<paths>(fetcher.request.bind(fetcher), { queryClient });
|
|
810
|
+
|
|
811
|
+
return Object.assign(fetcher.request.bind(fetcher), hooks);
|
|
812
|
+
}
|
|
813
|
+
`;
|
|
814
|
+
return `// Auto-generated by @geekmidas/cli - DO NOT EDIT
|
|
815
|
+
// Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
816
|
+
|
|
817
|
+
// ============================================================
|
|
818
|
+
// Security Scheme Type
|
|
819
|
+
// ============================================================
|
|
820
|
+
|
|
821
|
+
interface SecuritySchemeObject {
|
|
822
|
+
type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
|
|
823
|
+
description?: string;
|
|
824
|
+
name?: string;
|
|
825
|
+
in?: 'query' | 'header' | 'cookie';
|
|
826
|
+
scheme?: string;
|
|
827
|
+
bearerFormat?: string;
|
|
828
|
+
flows?: Record<string, unknown>;
|
|
829
|
+
openIdConnectUrl?: string;
|
|
830
|
+
[key: string]: unknown;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// ============================================================
|
|
834
|
+
// API Info
|
|
835
|
+
// ============================================================
|
|
836
|
+
|
|
837
|
+
export const apiInfo = {
|
|
838
|
+
title: '${title}',
|
|
839
|
+
version: '${version}',${description ? `\n description: '${description.replace(/'/g, "\\'")}',` : ""}
|
|
840
|
+
} as const;
|
|
841
|
+
|
|
842
|
+
// ============================================================
|
|
843
|
+
// Security Schemes
|
|
844
|
+
// ============================================================
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Available security schemes for this API.
|
|
848
|
+
* Maps authorizer names to OpenAPI security scheme definitions.
|
|
849
|
+
*/
|
|
850
|
+
export const securitySchemes = ${JSON.stringify(securitySchemesObj, null, 2).replace(/"([a-zA-Z_$][a-zA-Z0-9_$]*)":/g, "$1:")} as const satisfies Record<string, SecuritySchemeObject>;
|
|
851
|
+
|
|
852
|
+
export type SecuritySchemeId = ${schemeNames || "never"};
|
|
853
|
+
|
|
854
|
+
// ============================================================
|
|
855
|
+
// Endpoint Authentication Map
|
|
856
|
+
// ============================================================
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Runtime map of endpoints to their required authentication scheme.
|
|
860
|
+
* \`null\` indicates a public endpoint (no auth required).
|
|
861
|
+
*/
|
|
862
|
+
export const endpointAuth = ${JSON.stringify(endpointAuth, null, 2).replace(/"([^"]+)":/g, "'$1':")} as const satisfies Record<string, SecuritySchemeId | null>;
|
|
863
|
+
|
|
864
|
+
export type EndpointString = keyof typeof endpointAuth;
|
|
865
|
+
|
|
866
|
+
export type AuthenticatedEndpoint = {
|
|
867
|
+
[K in EndpointString]: typeof endpointAuth[K] extends null ? never : K;
|
|
868
|
+
}[EndpointString];
|
|
869
|
+
|
|
870
|
+
export type PublicEndpoint = {
|
|
871
|
+
[K in EndpointString]: typeof endpointAuth[K] extends null ? K : never;
|
|
872
|
+
}[EndpointString];
|
|
873
|
+
|
|
874
|
+
// ============================================================
|
|
875
|
+
// Schema Definitions
|
|
876
|
+
// ============================================================
|
|
877
|
+
|
|
878
|
+
${schemaInterfaces}
|
|
879
|
+
|
|
880
|
+
// ============================================================
|
|
881
|
+
// OpenAPI Paths
|
|
882
|
+
// ============================================================
|
|
883
|
+
|
|
884
|
+
${pathsInterface}
|
|
885
|
+
${createApiSection}
|
|
886
|
+
`;
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/openapi.ts
|
|
892
|
+
/**
|
|
893
|
+
* Fixed output path for generated OpenAPI client (not configurable)
|
|
894
|
+
*/
|
|
895
|
+
const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
|
|
896
|
+
/**
|
|
897
|
+
* Resolve OpenAPI config from GkmConfig
|
|
898
|
+
*/
|
|
899
|
+
function resolveOpenApiConfig(config) {
|
|
900
|
+
if (config.openapi === false) return { enabled: false };
|
|
901
|
+
if (config.openapi === true || config.openapi === void 0) return {
|
|
902
|
+
enabled: config.openapi === true,
|
|
903
|
+
title: "API Documentation",
|
|
904
|
+
version: "1.0.0",
|
|
905
|
+
description: "Auto-generated API documentation from endpoints"
|
|
906
|
+
};
|
|
907
|
+
return {
|
|
908
|
+
enabled: config.openapi.enabled !== false,
|
|
909
|
+
title: config.openapi.title || "API Documentation",
|
|
910
|
+
version: config.openapi.version || "1.0.0",
|
|
911
|
+
description: config.openapi.description || "Auto-generated API documentation from endpoints"
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Generate OpenAPI spec from endpoints
|
|
916
|
+
* @returns Object with output path and endpoint count, or null if disabled
|
|
917
|
+
*/
|
|
918
|
+
async function generateOpenApi(config, options = {}) {
|
|
919
|
+
const logger = options.silent ? { log: () => {} } : console;
|
|
920
|
+
const openApiConfig = resolveOpenApiConfig(config);
|
|
921
|
+
if (!openApiConfig.enabled) return null;
|
|
922
|
+
const endpointGenerator = new EndpointGenerator();
|
|
923
|
+
const loadedEndpoints = await endpointGenerator.load(config.routes);
|
|
924
|
+
if (loadedEndpoints.length === 0) {
|
|
925
|
+
logger.log("No valid endpoints found for OpenAPI generation");
|
|
926
|
+
return null;
|
|
927
|
+
}
|
|
928
|
+
const endpoints = loadedEndpoints.map(({ construct }) => construct);
|
|
929
|
+
const outputPath = (0, node_path.join)(process.cwd(), OPENAPI_OUTPUT_PATH);
|
|
930
|
+
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(outputPath), { recursive: true });
|
|
931
|
+
const tsGenerator = new OpenApiTsGenerator();
|
|
932
|
+
const tsContent = await tsGenerator.generate(endpoints, {
|
|
933
|
+
title: openApiConfig.title,
|
|
934
|
+
version: openApiConfig.version,
|
|
935
|
+
description: openApiConfig.description
|
|
936
|
+
});
|
|
937
|
+
await (0, node_fs_promises.writeFile)(outputPath, tsContent);
|
|
938
|
+
logger.log(`📄 OpenAPI client generated: ${OPENAPI_OUTPUT_PATH}`);
|
|
939
|
+
return {
|
|
940
|
+
outputPath,
|
|
941
|
+
endpointCount: loadedEndpoints.length
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
async function openapiCommand(options = {}) {
|
|
945
|
+
const logger = console;
|
|
946
|
+
try {
|
|
947
|
+
const config = await require_config.loadConfig(options.cwd);
|
|
948
|
+
if (!config.openapi) config.openapi = { enabled: true };
|
|
949
|
+
const result = await generateOpenApi(config);
|
|
950
|
+
if (result) logger.log(`Found ${result.endpointCount} endpoints`);
|
|
951
|
+
} catch (error) {
|
|
952
|
+
throw new Error(`OpenAPI generation failed: ${error.message}`);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
//#endregion
|
|
957
|
+
Object.defineProperty(exports, 'ConstructGenerator', {
|
|
958
|
+
enumerable: true,
|
|
959
|
+
get: function () {
|
|
960
|
+
return ConstructGenerator;
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
Object.defineProperty(exports, 'EndpointGenerator', {
|
|
964
|
+
enumerable: true,
|
|
965
|
+
get: function () {
|
|
966
|
+
return EndpointGenerator;
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
Object.defineProperty(exports, 'OPENAPI_OUTPUT_PATH', {
|
|
970
|
+
enumerable: true,
|
|
971
|
+
get: function () {
|
|
972
|
+
return OPENAPI_OUTPUT_PATH;
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
Object.defineProperty(exports, 'generateOpenApi', {
|
|
976
|
+
enumerable: true,
|
|
977
|
+
get: function () {
|
|
978
|
+
return generateOpenApi;
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
Object.defineProperty(exports, 'openapiCommand', {
|
|
982
|
+
enumerable: true,
|
|
983
|
+
get: function () {
|
|
984
|
+
return openapiCommand;
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
Object.defineProperty(exports, 'resolveOpenApiConfig', {
|
|
988
|
+
enumerable: true,
|
|
989
|
+
get: function () {
|
|
990
|
+
return resolveOpenApiConfig;
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
//# sourceMappingURL=openapi-tAIbJJU_.cjs.map
|