@geekmidas/cli 1.9.0 → 1.10.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/CHANGELOG.md +21 -0
- package/README.md +42 -6
- package/dist/{HostingerProvider-CEsQbmpY.cjs → HostingerProvider-5KYmwoK2.cjs} +1 -1
- package/dist/{HostingerProvider-CEsQbmpY.cjs.map → HostingerProvider-5KYmwoK2.cjs.map} +1 -1
- package/dist/{HostingerProvider-DkahM5AP.mjs → HostingerProvider-ANWchdiK.mjs} +1 -1
- package/dist/{HostingerProvider-DkahM5AP.mjs.map → HostingerProvider-ANWchdiK.mjs.map} +1 -1
- package/dist/{LocalStateProvider-Roi202l7.cjs → LocalStateProvider-CLifRC0Y.cjs} +1 -1
- package/dist/{LocalStateProvider-Roi202l7.cjs.map → LocalStateProvider-CLifRC0Y.cjs.map} +1 -1
- package/dist/{LocalStateProvider-DXIwWb7k.mjs → LocalStateProvider-Dp0KkRcw.mjs} +1 -1
- package/dist/{LocalStateProvider-DXIwWb7k.mjs.map → LocalStateProvider-Dp0KkRcw.mjs.map} +1 -1
- package/dist/{Route53Provider-Ckq_n5Be.mjs → Route53Provider-QoPgcXxn.mjs} +1 -1
- package/dist/{Route53Provider-Ckq_n5Be.mjs.map → Route53Provider-QoPgcXxn.mjs.map} +1 -1
- package/dist/{Route53Provider-BqXeHzuc.cjs → Route53Provider-owQQ4pn6.cjs} +1 -1
- package/dist/{Route53Provider-BqXeHzuc.cjs.map → Route53Provider-owQQ4pn6.cjs.map} +1 -1
- package/dist/{SSMStateProvider-BReQA5re.cjs → SSMStateProvider-CT8tjl9o.cjs} +1 -1
- package/dist/{SSMStateProvider-BReQA5re.cjs.map → SSMStateProvider-CT8tjl9o.cjs.map} +1 -1
- package/dist/{SSMStateProvider-wddd0_-d.mjs → SSMStateProvider-CksOTB8M.mjs} +1 -1
- package/dist/{SSMStateProvider-wddd0_-d.mjs.map → SSMStateProvider-CksOTB8M.mjs.map} +1 -1
- package/dist/{backup-provisioner-BAExdDtc.mjs → backup-provisioner-BEXoHTuC.mjs} +1 -1
- package/dist/{backup-provisioner-BAExdDtc.mjs.map → backup-provisioner-BEXoHTuC.mjs.map} +1 -1
- package/dist/{backup-provisioner-C8VK63I-.cjs → backup-provisioner-C4noe75O.cjs} +1 -1
- package/dist/{backup-provisioner-C8VK63I-.cjs.map → backup-provisioner-C4noe75O.cjs.map} +1 -1
- package/dist/{bundler-BxHyDhdt.mjs → bundler-DQYjKFPm.mjs} +1 -1
- package/dist/{bundler-BxHyDhdt.mjs.map → bundler-DQYjKFPm.mjs.map} +1 -1
- package/dist/{bundler-CuMIfXw5.cjs → bundler-NpfYPBUo.cjs} +1 -1
- package/dist/{bundler-CuMIfXw5.cjs.map → bundler-NpfYPBUo.cjs.map} +1 -1
- package/dist/{config-6JHOwLCx.cjs → config-D3ORuiUs.cjs} +2 -2
- package/dist/{config-6JHOwLCx.cjs.map → config-D3ORuiUs.cjs.map} +1 -1
- package/dist/{config-DxASSNjr.mjs → config-jsRYHOHU.mjs} +2 -2
- package/dist/{config-DxASSNjr.mjs.map → config-jsRYHOHU.mjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -2
- package/dist/fullstack-secrets-COWz084x.cjs +238 -0
- package/dist/fullstack-secrets-COWz084x.cjs.map +1 -0
- package/dist/fullstack-secrets-UZAFWuH4.mjs +202 -0
- package/dist/fullstack-secrets-UZAFWuH4.mjs.map +1 -0
- package/dist/{index-BVNXOydm.d.mts → index-3n-giNaw.d.mts} +18 -6
- package/dist/index-3n-giNaw.d.mts.map +1 -0
- package/dist/{index-Cyk2rTyj.d.cts → index-CiEOtKEX.d.cts} +18 -6
- package/dist/index-CiEOtKEX.d.cts.map +1 -0
- package/dist/index.cjs +322 -433
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +306 -417
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-CnvwSRDU.cjs → openapi-BYxAWwok.cjs} +178 -32
- package/dist/openapi-BYxAWwok.cjs.map +1 -0
- package/dist/{openapi-BYlyAbH3.mjs → openapi-DenF-okj.mjs} +148 -32
- package/dist/openapi-DenF-okj.mjs.map +1 -0
- package/dist/{openapi-react-query-DaTMSPD5.mjs → openapi-react-query-C4UdILaI.mjs} +1 -1
- package/dist/{openapi-react-query-DaTMSPD5.mjs.map → openapi-react-query-C4UdILaI.mjs.map} +1 -1
- package/dist/{openapi-react-query-BeXvk-wa.cjs → openapi-react-query-DYbBq-WJ.cjs} +1 -1
- package/dist/{openapi-react-query-BeXvk-wa.cjs.map → openapi-react-query-DYbBq-WJ.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.d.mts.map +1 -1
- package/dist/openapi.mjs +3 -3
- package/dist/reconcile-7yarEvmK.cjs +36 -0
- package/dist/reconcile-7yarEvmK.cjs.map +1 -0
- package/dist/reconcile-D2WCDQue.mjs +36 -0
- package/dist/reconcile-D2WCDQue.mjs.map +1 -0
- package/dist/{sync-BnqNNc6O.mjs → sync-6FoT41G3.mjs} +1 -1
- package/dist/{sync-CHfhmXF3.mjs → sync-CbeKrnQV.mjs} +1 -1
- package/dist/{sync-CHfhmXF3.mjs.map → sync-CbeKrnQV.mjs.map} +1 -1
- package/dist/{sync-BOS0jKLn.cjs → sync-DdkKaHqP.cjs} +1 -1
- package/dist/{sync-BOS0jKLn.cjs.map → sync-DdkKaHqP.cjs.map} +1 -1
- package/dist/sync-RsnjXYwG.cjs +4 -0
- package/dist/{types-eTlj5f2M.d.mts → types-C7QJJl9f.d.cts} +6 -2
- package/dist/types-C7QJJl9f.d.cts.map +1 -0
- package/dist/{types-l53qUmGt.d.cts → types-Iqsq_FIG.d.mts} +6 -2
- package/dist/types-Iqsq_FIG.d.mts.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-D2ocAlpl.cjs → workspace-4SP3Gx4Y.cjs} +11 -3
- package/dist/{workspace-D2ocAlpl.cjs.map → workspace-4SP3Gx4Y.cjs.map} +1 -1
- package/dist/{workspace-9IQIjwkQ.mjs → workspace-D4z4A4cq.mjs} +11 -3
- package/dist/{workspace-9IQIjwkQ.mjs.map → workspace-D4z4A4cq.mjs.map} +1 -1
- package/package.json +2 -2
- package/src/build/__tests__/manifests.spec.ts +171 -0
- package/src/build/__tests__/partitions.spec.ts +110 -0
- package/src/build/index.ts +58 -15
- package/src/build/manifests.ts +153 -32
- package/src/build/partitions.ts +58 -0
- package/src/deploy/sniffer.ts +6 -1
- package/src/dev/__tests__/index.spec.ts +49 -0
- package/src/dev/index.ts +84 -63
- package/src/generators/Generator.ts +27 -7
- package/src/generators/OpenApiTsGenerator.ts +4 -4
- package/src/index.ts +79 -1
- package/src/init/versions.ts +4 -4
- package/src/openapi.ts +2 -1
- package/src/secrets/__tests__/reconcile.spec.ts +123 -0
- package/src/secrets/reconcile.ts +53 -0
- package/src/setup/fullstack-secrets.ts +2 -0
- package/src/types.ts +17 -1
- package/src/workspace/client-generator.ts +6 -3
- package/src/workspace/schema.ts +13 -3
- package/dist/index-BVNXOydm.d.mts.map +0 -1
- package/dist/index-Cyk2rTyj.d.cts.map +0 -1
- package/dist/openapi-BYlyAbH3.mjs.map +0 -1
- package/dist/openapi-CnvwSRDU.cjs.map +0 -1
- package/dist/sync-BxFB34zW.cjs +0 -4
- package/dist/types-eTlj5f2M.d.mts.map +0 -1
- package/dist/types-l53qUmGt.d.cts.map +0 -1
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { loadWorkspaceConfig } from "./config-
|
|
1
|
+
import { loadWorkspaceConfig } from "./config-jsRYHOHU.mjs";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
2
3
|
import { dirname, join, relative } from "node:path";
|
|
3
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
5
|
import fg from "fast-glob";
|
|
5
6
|
import kebabCase from "lodash.kebabcase";
|
|
6
7
|
import { Endpoint } from "@geekmidas/constructs/endpoints";
|
|
7
8
|
import { StandardSchemaJsonSchema, getSchemaMetadata } from "@geekmidas/schema/conversion";
|
|
8
9
|
|
|
10
|
+
//#region src/types.ts
|
|
11
|
+
function isPartitionedRoutes(routes) {
|
|
12
|
+
return typeof routes === "object" && routes !== null && !Array.isArray(routes) && "paths" in routes;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
9
16
|
//#region src/generators/Generator.ts
|
|
10
17
|
var ConstructGenerator = class {
|
|
11
18
|
static async build(context, outputDir, generator, patterns, options) {
|
|
@@ -13,8 +20,13 @@ var ConstructGenerator = class {
|
|
|
13
20
|
return generator.build(context, constructs, outputDir, options);
|
|
14
21
|
}
|
|
15
22
|
async load(patterns, cwd = process.cwd(), bustCache = false) {
|
|
16
|
-
const logger = console;
|
|
17
|
-
|
|
23
|
+
const logger$1 = console;
|
|
24
|
+
let globPatterns;
|
|
25
|
+
let partitionFn;
|
|
26
|
+
if (isPartitionedRoutes(patterns)) {
|
|
27
|
+
globPatterns = Array.isArray(patterns.paths) ? patterns.paths : [patterns.paths];
|
|
28
|
+
partitionFn = patterns.partition;
|
|
29
|
+
} else globPatterns = Array.isArray(patterns) ? patterns : patterns ? [patterns] : [];
|
|
18
30
|
const files = fg.stream(globPatterns, {
|
|
19
31
|
cwd,
|
|
20
32
|
absolute: true
|
|
@@ -24,6 +36,7 @@ var ConstructGenerator = class {
|
|
|
24
36
|
const file = f.toString();
|
|
25
37
|
const importPath = bustCache ? `${file}?t=${Date.now()}` : file;
|
|
26
38
|
const module = await import(importPath);
|
|
39
|
+
const partition = partitionFn ? partitionFn(file) : void 0;
|
|
27
40
|
for (const [key, construct] of Object.entries(module)) if (this.isConstruct(construct)) constructs.push({
|
|
28
41
|
key,
|
|
29
42
|
name: kebabCase(key),
|
|
@@ -31,10 +44,11 @@ var ConstructGenerator = class {
|
|
|
31
44
|
path: {
|
|
32
45
|
absolute: file,
|
|
33
46
|
relative: relative(process.cwd(), file)
|
|
34
|
-
}
|
|
47
|
+
},
|
|
48
|
+
partition
|
|
35
49
|
});
|
|
36
50
|
} catch (error) {
|
|
37
|
-
logger.warn(`Failed to load ${f}:`, error.message);
|
|
51
|
+
logger$1.warn(`Failed to load ${f}:`, error.message);
|
|
38
52
|
throw new Error("Failed to load constructs. Please check the logs for details.");
|
|
39
53
|
}
|
|
40
54
|
return constructs;
|
|
@@ -630,7 +644,7 @@ var EndpointGenerator = class extends ConstructGenerator {
|
|
|
630
644
|
async build(context, constructs, outputDir, options) {
|
|
631
645
|
const provider = options?.provider || "aws-apigatewayv2";
|
|
632
646
|
const enableOpenApi = options?.enableOpenApi || false;
|
|
633
|
-
const logger = console;
|
|
647
|
+
const logger$1 = console;
|
|
634
648
|
const routes = [];
|
|
635
649
|
if (constructs.length === 0) return routes;
|
|
636
650
|
if (provider === "server") {
|
|
@@ -642,7 +656,7 @@ var EndpointGenerator = class extends ConstructGenerator {
|
|
|
642
656
|
handler: relative(process.cwd(), appFile),
|
|
643
657
|
authorizer: "none"
|
|
644
658
|
});
|
|
645
|
-
logger.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
|
|
659
|
+
logger$1.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
|
|
646
660
|
} else if (provider === "aws-lambda") {
|
|
647
661
|
const routesDir = join(outputDir, "routes");
|
|
648
662
|
await mkdir(routesDir, { recursive: true });
|
|
@@ -658,7 +672,7 @@ var EndpointGenerator = class extends ConstructGenerator {
|
|
|
658
672
|
authorizer: construct.authorizer?.name ?? "none"
|
|
659
673
|
};
|
|
660
674
|
routes.push(routeInfo);
|
|
661
|
-
logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
675
|
+
logger$1.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
662
676
|
}
|
|
663
677
|
} else for (const { key, construct, path } of constructs) {
|
|
664
678
|
const handlerFile = await this.generateHandlerFile(outputDir, path.relative, key, provider, construct, context);
|
|
@@ -672,7 +686,7 @@ var EndpointGenerator = class extends ConstructGenerator {
|
|
|
672
686
|
authorizer: construct.authorizer?.name ?? "none"
|
|
673
687
|
};
|
|
674
688
|
routes.push(routeInfo);
|
|
675
|
-
logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
689
|
+
logger$1.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
676
690
|
}
|
|
677
691
|
return routes;
|
|
678
692
|
}
|
|
@@ -761,7 +775,7 @@ export async function setupEndpoints(
|
|
|
761
775
|
* Generate optimized endpoints files with nested folder structure (per-endpoint files)
|
|
762
776
|
*/
|
|
763
777
|
async generateOptimizedEndpointsFile(endpointsPath, endpoints, _endpointImports, _allExportNames) {
|
|
764
|
-
const logger = console;
|
|
778
|
+
const logger$1 = console;
|
|
765
779
|
const outputDir = dirname(endpointsPath);
|
|
766
780
|
const endpointsDir = join(outputDir, "endpoints");
|
|
767
781
|
await mkdir(join(endpointsDir, "minimal"), { recursive: true });
|
|
@@ -778,11 +792,11 @@ export async function setupEndpoints(
|
|
|
778
792
|
};
|
|
779
793
|
});
|
|
780
794
|
const summary = summarizeAnalysis(analyses);
|
|
781
|
-
logger.log(`\n📊 Endpoint Analysis:`);
|
|
782
|
-
logger.log(` Total: ${summary.total} endpoints`);
|
|
783
|
-
logger.log(` - Minimal (near-raw-Hono): ${summary.byTier.minimal} endpoints`);
|
|
784
|
-
logger.log(` - Standard (auth/services): ${summary.byTier.standard} endpoints`);
|
|
785
|
-
logger.log(` - Full (audits/rls/rate-limit): ${summary.byTier.full} endpoints`);
|
|
795
|
+
logger$1.log(`\n📊 Endpoint Analysis:`);
|
|
796
|
+
logger$1.log(` Total: ${summary.total} endpoints`);
|
|
797
|
+
logger$1.log(` - Minimal (near-raw-Hono): ${summary.byTier.minimal} endpoints`);
|
|
798
|
+
logger$1.log(` - Standard (auth/services): ${summary.byTier.standard} endpoints`);
|
|
799
|
+
logger$1.log(` - Full (audits/rls/rate-limit): ${summary.byTier.full} endpoints`);
|
|
786
800
|
const files = generateEndpointFilesNested(analyses, endpointImports);
|
|
787
801
|
for (const [filename, content] of Object.entries(files)) {
|
|
788
802
|
const filePath = join(endpointsDir, filename);
|
|
@@ -791,7 +805,7 @@ export async function setupEndpoints(
|
|
|
791
805
|
}
|
|
792
806
|
const endpointFiles = Object.keys(files).filter((f) => !f.endsWith("index.ts") && !f.endsWith("validators.ts")).length;
|
|
793
807
|
const indexFiles = Object.keys(files).filter((f) => f.endsWith("index.ts")).length;
|
|
794
|
-
logger.log(` Generated ${endpointFiles} endpoint files + ${indexFiles} index files + validators.ts`);
|
|
808
|
+
logger$1.log(` Generated ${endpointFiles} endpoint files + ${indexFiles} index files + validators.ts`);
|
|
795
809
|
return join(endpointsDir, "index.ts");
|
|
796
810
|
}
|
|
797
811
|
async generateAppFile(outputDir, context) {
|
|
@@ -1556,7 +1570,7 @@ export function createApi(options: CreateApiOptions) {
|
|
|
1556
1570
|
// API Client Factory
|
|
1557
1571
|
// ============================================================
|
|
1558
1572
|
|
|
1559
|
-
import {
|
|
1573
|
+
import { createTypedFetcher, type FetcherOptions } from '@geekmidas/client/fetcher';
|
|
1560
1574
|
import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
|
|
1561
1575
|
import type { QueryClient } from '@tanstack/react-query';
|
|
1562
1576
|
|
|
@@ -1588,11 +1602,11 @@ export interface CreateApiOptions extends Omit<FetcherOptions, 'baseURL'> {
|
|
|
1588
1602
|
*/
|
|
1589
1603
|
export function createApi(options: CreateApiOptions) {
|
|
1590
1604
|
const { queryClient, ...fetcherOptions } = options;
|
|
1591
|
-
const
|
|
1605
|
+
const request = createTypedFetcher<paths>(fetcherOptions);
|
|
1592
1606
|
|
|
1593
|
-
const hooks = createEndpointHooks<paths>(
|
|
1607
|
+
const hooks = createEndpointHooks<paths>(request, { queryClient });
|
|
1594
1608
|
|
|
1595
|
-
return Object.assign(
|
|
1609
|
+
return Object.assign(request, hooks);
|
|
1596
1610
|
}
|
|
1597
1611
|
`;
|
|
1598
1612
|
return `// Auto-generated by @geekmidas/cli - DO NOT EDIT
|
|
@@ -1670,6 +1684,108 @@ ${createApiSection}
|
|
|
1670
1684
|
}
|
|
1671
1685
|
};
|
|
1672
1686
|
|
|
1687
|
+
//#endregion
|
|
1688
|
+
//#region src/workspace/client-generator.ts
|
|
1689
|
+
const logger = console;
|
|
1690
|
+
/**
|
|
1691
|
+
* Normalize routes to an array of patterns.
|
|
1692
|
+
* Handles string, string[], and PartitionedRoutes (extracts paths).
|
|
1693
|
+
* @internal Exported for use in dev command
|
|
1694
|
+
*/
|
|
1695
|
+
function normalizeRoutes(routes) {
|
|
1696
|
+
if (!routes) return [];
|
|
1697
|
+
if (isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
|
|
1698
|
+
return Array.isArray(routes) ? routes : [routes];
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Get frontend apps that depend on a backend app.
|
|
1702
|
+
*/
|
|
1703
|
+
function getDependentFrontends(workspace, backendAppName) {
|
|
1704
|
+
const dependentApps = [];
|
|
1705
|
+
for (const [appName, app] of Object.entries(workspace.apps)) if (app.type === "frontend" && app.dependencies.includes(backendAppName)) dependentApps.push(appName);
|
|
1706
|
+
return dependentApps;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Get the path to a backend's OpenAPI spec file.
|
|
1710
|
+
*/
|
|
1711
|
+
function getBackendOpenApiPath(workspace, backendAppName) {
|
|
1712
|
+
const app = workspace.apps[backendAppName];
|
|
1713
|
+
if (!app || app.type !== "backend") return null;
|
|
1714
|
+
return join(workspace.root, app.path, ".gkm", "openapi.ts");
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Count endpoints in an OpenAPI spec content.
|
|
1718
|
+
*/
|
|
1719
|
+
function countEndpoints(content) {
|
|
1720
|
+
const endpointMatches = content.match(/'(GET|POST|PUT|PATCH|DELETE)\s+\/[^']+'/g);
|
|
1721
|
+
return endpointMatches?.length ?? 0;
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Copy the OpenAPI client from a backend to all dependent frontend apps.
|
|
1725
|
+
* Called when the backend's .gkm/openapi.ts file changes.
|
|
1726
|
+
*/
|
|
1727
|
+
async function copyClientToFrontends(workspace, backendAppName, options = {}) {
|
|
1728
|
+
const log = options.silent ? () => {} : logger.log.bind(logger);
|
|
1729
|
+
const results = [];
|
|
1730
|
+
const backendApp = workspace.apps[backendAppName];
|
|
1731
|
+
if (!backendApp || backendApp.type !== "backend") return results;
|
|
1732
|
+
const openApiPath = join(workspace.root, backendApp.path, ".gkm", "openapi.ts");
|
|
1733
|
+
if (!existsSync(openApiPath)) return results;
|
|
1734
|
+
const content = await readFile(openApiPath, "utf-8");
|
|
1735
|
+
const endpointCount = countEndpoints(content);
|
|
1736
|
+
const dependentFrontends = getDependentFrontends(workspace, backendAppName);
|
|
1737
|
+
for (const frontendAppName of dependentFrontends) {
|
|
1738
|
+
const frontendApp = workspace.apps[frontendAppName];
|
|
1739
|
+
if (!frontendApp || frontendApp.type !== "frontend") continue;
|
|
1740
|
+
const clientOutput = frontendApp.client?.output;
|
|
1741
|
+
if (!clientOutput) continue;
|
|
1742
|
+
const result = {
|
|
1743
|
+
frontendApp: frontendAppName,
|
|
1744
|
+
backendApp: backendAppName,
|
|
1745
|
+
outputPath: "",
|
|
1746
|
+
endpointCount,
|
|
1747
|
+
success: false
|
|
1748
|
+
};
|
|
1749
|
+
try {
|
|
1750
|
+
const frontendPath = join(workspace.root, frontendApp.path);
|
|
1751
|
+
const outputDir = join(frontendPath, clientOutput);
|
|
1752
|
+
await mkdir(outputDir, { recursive: true });
|
|
1753
|
+
const fileName = `${backendAppName}.ts`;
|
|
1754
|
+
const outputPath = join(outputDir, fileName);
|
|
1755
|
+
const backendRelPath = relative(dirname(outputPath), join(workspace.root, backendApp.path));
|
|
1756
|
+
const clientContent = `/**
|
|
1757
|
+
* Auto-generated API client for ${backendAppName}
|
|
1758
|
+
* Generated from: ${backendRelPath}
|
|
1759
|
+
*
|
|
1760
|
+
* DO NOT EDIT - This file is automatically regenerated when backend schemas change.
|
|
1761
|
+
*/
|
|
1762
|
+
|
|
1763
|
+
${content}
|
|
1764
|
+
`;
|
|
1765
|
+
await writeFile(outputPath, clientContent);
|
|
1766
|
+
result.outputPath = outputPath;
|
|
1767
|
+
result.success = true;
|
|
1768
|
+
log(`📦 Copied client to ${frontendAppName} from ${backendAppName} (${endpointCount} endpoints)`);
|
|
1769
|
+
} catch (error) {
|
|
1770
|
+
result.error = error.message;
|
|
1771
|
+
}
|
|
1772
|
+
results.push(result);
|
|
1773
|
+
}
|
|
1774
|
+
return results;
|
|
1775
|
+
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Copy clients from all backends to their dependent frontends.
|
|
1778
|
+
* Useful for initial setup or force refresh.
|
|
1779
|
+
*/
|
|
1780
|
+
async function copyAllClients(workspace, options = {}) {
|
|
1781
|
+
const allResults = [];
|
|
1782
|
+
for (const [appName, app] of Object.entries(workspace.apps)) if (app.type === "backend" && app.routes) {
|
|
1783
|
+
const results = await copyClientToFrontends(workspace, appName, options);
|
|
1784
|
+
allResults.push(...results);
|
|
1785
|
+
}
|
|
1786
|
+
return allResults;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1673
1789
|
//#endregion
|
|
1674
1790
|
//#region src/openapi.ts
|
|
1675
1791
|
/**
|
|
@@ -1699,13 +1815,13 @@ function resolveOpenApiConfig(config) {
|
|
|
1699
1815
|
* @returns Object with output path and endpoint count, or null if disabled
|
|
1700
1816
|
*/
|
|
1701
1817
|
async function generateOpenApi(config, options = {}) {
|
|
1702
|
-
const logger = options.silent ? { log: () => {} } : console;
|
|
1818
|
+
const logger$1 = options.silent ? { log: () => {} } : console;
|
|
1703
1819
|
const openApiConfig = resolveOpenApiConfig(config);
|
|
1704
1820
|
if (!openApiConfig.enabled) return null;
|
|
1705
1821
|
const endpointGenerator = new EndpointGenerator();
|
|
1706
1822
|
const loadedEndpoints = await endpointGenerator.load(config.routes, void 0, options.bustCache);
|
|
1707
1823
|
if (loadedEndpoints.length === 0) {
|
|
1708
|
-
logger.log("No valid endpoints found for OpenAPI generation");
|
|
1824
|
+
logger$1.log("No valid endpoints found for OpenAPI generation");
|
|
1709
1825
|
return null;
|
|
1710
1826
|
}
|
|
1711
1827
|
const endpoints = loadedEndpoints.map(({ construct }) => construct);
|
|
@@ -1718,34 +1834,34 @@ async function generateOpenApi(config, options = {}) {
|
|
|
1718
1834
|
description: openApiConfig.description
|
|
1719
1835
|
});
|
|
1720
1836
|
await writeFile(outputPath, tsContent);
|
|
1721
|
-
logger.log(`📄 OpenAPI client generated: ${OPENAPI_OUTPUT_PATH}`);
|
|
1837
|
+
logger$1.log(`📄 OpenAPI client generated: ${OPENAPI_OUTPUT_PATH}`);
|
|
1722
1838
|
return {
|
|
1723
1839
|
outputPath,
|
|
1724
1840
|
endpointCount: loadedEndpoints.length
|
|
1725
1841
|
};
|
|
1726
1842
|
}
|
|
1727
1843
|
async function openapiCommand(options = {}) {
|
|
1728
|
-
const logger = console;
|
|
1844
|
+
const logger$1 = console;
|
|
1729
1845
|
try {
|
|
1730
1846
|
const loadedConfig = await loadWorkspaceConfig(options.cwd);
|
|
1731
1847
|
if (loadedConfig.type === "single") {
|
|
1732
1848
|
const config = loadedConfig.raw;
|
|
1733
1849
|
if (!config.openapi) config.openapi = { enabled: true };
|
|
1734
1850
|
const result = await generateOpenApi(config);
|
|
1735
|
-
if (result) logger.log(`Found ${result.endpointCount} endpoints`);
|
|
1851
|
+
if (result) logger$1.log(`Found ${result.endpointCount} endpoints`);
|
|
1736
1852
|
} else {
|
|
1737
1853
|
const { workspace } = loadedConfig;
|
|
1738
1854
|
const workspaceRoot = options.cwd || process.cwd();
|
|
1739
1855
|
const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend" && (app.openapi === true || typeof app.openapi === "object" && app.openapi.enabled !== false));
|
|
1740
1856
|
if (backendApps.length === 0) {
|
|
1741
|
-
logger.log("No backend apps with OpenAPI enabled found");
|
|
1857
|
+
logger$1.log("No backend apps with OpenAPI enabled found");
|
|
1742
1858
|
return;
|
|
1743
1859
|
}
|
|
1744
1860
|
const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "frontend" && app.client?.output);
|
|
1745
1861
|
for (const [appName, app] of backendApps) {
|
|
1746
1862
|
if (app.type !== "backend" || !app.routes) continue;
|
|
1747
1863
|
const appPath = join(workspaceRoot, app.path);
|
|
1748
|
-
const routes =
|
|
1864
|
+
const routes = normalizeRoutes(app.routes);
|
|
1749
1865
|
const routesGlob = routes.map((r) => join(appPath, r));
|
|
1750
1866
|
const gkmConfig = {
|
|
1751
1867
|
routes: routesGlob,
|
|
@@ -1758,7 +1874,7 @@ async function openapiCommand(options = {}) {
|
|
|
1758
1874
|
const result = await generateOpenApi(gkmConfig, { silent: true });
|
|
1759
1875
|
process.chdir(originalCwd);
|
|
1760
1876
|
if (result) {
|
|
1761
|
-
logger.log(`📄 [${appName}] Generated OpenAPI (${result.endpointCount} endpoints)`);
|
|
1877
|
+
logger$1.log(`📄 [${appName}] Generated OpenAPI (${result.endpointCount} endpoints)`);
|
|
1762
1878
|
for (const [frontendName, frontendApp] of frontendApps) {
|
|
1763
1879
|
if (frontendApp.type !== "frontend") continue;
|
|
1764
1880
|
const dependsOnBackend = !frontendApp.dependencies || frontendApp.dependencies.includes(appName);
|
|
@@ -1769,7 +1885,7 @@ async function openapiCommand(options = {}) {
|
|
|
1769
1885
|
const { readFile: readFile$1 } = await import("node:fs/promises");
|
|
1770
1886
|
const content = await readFile$1(result.outputPath, "utf-8");
|
|
1771
1887
|
await writeFile(clientOutputPath, content);
|
|
1772
|
-
logger.log(` → [${frontendName}] ${frontendApp.client.output}/openapi.ts`);
|
|
1888
|
+
logger$1.log(` → [${frontendName}] ${frontendApp.client.output}/openapi.ts`);
|
|
1773
1889
|
}
|
|
1774
1890
|
}
|
|
1775
1891
|
}
|
|
@@ -1781,5 +1897,5 @@ async function openapiCommand(options = {}) {
|
|
|
1781
1897
|
}
|
|
1782
1898
|
|
|
1783
1899
|
//#endregion
|
|
1784
|
-
export { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig };
|
|
1785
|
-
//# sourceMappingURL=openapi-
|
|
1900
|
+
export { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, copyAllClients, copyClientToFrontends, generateOpenApi, getBackendOpenApiPath, isPartitionedRoutes, normalizeRoutes, openapiCommand, resolveOpenApiConfig };
|
|
1901
|
+
//# sourceMappingURL=openapi-DenF-okj.mjs.map
|