@geekmidas/cli 10.0.0-alpha.2 → 10.0.0-alpha.21
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/README.md +25 -48
- package/bin/adjacent-tsconfig.mjs +59 -0
- package/bin/gkm.mjs +7 -1
- package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-BY26bWwB.mjs} +20 -21
- package/dist/HostingerProvider-BY26bWwB.mjs.map +1 -0
- package/dist/{HostingerProvider-h3EbEp-Z.cjs → HostingerProvider-BZFGYYVA.cjs} +21 -22
- package/dist/HostingerProvider-BZFGYYVA.cjs.map +1 -0
- package/dist/{LocalStateProvider-Db9SEjyH.cjs → LocalStateProvider-7HR6SS2t.cjs} +11 -6
- package/dist/LocalStateProvider-7HR6SS2t.cjs.map +1 -0
- package/dist/{LocalStateProvider-Bn6tS-oL.mjs → LocalStateProvider-D7QyJoLM.mjs} +10 -4
- package/dist/LocalStateProvider-D7QyJoLM.mjs.map +1 -0
- package/dist/{Route53Provider-RdpUDJQk.mjs → Route53Provider-Cvj40A8I.mjs} +12 -12
- package/dist/Route53Provider-Cvj40A8I.mjs.map +1 -0
- package/dist/{Route53Provider-di2fMM5N.cjs → Route53Provider-DVILBsvV.cjs} +20 -21
- package/dist/Route53Provider-DVILBsvV.cjs.map +1 -0
- package/dist/{SSMStateProvider-BRt2py-A.mjs → SSMStateProvider-B0Hu1MKZ.mjs} +13 -4
- package/dist/SSMStateProvider-B0Hu1MKZ.mjs.map +1 -0
- package/dist/{SSMStateProvider-DyX8s9HI.cjs → SSMStateProvider-VrQ-yeqd.cjs} +17 -9
- package/dist/SSMStateProvider-VrQ-yeqd.cjs.map +1 -0
- package/dist/{backup-provisioner-BrsHwYG0.cjs → backup-provisioner-BmhIO_Yr.cjs} +21 -19
- package/dist/backup-provisioner-BmhIO_Yr.cjs.map +1 -0
- package/dist/{backup-provisioner-Bgj5Vi_L.mjs → backup-provisioner-DIVCbfee.mjs} +10 -7
- package/dist/backup-provisioner-DIVCbfee.mjs.map +1 -0
- package/dist/{bundler-BY1OmV1e.cjs → bundler-mjqGAvu1.cjs} +10 -28
- package/dist/bundler-mjqGAvu1.cjs.map +1 -0
- package/dist/{bundler-Be8Zg4Wd.mjs → bundler-mwH7WOb1.mjs} +9 -26
- package/dist/bundler-mwH7WOb1.mjs.map +1 -0
- package/dist/{config-BholeD-0.cjs → config-DSXI480r.cjs} +80 -148
- package/dist/config-DSXI480r.cjs.map +1 -0
- package/dist/{config-CzWnfcXM.mjs → config-DdKkoUE1.mjs} +33 -88
- package/dist/config-DdKkoUE1.mjs.map +1 -0
- package/dist/config.cjs +4 -5
- package/dist/config.d.cts +14 -17
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +14 -17
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +3 -5
- package/dist/{credentials-DQmbRnr1.cjs → credentials-BfmmB4WD.cjs} +1508 -1243
- package/dist/credentials-BfmmB4WD.cjs.map +1 -0
- package/dist/{credentials-BZcp3CGx.mjs → credentials-CD8ftUS6.mjs} +1374 -1114
- package/dist/credentials-CD8ftUS6.mjs.map +1 -0
- package/dist/deploy/sniffer-envkit-patch.cjs +18 -10
- package/dist/deploy/sniffer-envkit-patch.cjs.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.d.cts +0 -2
- package/dist/deploy/sniffer-envkit-patch.d.cts.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.d.mts +0 -2
- package/dist/deploy/sniffer-envkit-patch.d.mts.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.mjs +10 -2
- package/dist/deploy/sniffer-envkit-patch.mjs.map +1 -1
- package/dist/deploy/sniffer-hooks.cjs +13 -7
- package/dist/deploy/sniffer-hooks.cjs.map +1 -1
- package/dist/deploy/sniffer-hooks.d.cts +1 -2
- package/dist/deploy/sniffer-hooks.d.cts.map +1 -1
- package/dist/deploy/sniffer-hooks.d.mts +1 -2
- package/dist/deploy/sniffer-hooks.d.mts.map +1 -1
- package/dist/deploy/sniffer-hooks.mjs +9 -2
- package/dist/deploy/sniffer-hooks.mjs.map +1 -1
- package/dist/deploy/sniffer-loader.cjs +16 -7
- package/dist/deploy/sniffer-loader.cjs.map +1 -1
- package/dist/deploy/sniffer-loader.d.cts +1 -1
- package/dist/deploy/sniffer-loader.d.mts +1 -1
- package/dist/deploy/sniffer-loader.mjs +13 -2
- package/dist/deploy/sniffer-loader.mjs.map +1 -1
- package/dist/deploy/sniffer-routes-worker.cjs +11 -11
- package/dist/deploy/sniffer-routes-worker.cjs.map +1 -1
- package/dist/deploy/sniffer-routes-worker.d.cts +1 -1
- package/dist/deploy/sniffer-routes-worker.d.mts +1 -1
- package/dist/deploy/sniffer-routes-worker.mjs +2 -2
- package/dist/deploy/sniffer-routes-worker.mjs.map +1 -1
- package/dist/deploy/sniffer-worker.cjs +15 -6
- package/dist/deploy/sniffer-worker.cjs.map +1 -1
- package/dist/deploy/sniffer-worker.d.cts +1 -3
- package/dist/deploy/sniffer-worker.d.cts.map +1 -1
- package/dist/deploy/sniffer-worker.d.mts +1 -3
- package/dist/deploy/sniffer-worker.d.mts.map +1 -1
- package/dist/deploy/sniffer-worker.mjs +15 -4
- package/dist/deploy/sniffer-worker.mjs.map +1 -1
- package/dist/{discover-DTmFeloL.cjs → discover-BERGFg8v.cjs} +81 -64
- package/dist/discover-BERGFg8v.cjs.map +1 -0
- package/dist/{discover-CAlFgYec.mjs → discover-CK-n3w6b.mjs} +35 -20
- package/dist/discover-CK-n3w6b.mjs.map +1 -0
- package/dist/{emit-CbcRolsa.cjs → emit-BdoPFjZf.cjs} +53 -36
- package/dist/emit-BdoPFjZf.cjs.map +1 -0
- package/dist/{emit-CiZS_5Ub.mjs → emit-Bzq7JsMP.mjs} +24 -6
- package/dist/emit-Bzq7JsMP.mjs.map +1 -0
- package/dist/{generator-VE2JrFlY.mjs → generator-LfZU7NlU.mjs} +8 -14
- package/dist/generator-LfZU7NlU.mjs.map +1 -0
- package/dist/{generator-CNzBw7g5.cjs → generator-Wdfp0jCS.cjs} +38 -45
- package/dist/generator-Wdfp0jCS.cjs.map +1 -0
- package/dist/github-Bho-C6Zg.cjs +216 -0
- package/dist/github-Bho-C6Zg.cjs.map +1 -0
- package/dist/github-De-yMwVt.mjs +216 -0
- package/dist/github-De-yMwVt.mjs.map +1 -0
- package/dist/{index-CHB4tSzX.d.cts → index-B4H4XF7A.d.mts} +4 -13
- package/dist/index-B4H4XF7A.d.mts.map +1 -0
- package/dist/{index-BThUzEIp.d.mts → index-RCUizGxL.d.cts} +4 -13
- package/dist/index-RCUizGxL.d.cts.map +1 -0
- package/dist/index.cjs +5108 -3381
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +5025 -3315
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-c9bpieI5.cjs → openapi-B8bu_OXN.cjs} +228 -188
- package/dist/openapi-B8bu_OXN.cjs.map +1 -0
- package/dist/{openapi-CY9xFkTH.mjs → openapi-DfjbhrsM.mjs} +172 -143
- package/dist/openapi-DfjbhrsM.mjs.map +1 -0
- package/dist/openapi.cjs +5 -6
- package/dist/openapi.d.cts +47 -14
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.mts +47 -14
- package/dist/openapi.d.mts.map +1 -1
- package/dist/openapi.mjs +2 -6
- package/dist/reconcile/public.cjs +4 -4
- package/dist/reconcile/public.d.cts +8 -26
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +8 -26
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +3 -4
- package/dist/{fullstack-secrets-D1o9-G5l.mjs → reconcile-gb1lz1Dk.mjs} +43 -17
- package/dist/reconcile-gb1lz1Dk.mjs.map +1 -0
- package/dist/{fullstack-secrets-C-GGohke.cjs → reconcile-hx_vBvux.cjs} +63 -38
- package/dist/reconcile-hx_vBvux.cjs.map +1 -0
- package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
- package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-C0BPl7ul.cjs} +23 -10
- package/dist/ssm-BKN1Cg4z.mjs +60 -0
- package/dist/ssm-BKN1Cg4z.mjs.map +1 -0
- package/dist/ssm-FxeSAt35.cjs +60 -0
- package/dist/ssm-FxeSAt35.cjs.map +1 -0
- package/dist/{storage-BJmzYxt8.cjs → storage-DgypfSD6.cjs} +65 -77
- package/dist/storage-DgypfSD6.cjs.map +1 -0
- package/dist/{storage-Bi24WfoW.mjs → storage-TP0x118M.mjs} +22 -15
- package/dist/storage-TP0x118M.mjs.map +1 -0
- package/dist/transfer-CXoyQZbB.cjs +151 -0
- package/dist/transfer-CXoyQZbB.cjs.map +1 -0
- package/dist/transfer-Gsxfy6m-.mjs +122 -0
- package/dist/transfer-Gsxfy6m-.mjs.map +1 -0
- package/dist/types-7R81hu0i.d.mts +6302 -0
- package/dist/types-7R81hu0i.d.mts.map +1 -0
- package/dist/types-N7c2O2m7.d.cts +6303 -0
- package/dist/types-N7c2O2m7.d.cts.map +1 -0
- package/dist/workspace/index.cjs +3 -3
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +2 -3
- package/dist/workspace-Bu3xNCej.mjs +6563 -0
- package/dist/workspace-Bu3xNCej.mjs.map +1 -0
- package/dist/workspace-CRD9YinV.cjs +6741 -0
- package/dist/workspace-CRD9YinV.cjs.map +1 -0
- package/package.json +33 -43
- package/dist/CachedStateProvider-BLo7zv7S.cjs +0 -3
- package/dist/CachedStateProvider-BxoAm-B2.mjs +0 -3
- package/dist/CachedStateProvider-CqPdW7CB.cjs +0 -60
- package/dist/CachedStateProvider-CqPdW7CB.cjs.map +0 -1
- package/dist/CachedStateProvider-DTniehMP.mjs +0 -54
- package/dist/CachedStateProvider-DTniehMP.mjs.map +0 -1
- package/dist/HostingerProvider-Cft7lEYr.mjs.map +0 -1
- package/dist/HostingerProvider-h3EbEp-Z.cjs.map +0 -1
- package/dist/LocalStateProvider-Bn6tS-oL.mjs.map +0 -1
- package/dist/LocalStateProvider-Db9SEjyH.cjs.map +0 -1
- package/dist/Route53Provider-RdpUDJQk.mjs.map +0 -1
- package/dist/Route53Provider-di2fMM5N.cjs.map +0 -1
- package/dist/SSMStateProvider-BRt2py-A.mjs.map +0 -1
- package/dist/SSMStateProvider-DyX8s9HI.cjs.map +0 -1
- package/dist/backup-provisioner-Bgj5Vi_L.mjs.map +0 -1
- package/dist/backup-provisioner-BrsHwYG0.cjs.map +0 -1
- package/dist/bundler-BY1OmV1e.cjs.map +0 -1
- package/dist/bundler-Be8Zg4Wd.mjs.map +0 -1
- package/dist/chunk-Duj1WY3L.mjs +0 -7
- package/dist/config-BholeD-0.cjs.map +0 -1
- package/dist/config-CzWnfcXM.mjs.map +0 -1
- package/dist/credentials-B5zRHdAl.mjs +0 -141
- package/dist/credentials-B5zRHdAl.mjs.map +0 -1
- package/dist/credentials-BZcp3CGx.mjs.map +0 -1
- package/dist/credentials-BapzjyV5.cjs +0 -195
- package/dist/credentials-BapzjyV5.cjs.map +0 -1
- package/dist/credentials-DQmbRnr1.cjs.map +0 -1
- package/dist/discover-CAlFgYec.mjs.map +0 -1
- package/dist/discover-DTmFeloL.cjs.map +0 -1
- package/dist/dokploy-api-BS2xnJLZ.mjs +0 -3
- package/dist/dokploy-api-BsVH0y_s.cjs +0 -718
- package/dist/dokploy-api-BsVH0y_s.cjs.map +0 -1
- package/dist/dokploy-api-BuxDRo3l.cjs +0 -3
- package/dist/dokploy-api-aTFPz7_4.mjs +0 -706
- package/dist/dokploy-api-aTFPz7_4.mjs.map +0 -1
- package/dist/emit-CbcRolsa.cjs.map +0 -1
- package/dist/emit-CiZS_5Ub.mjs.map +0 -1
- package/dist/encryption-C6jaU0hE.cjs +0 -54
- package/dist/encryption-C6jaU0hE.cjs.map +0 -1
- package/dist/encryption-CHzzeR8a.cjs +0 -4
- package/dist/encryption-CQUncu7v.mjs +0 -3
- package/dist/encryption-D-abyhZx.mjs +0 -42
- package/dist/encryption-D-abyhZx.mjs.map +0 -1
- package/dist/fullstack-secrets-C-GGohke.cjs.map +0 -1
- package/dist/fullstack-secrets-D1o9-G5l.mjs.map +0 -1
- package/dist/generator-CNzBw7g5.cjs.map +0 -1
- package/dist/generator-VE2JrFlY.mjs.map +0 -1
- package/dist/index-BThUzEIp.d.mts.map +0 -1
- package/dist/index-CHB4tSzX.d.cts.map +0 -1
- package/dist/openapi-CY9xFkTH.mjs.map +0 -1
- package/dist/openapi-c9bpieI5.cjs.map +0 -1
- package/dist/openapi-react-query-Byltvm_7.mjs +0 -167
- package/dist/openapi-react-query-Byltvm_7.mjs.map +0 -1
- package/dist/openapi-react-query-CmJ1xDbn.cjs +0 -173
- package/dist/openapi-react-query-CmJ1xDbn.cjs.map +0 -1
- package/dist/openapi-react-query.cjs +0 -4
- package/dist/openapi-react-query.d.cts +0 -11
- package/dist/openapi-react-query.d.cts.map +0 -1
- package/dist/openapi-react-query.d.mts +0 -11
- package/dist/openapi-react-query.d.mts.map +0 -1
- package/dist/openapi-react-query.mjs +0 -4
- package/dist/reconcile-CFs8C_1a.mjs +0 -37
- package/dist/reconcile-CFs8C_1a.mjs.map +0 -1
- package/dist/reconcile-D0pimNiy.cjs +0 -37
- package/dist/reconcile-D0pimNiy.cjs.map +0 -1
- package/dist/setup-Bc73t0ve.mjs +0 -443
- package/dist/setup-Bc73t0ve.mjs.map +0 -1
- package/dist/setup-C48C9hto.cjs +0 -473
- package/dist/setup-C48C9hto.cjs.map +0 -1
- package/dist/setup-DCuudnCl.mjs +0 -11
- package/dist/setup-fG_ivuxO.cjs +0 -11
- package/dist/storage-BJmzYxt8.cjs.map +0 -1
- package/dist/storage-BM9hGpgv.cjs +0 -7
- package/dist/storage-Bi24WfoW.mjs.map +0 -1
- package/dist/storage-CYlGwWTj.mjs +0 -3
- package/dist/sync-CmEuNZsB.mjs +0 -76
- package/dist/sync-CmEuNZsB.mjs.map +0 -1
- package/dist/sync-D306yOWu.cjs +0 -4
- package/dist/sync-SizaChmC.cjs +0 -93
- package/dist/sync-SizaChmC.cjs.map +0 -1
- package/dist/sync-hOqAWHR6.mjs +0 -3
- package/dist/types-C-arnQ1r.d.mts +0 -2184
- package/dist/types-C-arnQ1r.d.mts.map +0 -1
- package/dist/types-abJQuk7m.d.cts +0 -2184
- package/dist/types-abJQuk7m.d.cts.map +0 -1
- package/dist/workspace-7FqprxuJ.mjs +0 -4323
- package/dist/workspace-7FqprxuJ.mjs.map +0 -1
- package/dist/workspace-BO_KWohI.cjs +0 -9
- package/dist/workspace-DK4WWJIn.mjs +0 -8
- package/dist/workspace-XvqO9jIv.cjs +0 -4472
- package/dist/workspace-XvqO9jIv.cjs.map +0 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as EmailBackend, t as CacheBackend } from "../types-N7c2O2m7.cjs";
|
|
2
2
|
import { ConstructManifest, Declaration, RouteInfo } from "@geekmidas/manifest";
|
|
3
|
-
|
|
4
3
|
//#region src/reconcile/discover.d.ts
|
|
5
|
-
|
|
6
4
|
/** The construct face discovery needs: an id, and the ability to declare. */
|
|
7
5
|
interface Declarable {
|
|
8
6
|
id: string;
|
|
@@ -15,7 +13,7 @@ interface Declarable {
|
|
|
15
13
|
* `service` is still a construct, and requiring one would exclude the kinds that
|
|
16
14
|
* own no address.
|
|
17
15
|
*/
|
|
18
|
-
declare function isDeclarable(value: unknown): value is Declarable;
|
|
16
|
+
export declare function isDeclarable(value: unknown): value is Declarable;
|
|
19
17
|
interface DiscoverOptions {
|
|
20
18
|
/** The glob(s) to search. One pattern, not one per kind. */
|
|
21
19
|
patterns: string | readonly string[];
|
|
@@ -55,12 +53,11 @@ interface ConstructSource {
|
|
|
55
53
|
*
|
|
56
54
|
* @throws {DuplicateConstruct} when two exports claim one id.
|
|
57
55
|
*/
|
|
58
|
-
declare function discover(options: DiscoverOptions): Promise<ConstructManifest>;
|
|
59
|
-
/** Two constructs claiming one id. */
|
|
56
|
+
export declare function discover(options: DiscoverOptions): Promise<ConstructManifest>;
|
|
60
57
|
//#endregion
|
|
61
58
|
//#region src/reconcile/emit.d.ts
|
|
62
59
|
/** Where the build writes it, relative to the app root. */
|
|
63
|
-
declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
60
|
+
export declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
64
61
|
/**
|
|
65
62
|
* Fold the build's generated routes into the surface that serves them.
|
|
66
63
|
*
|
|
@@ -89,37 +86,22 @@ declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
|
89
86
|
* document's contents depend on which `--provider` ran last. A manifest must not
|
|
90
87
|
* do that.
|
|
91
88
|
*/
|
|
92
|
-
declare function withRoutes(manifest: ConstructManifest, routes: readonly RouteInfo[], options: {
|
|
89
|
+
export declare function withRoutes(manifest: ConstructManifest, routes: readonly RouteInfo[], options: {
|
|
93
90
|
perRoute: boolean;
|
|
94
91
|
}): ConstructManifest;
|
|
95
|
-
/**
|
|
96
|
-
* Fold in the compute the build generated: functions, crons, queue workers and
|
|
97
|
-
* topic subscribers.
|
|
98
|
-
*
|
|
99
|
-
* All four are named by their *export*, the same way an endpoint's handler is —
|
|
100
|
-
* `CronGenerator` uses the export key as the name — so none of them can declare
|
|
101
|
-
* themselves and all of them are the build's to add. That is why a `Function`
|
|
102
|
-
* has no `declare()` and never will.
|
|
103
|
-
*
|
|
104
|
-
* A worker and a subscriber **nest** inside the queue or topic that triggers
|
|
105
|
-
* them, because position carries the trigger. A function and a cron are
|
|
106
|
-
* top-level, because nothing triggers them but a caller or a clock.
|
|
107
|
-
*/
|
|
108
|
-
|
|
109
92
|
/**
|
|
110
93
|
* The manifest as TypeScript source.
|
|
111
94
|
*
|
|
112
95
|
* Pure, so what gets written can be asserted without touching a filesystem.
|
|
113
96
|
*/
|
|
114
|
-
declare function manifestModule(manifest: ConstructManifest, backends?: Backends): string;
|
|
97
|
+
export declare function manifestModule(manifest: ConstructManifest, backends?: Backends): string;
|
|
115
98
|
/** Write it where the deploy config expects to import it from. */
|
|
116
|
-
declare function writeManifestModule(manifest: ConstructManifest, appRoot: string, backends?: Backends): Promise<string>;
|
|
99
|
+
export declare function writeManifestModule(manifest: ConstructManifest, appRoot: string, backends?: Backends): Promise<string>;
|
|
117
100
|
/** The choices that are deployment config rather than declaration. */
|
|
118
101
|
interface Backends {
|
|
119
102
|
cache?: CacheBackend;
|
|
120
103
|
email?: EmailBackend;
|
|
121
104
|
}
|
|
122
|
-
//# sourceMappingURL=emit.d.ts.map
|
|
123
105
|
//#endregion
|
|
124
|
-
export { DiscoverOptions
|
|
106
|
+
export type { DiscoverOptions };
|
|
125
107
|
//# sourceMappingURL=public.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.cts","names":[],"sources":["../../src/reconcile/discover.ts","../../src/reconcile/emit.ts"],"
|
|
1
|
+
{"version":3,"file":"public.d.cts","names":[],"sources":["../../src/reconcile/discover.ts","../../src/reconcile/emit.ts"],"mappings":";;;;UA8BU;EACT;EACA,WAAW;;;;;;;;;wBAUI,aAAa,iBAAiB,SAAS;UAYtC;;EAEhB;EACA;;;;;;;EAOA;;;;;;;;;;;;EAYA,UAAU,eAAe;;;UAIT;;EAEhB;;EAEA;;;;;;;;;;wBAWqB,SACrB,SAAS,kBACP,QAAQ;;;;qBC5DE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8BG,WACf,UAAU,mBACV,iBAAiB,aACjB;EAAW;IACT;;;;;;wBA2Ja,eACf,UAAU,mBACV,WAAU;;wBA8BW,oBACrB,UAAU,mBACV,iBACA,WAAU,WACR;;UAUc;EAChB,QAAQ;EACR,QAAQ"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as EmailBackend, t as CacheBackend } from "../types-7R81hu0i.mjs";
|
|
2
2
|
import { ConstructManifest, Declaration, RouteInfo } from "@geekmidas/manifest";
|
|
3
|
-
|
|
4
3
|
//#region src/reconcile/discover.d.ts
|
|
5
|
-
|
|
6
4
|
/** The construct face discovery needs: an id, and the ability to declare. */
|
|
7
5
|
interface Declarable {
|
|
8
6
|
id: string;
|
|
@@ -15,7 +13,7 @@ interface Declarable {
|
|
|
15
13
|
* `service` is still a construct, and requiring one would exclude the kinds that
|
|
16
14
|
* own no address.
|
|
17
15
|
*/
|
|
18
|
-
declare function isDeclarable(value: unknown): value is Declarable;
|
|
16
|
+
export declare function isDeclarable(value: unknown): value is Declarable;
|
|
19
17
|
interface DiscoverOptions {
|
|
20
18
|
/** The glob(s) to search. One pattern, not one per kind. */
|
|
21
19
|
patterns: string | readonly string[];
|
|
@@ -55,12 +53,11 @@ interface ConstructSource {
|
|
|
55
53
|
*
|
|
56
54
|
* @throws {DuplicateConstruct} when two exports claim one id.
|
|
57
55
|
*/
|
|
58
|
-
declare function discover(options: DiscoverOptions): Promise<ConstructManifest>;
|
|
59
|
-
/** Two constructs claiming one id. */
|
|
56
|
+
export declare function discover(options: DiscoverOptions): Promise<ConstructManifest>;
|
|
60
57
|
//#endregion
|
|
61
58
|
//#region src/reconcile/emit.d.ts
|
|
62
59
|
/** Where the build writes it, relative to the app root. */
|
|
63
|
-
declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
60
|
+
export declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
64
61
|
/**
|
|
65
62
|
* Fold the build's generated routes into the surface that serves them.
|
|
66
63
|
*
|
|
@@ -89,37 +86,22 @@ declare const MANIFEST_PATH = ".gkm/manifest.ts";
|
|
|
89
86
|
* document's contents depend on which `--provider` ran last. A manifest must not
|
|
90
87
|
* do that.
|
|
91
88
|
*/
|
|
92
|
-
declare function withRoutes(manifest: ConstructManifest, routes: readonly RouteInfo[], options: {
|
|
89
|
+
export declare function withRoutes(manifest: ConstructManifest, routes: readonly RouteInfo[], options: {
|
|
93
90
|
perRoute: boolean;
|
|
94
91
|
}): ConstructManifest;
|
|
95
|
-
/**
|
|
96
|
-
* Fold in the compute the build generated: functions, crons, queue workers and
|
|
97
|
-
* topic subscribers.
|
|
98
|
-
*
|
|
99
|
-
* All four are named by their *export*, the same way an endpoint's handler is —
|
|
100
|
-
* `CronGenerator` uses the export key as the name — so none of them can declare
|
|
101
|
-
* themselves and all of them are the build's to add. That is why a `Function`
|
|
102
|
-
* has no `declare()` and never will.
|
|
103
|
-
*
|
|
104
|
-
* A worker and a subscriber **nest** inside the queue or topic that triggers
|
|
105
|
-
* them, because position carries the trigger. A function and a cron are
|
|
106
|
-
* top-level, because nothing triggers them but a caller or a clock.
|
|
107
|
-
*/
|
|
108
|
-
|
|
109
92
|
/**
|
|
110
93
|
* The manifest as TypeScript source.
|
|
111
94
|
*
|
|
112
95
|
* Pure, so what gets written can be asserted without touching a filesystem.
|
|
113
96
|
*/
|
|
114
|
-
declare function manifestModule(manifest: ConstructManifest, backends?: Backends): string;
|
|
97
|
+
export declare function manifestModule(manifest: ConstructManifest, backends?: Backends): string;
|
|
115
98
|
/** Write it where the deploy config expects to import it from. */
|
|
116
|
-
declare function writeManifestModule(manifest: ConstructManifest, appRoot: string, backends?: Backends): Promise<string>;
|
|
99
|
+
export declare function writeManifestModule(manifest: ConstructManifest, appRoot: string, backends?: Backends): Promise<string>;
|
|
117
100
|
/** The choices that are deployment config rather than declaration. */
|
|
118
101
|
interface Backends {
|
|
119
102
|
cache?: CacheBackend;
|
|
120
103
|
email?: EmailBackend;
|
|
121
104
|
}
|
|
122
|
-
//# sourceMappingURL=emit.d.ts.map
|
|
123
105
|
//#endregion
|
|
124
|
-
export { DiscoverOptions
|
|
106
|
+
export type { DiscoverOptions };
|
|
125
107
|
//# sourceMappingURL=public.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.mts","names":[],"sources":["../../src/reconcile/discover.ts","../../src/reconcile/emit.ts"],"
|
|
1
|
+
{"version":3,"file":"public.d.mts","names":[],"sources":["../../src/reconcile/discover.ts","../../src/reconcile/emit.ts"],"mappings":";;;;UA8BU;EACT;EACA,WAAW;;;;;;;;;wBAUI,aAAa,iBAAiB,SAAS;UAYtC;;EAEhB;EACA;;;;;;;EAOA;;;;;;;;;;;;EAYA,UAAU,eAAe;;;UAIT;;EAEhB;;EAEA;;;;;;;;;;wBAWqB,SACrB,SAAS,kBACP,QAAQ;;;;qBC5DE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8BG,WACf,UAAU,mBACV,iBAAiB,aACjB;EAAW;IACT;;;;;;wBA2Ja,eACf,UAAU,mBACV,WAAU;;wBA8BW,oBACrB,UAAU,mBACV,iBACA,WAAU,WACR;;UAUc;EAChB,QAAQ;EACR,QAAQ"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export { MANIFEST_PATH, discover, isDeclarable, manifestModule, withRoutes, writeManifestModule };
|
|
1
|
+
import { n as isDeclarable, t as discover } from "../discover-CK-n3w6b.mjs";
|
|
2
|
+
import { a as writeManifestModule, i as withRoutes, n as manifestModule, t as MANIFEST_PATH } from "../emit-Bzq7JsMP.mjs";
|
|
3
|
+
export { MANIFEST_PATH, discover, isDeclarable, manifestModule, withRoutes, writeManifestModule };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
|
+
import { i as generateSecurePassword } from "./generator-LfZU7NlU.mjs";
|
|
3
3
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
-
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
//#region src/setup/fullstack-secrets.ts
|
|
6
6
|
/**
|
|
7
7
|
* Generate a secure random password for database users.
|
|
@@ -15,22 +15,20 @@ function generateDbPassword() {
|
|
|
15
15
|
* All apps connect to the same database, but use different users/schemas.
|
|
16
16
|
*/
|
|
17
17
|
function generateDbUrl(appName, password, projectName, host = "localhost", port = 5432) {
|
|
18
|
-
|
|
19
|
-
const dbName = `${projectName.replace(/-/g, "_")}_dev`;
|
|
20
|
-
return `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;
|
|
18
|
+
return `postgresql://${appName.replace(/-/g, "_")}:${password}@${host}:${port}/${`${projectName.replace(/-/g, "_")}_dev`}`;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
21
|
* Generate fullstack-aware custom secrets for a workspace.
|
|
24
22
|
*
|
|
25
23
|
* Generates:
|
|
26
|
-
* - Common secrets:
|
|
24
|
+
* - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command
|
|
25
|
+
* decides that; see `gkm init`)
|
|
27
26
|
* - Per-app database passwords and URLs for backend apps with db service
|
|
28
27
|
* - Better-auth secrets for apps using the better-auth framework
|
|
29
28
|
*/
|
|
30
29
|
function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
31
30
|
const hasDb = containers.includes("postgres");
|
|
32
31
|
const customs = {
|
|
33
|
-
NODE_ENV: "development",
|
|
34
32
|
PORT: "3000",
|
|
35
33
|
LOG_LEVEL: "debug",
|
|
36
34
|
JWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
@@ -40,8 +38,8 @@ function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
|
40
38
|
for (const [appName, appConfig] of Object.entries(workspace.apps)) {
|
|
41
39
|
if (appConfig.type === "web") {
|
|
42
40
|
frontendPorts.push(appConfig.port);
|
|
43
|
-
const upperName
|
|
44
|
-
customs[`${upperName
|
|
41
|
+
const upperName = appName.toUpperCase();
|
|
42
|
+
customs[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;
|
|
45
43
|
continue;
|
|
46
44
|
}
|
|
47
45
|
if (appConfig.type === "mobile") continue;
|
|
@@ -56,10 +54,7 @@ function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
|
56
54
|
customs.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
|
-
if (customs.BETTER_AUTH_SECRET) {
|
|
60
|
-
const allPorts = Object.values(workspace.apps).map((a) => a.port);
|
|
61
|
-
customs.BETTER_AUTH_TRUSTED_ORIGINS = allPorts.map((p) => `http://localhost:${p}`).join(",");
|
|
62
|
-
}
|
|
57
|
+
if (customs.BETTER_AUTH_SECRET) customs.BETTER_AUTH_TRUSTED_ORIGINS = Object.values(workspace.apps).map((a) => a.port).map((p) => `http://localhost:${p}`).join(",");
|
|
63
58
|
return customs;
|
|
64
59
|
}
|
|
65
60
|
/**
|
|
@@ -81,7 +76,38 @@ ${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
|
81
76
|
await mkdir(dirname(envPath), { recursive: true });
|
|
82
77
|
await writeFile(envPath, envContent);
|
|
83
78
|
}
|
|
84
|
-
|
|
85
79
|
//#endregion
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
//#region src/secrets/reconcile.ts
|
|
81
|
+
var reconcile_exports = /* @__PURE__ */ __exportAll({ reconcileMissingSecrets: () => reconcileMissingSecrets });
|
|
82
|
+
/**
|
|
83
|
+
* Reconcile missing custom secrets for a workspace.
|
|
84
|
+
*
|
|
85
|
+
* Compares current secrets against what generateFullstackCustomSecrets()
|
|
86
|
+
* would produce and backfills any missing keys without overwriting
|
|
87
|
+
* existing values.
|
|
88
|
+
*
|
|
89
|
+
* @returns ReconcileResult if keys were added, null if secrets are up-to-date
|
|
90
|
+
*/
|
|
91
|
+
function reconcileMissingSecrets(secrets, workspace, containers = []) {
|
|
92
|
+
if (!(Object.keys(workspace.apps).length > 1)) return null;
|
|
93
|
+
const expectedCustom = generateFullstackCustomSecrets(workspace, containers);
|
|
94
|
+
const addedKeys = [];
|
|
95
|
+
const mergedCustom = { ...secrets.custom };
|
|
96
|
+
for (const [key, value] of Object.entries(expectedCustom)) if (!(key in mergedCustom)) {
|
|
97
|
+
mergedCustom[key] = value;
|
|
98
|
+
addedKeys.push(key);
|
|
99
|
+
}
|
|
100
|
+
if (addedKeys.length === 0) return null;
|
|
101
|
+
return {
|
|
102
|
+
secrets: {
|
|
103
|
+
...secrets,
|
|
104
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
|
+
custom: mergedCustom
|
|
106
|
+
},
|
|
107
|
+
addedKeys
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { writeDockerEnvFromSecrets as i, reconcile_exports as n, generateFullstackCustomSecrets as r, reconcileMissingSecrets as t };
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=reconcile-gb1lz1Dk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile-gb1lz1Dk.mjs","names":[],"sources":["../src/setup/fullstack-secrets.ts","../src/secrets/reconcile.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { generateSecurePassword } from '../secrets/generator.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/**\n * Generate a secure random password for database users.\n * Uses a combination of timestamp and random bytes for uniqueness.\n */\nexport function generateDbPassword(): string {\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Generate database URL for an app.\n * All apps connect to the same database, but use different users/schemas.\n */\nexport function generateDbUrl(\n\tappName: string,\n\tpassword: string,\n\tprojectName: string,\n\thost = 'localhost',\n\tport = 5432,\n): string {\n\tconst userName = appName.replace(/-/g, '_');\n\tconst dbName = `${projectName.replace(/-/g, '_')}_dev`;\n\treturn `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;\n}\n\n/**\n * Generate fullstack-aware custom secrets for a workspace.\n *\n * Generates:\n * - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command\n * decides that; see `gkm init`)\n * - Per-app database passwords and URLs for backend apps with db service\n * - Better-auth secrets for apps using the better-auth framework\n */\nexport function generateFullstackCustomSecrets(\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): Record<string, string> {\n\t// A Postgres exists because something declared a database, not because\n\t// config carried a flag saying so.\n\tconst hasDb = containers.includes('postgres');\n\tconst customs: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (!hasDb) {\n\t\treturn customs;\n\t}\n\n\t// Collect all frontend ports for trusted origins\n\tconst frontendPorts: number[] = [];\n\n\tfor (const [appName, appConfig] of Object.entries(workspace.apps)) {\n\t\tif (appConfig.type === 'web') {\n\t\t\tfrontendPorts.push(appConfig.port);\n\t\t\tconst upperName = appName.toUpperCase();\n\t\t\tcustoms[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mobile apps (Expo, etc.) don't run on a host port the backend\n\t\t// cares about for CORS, and don't need DB credentials.\n\t\tif (appConfig.type === 'mobile') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Backend apps with database: generate per-app DB passwords and URLs\n\t\tconst password = generateDbPassword();\n\t\tconst upperName = appName.toUpperCase();\n\n\t\tcustoms[`${upperName}_DATABASE_URL`] = generateDbUrl(\n\t\t\tappName,\n\t\t\tpassword,\n\t\t\tworkspace.name,\n\t\t);\n\t\tcustoms[`${upperName}_DB_PASSWORD`] = password;\n\n\t\t// Better-auth framework secrets\n\t\tif (appConfig.framework === 'better-auth') {\n\t\t\tcustoms.AUTH_PORT = String(appConfig.port);\n\t\t\tcustoms.AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t\tcustoms.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${generateSecurePassword(16)}`;\n\t\t\tcustoms.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t}\n\t}\n\n\t// Generate trusted origins for better-auth (all app ports)\n\tif (customs.BETTER_AUTH_SECRET) {\n\t\tconst allPorts = Object.values(workspace.apps).map((a) => a.port);\n\t\tcustoms.BETTER_AUTH_TRUSTED_ORIGINS = allPorts\n\t\t\t.map((p) => `http://localhost:${p}`)\n\t\t\t.join(',');\n\t}\n\n\treturn customs;\n}\n\n/**\n * Extract *_DB_PASSWORD keys from secrets and write docker/.env.\n *\n * The docker/.env file contains database passwords that the PostgreSQL\n * init script reads to create per-app database users.\n */\nexport async function writeDockerEnvFromSecrets(\n\tsecrets: StageSecrets,\n\tworkspaceRoot: string,\n): Promise<void> {\n\tconst dbPasswordEntries = Object.entries(secrets.custom).filter(([key]) =>\n\t\tkey.endsWith('_DB_PASSWORD'),\n\t);\n\n\t// Always include pgboss password when pgboss credentials exist\n\tif (\n\t\tsecrets.services.pgboss &&\n\t\t!dbPasswordEntries.some(([key]) => key === 'PGBOSS_DB_PASSWORD')\n\t) {\n\t\tdbPasswordEntries.push([\n\t\t\t'PGBOSS_DB_PASSWORD',\n\t\t\tsecrets.services.pgboss.password,\n\t\t]);\n\t}\n\n\tif (dbPasswordEntries.length === 0) {\n\t\treturn;\n\t}\n\n\tconst envContent = `# Auto-generated docker environment file\n# Contains database passwords for docker-compose postgres init\n# This file is gitignored - do not commit to version control\n${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join('\\n')}\n`;\n\n\tconst envPath = join(workspaceRoot, 'docker', '.env');\n\tawait mkdir(dirname(envPath), { recursive: true });\n\tawait writeFile(envPath, envContent);\n}\n","import { generateFullstackCustomSecrets } from '../setup/fullstack-secrets.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { StageSecrets } from './types.js';\n\nexport interface ReconcileResult {\n\t/** The updated secrets with missing keys backfilled */\n\tsecrets: StageSecrets;\n\t/** Keys that were added */\n\taddedKeys: string[];\n}\n\n/**\n * Reconcile missing custom secrets for a workspace.\n *\n * Compares current secrets against what generateFullstackCustomSecrets()\n * would produce and backfills any missing keys without overwriting\n * existing values.\n *\n * @returns ReconcileResult if keys were added, null if secrets are up-to-date\n */\nexport function reconcileMissingSecrets(\n\tsecrets: StageSecrets,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): ReconcileResult | null {\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (!isMultiApp) {\n\t\treturn null;\n\t}\n\n\tconst expectedCustom = generateFullstackCustomSecrets(workspace, containers);\n\tconst addedKeys: string[] = [];\n\tconst mergedCustom = { ...secrets.custom };\n\n\tfor (const [key, value] of Object.entries(expectedCustom)) {\n\t\tif (!(key in mergedCustom)) {\n\t\t\tmergedCustom[key] = value;\n\t\t\taddedKeys.push(key);\n\t\t}\n\t}\n\n\tif (addedKeys.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\tcustom: mergedCustom,\n\t\t},\n\t\taddedKeys,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
const require_generator = require(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
+
const require_generator = require("./generator-Wdfp0jCS.cjs");
|
|
3
|
+
let node_fs_promises = require("node:fs/promises");
|
|
4
|
+
let node_path = require("node:path");
|
|
6
5
|
//#region src/setup/fullstack-secrets.ts
|
|
7
6
|
/**
|
|
8
7
|
* Generate a secure random password for database users.
|
|
@@ -16,22 +15,20 @@ function generateDbPassword() {
|
|
|
16
15
|
* All apps connect to the same database, but use different users/schemas.
|
|
17
16
|
*/
|
|
18
17
|
function generateDbUrl(appName, password, projectName, host = "localhost", port = 5432) {
|
|
19
|
-
|
|
20
|
-
const dbName = `${projectName.replace(/-/g, "_")}_dev`;
|
|
21
|
-
return `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;
|
|
18
|
+
return `postgresql://${appName.replace(/-/g, "_")}:${password}@${host}:${port}/${`${projectName.replace(/-/g, "_")}_dev`}`;
|
|
22
19
|
}
|
|
23
20
|
/**
|
|
24
21
|
* Generate fullstack-aware custom secrets for a workspace.
|
|
25
22
|
*
|
|
26
23
|
* Generates:
|
|
27
|
-
* - Common secrets:
|
|
24
|
+
* - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command
|
|
25
|
+
* decides that; see `gkm init`)
|
|
28
26
|
* - Per-app database passwords and URLs for backend apps with db service
|
|
29
27
|
* - Better-auth secrets for apps using the better-auth framework
|
|
30
28
|
*/
|
|
31
29
|
function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
32
30
|
const hasDb = containers.includes("postgres");
|
|
33
31
|
const customs = {
|
|
34
|
-
NODE_ENV: "development",
|
|
35
32
|
PORT: "3000",
|
|
36
33
|
LOG_LEVEL: "debug",
|
|
37
34
|
JWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
@@ -41,8 +38,8 @@ function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
|
41
38
|
for (const [appName, appConfig] of Object.entries(workspace.apps)) {
|
|
42
39
|
if (appConfig.type === "web") {
|
|
43
40
|
frontendPorts.push(appConfig.port);
|
|
44
|
-
const upperName
|
|
45
|
-
customs[`${upperName
|
|
41
|
+
const upperName = appName.toUpperCase();
|
|
42
|
+
customs[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;
|
|
46
43
|
continue;
|
|
47
44
|
}
|
|
48
45
|
if (appConfig.type === "mobile") continue;
|
|
@@ -57,10 +54,7 @@ function generateFullstackCustomSecrets(workspace, containers = []) {
|
|
|
57
54
|
customs.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
|
-
if (customs.BETTER_AUTH_SECRET) {
|
|
61
|
-
const allPorts = Object.values(workspace.apps).map((a) => a.port);
|
|
62
|
-
customs.BETTER_AUTH_TRUSTED_ORIGINS = allPorts.map((p) => `http://localhost:${p}`).join(",");
|
|
63
|
-
}
|
|
57
|
+
if (customs.BETTER_AUTH_SECRET) customs.BETTER_AUTH_TRUSTED_ORIGINS = Object.values(workspace.apps).map((a) => a.port).map((p) => `http://localhost:${p}`).join(",");
|
|
64
58
|
return customs;
|
|
65
59
|
}
|
|
66
60
|
/**
|
|
@@ -82,30 +76,61 @@ ${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
|
82
76
|
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(envPath), { recursive: true });
|
|
83
77
|
await (0, node_fs_promises.writeFile)(envPath, envContent);
|
|
84
78
|
}
|
|
85
|
-
|
|
86
79
|
//#endregion
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
80
|
+
//#region src/secrets/reconcile.ts
|
|
81
|
+
var reconcile_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ reconcileMissingSecrets: () => reconcileMissingSecrets });
|
|
82
|
+
/**
|
|
83
|
+
* Reconcile missing custom secrets for a workspace.
|
|
84
|
+
*
|
|
85
|
+
* Compares current secrets against what generateFullstackCustomSecrets()
|
|
86
|
+
* would produce and backfills any missing keys without overwriting
|
|
87
|
+
* existing values.
|
|
88
|
+
*
|
|
89
|
+
* @returns ReconcileResult if keys were added, null if secrets are up-to-date
|
|
90
|
+
*/
|
|
91
|
+
function reconcileMissingSecrets(secrets, workspace, containers = []) {
|
|
92
|
+
if (!(Object.keys(workspace.apps).length > 1)) return null;
|
|
93
|
+
const expectedCustom = generateFullstackCustomSecrets(workspace, containers);
|
|
94
|
+
const addedKeys = [];
|
|
95
|
+
const mergedCustom = { ...secrets.custom };
|
|
96
|
+
for (const [key, value] of Object.entries(expectedCustom)) if (!(key in mergedCustom)) {
|
|
97
|
+
mergedCustom[key] = value;
|
|
98
|
+
addedKeys.push(key);
|
|
99
|
+
}
|
|
100
|
+
if (addedKeys.length === 0) return null;
|
|
101
|
+
return {
|
|
102
|
+
secrets: {
|
|
103
|
+
...secrets,
|
|
104
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
|
+
custom: mergedCustom
|
|
106
|
+
},
|
|
107
|
+
addedKeys
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
Object.defineProperty(exports, "generateFullstackCustomSecrets", {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
get: function() {
|
|
114
|
+
return generateFullstackCustomSecrets;
|
|
115
|
+
}
|
|
92
116
|
});
|
|
93
|
-
Object.defineProperty(exports,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
117
|
+
Object.defineProperty(exports, "reconcileMissingSecrets", {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
get: function() {
|
|
120
|
+
return reconcileMissingSecrets;
|
|
121
|
+
}
|
|
98
122
|
});
|
|
99
|
-
Object.defineProperty(exports,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
Object.defineProperty(exports, "reconcile_exports", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
get: function() {
|
|
126
|
+
return reconcile_exports;
|
|
127
|
+
}
|
|
104
128
|
});
|
|
105
|
-
Object.defineProperty(exports,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
129
|
+
Object.defineProperty(exports, "writeDockerEnvFromSecrets", {
|
|
130
|
+
enumerable: true,
|
|
131
|
+
get: function() {
|
|
132
|
+
return writeDockerEnvFromSecrets;
|
|
133
|
+
}
|
|
110
134
|
});
|
|
111
|
-
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=reconcile-hx_vBvux.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile-hx_vBvux.cjs","names":["generateSecurePassword","join","mkdir","dirname","writeFile"],"sources":["../src/setup/fullstack-secrets.ts","../src/secrets/reconcile.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { generateSecurePassword } from '../secrets/generator.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/**\n * Generate a secure random password for database users.\n * Uses a combination of timestamp and random bytes for uniqueness.\n */\nexport function generateDbPassword(): string {\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Generate database URL for an app.\n * All apps connect to the same database, but use different users/schemas.\n */\nexport function generateDbUrl(\n\tappName: string,\n\tpassword: string,\n\tprojectName: string,\n\thost = 'localhost',\n\tport = 5432,\n): string {\n\tconst userName = appName.replace(/-/g, '_');\n\tconst dbName = `${projectName.replace(/-/g, '_')}_dev`;\n\treturn `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;\n}\n\n/**\n * Generate fullstack-aware custom secrets for a workspace.\n *\n * Generates:\n * - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command\n * decides that; see `gkm init`)\n * - Per-app database passwords and URLs for backend apps with db service\n * - Better-auth secrets for apps using the better-auth framework\n */\nexport function generateFullstackCustomSecrets(\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): Record<string, string> {\n\t// A Postgres exists because something declared a database, not because\n\t// config carried a flag saying so.\n\tconst hasDb = containers.includes('postgres');\n\tconst customs: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (!hasDb) {\n\t\treturn customs;\n\t}\n\n\t// Collect all frontend ports for trusted origins\n\tconst frontendPorts: number[] = [];\n\n\tfor (const [appName, appConfig] of Object.entries(workspace.apps)) {\n\t\tif (appConfig.type === 'web') {\n\t\t\tfrontendPorts.push(appConfig.port);\n\t\t\tconst upperName = appName.toUpperCase();\n\t\t\tcustoms[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mobile apps (Expo, etc.) don't run on a host port the backend\n\t\t// cares about for CORS, and don't need DB credentials.\n\t\tif (appConfig.type === 'mobile') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Backend apps with database: generate per-app DB passwords and URLs\n\t\tconst password = generateDbPassword();\n\t\tconst upperName = appName.toUpperCase();\n\n\t\tcustoms[`${upperName}_DATABASE_URL`] = generateDbUrl(\n\t\t\tappName,\n\t\t\tpassword,\n\t\t\tworkspace.name,\n\t\t);\n\t\tcustoms[`${upperName}_DB_PASSWORD`] = password;\n\n\t\t// Better-auth framework secrets\n\t\tif (appConfig.framework === 'better-auth') {\n\t\t\tcustoms.AUTH_PORT = String(appConfig.port);\n\t\t\tcustoms.AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t\tcustoms.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${generateSecurePassword(16)}`;\n\t\t\tcustoms.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t}\n\t}\n\n\t// Generate trusted origins for better-auth (all app ports)\n\tif (customs.BETTER_AUTH_SECRET) {\n\t\tconst allPorts = Object.values(workspace.apps).map((a) => a.port);\n\t\tcustoms.BETTER_AUTH_TRUSTED_ORIGINS = allPorts\n\t\t\t.map((p) => `http://localhost:${p}`)\n\t\t\t.join(',');\n\t}\n\n\treturn customs;\n}\n\n/**\n * Extract *_DB_PASSWORD keys from secrets and write docker/.env.\n *\n * The docker/.env file contains database passwords that the PostgreSQL\n * init script reads to create per-app database users.\n */\nexport async function writeDockerEnvFromSecrets(\n\tsecrets: StageSecrets,\n\tworkspaceRoot: string,\n): Promise<void> {\n\tconst dbPasswordEntries = Object.entries(secrets.custom).filter(([key]) =>\n\t\tkey.endsWith('_DB_PASSWORD'),\n\t);\n\n\t// Always include pgboss password when pgboss credentials exist\n\tif (\n\t\tsecrets.services.pgboss &&\n\t\t!dbPasswordEntries.some(([key]) => key === 'PGBOSS_DB_PASSWORD')\n\t) {\n\t\tdbPasswordEntries.push([\n\t\t\t'PGBOSS_DB_PASSWORD',\n\t\t\tsecrets.services.pgboss.password,\n\t\t]);\n\t}\n\n\tif (dbPasswordEntries.length === 0) {\n\t\treturn;\n\t}\n\n\tconst envContent = `# Auto-generated docker environment file\n# Contains database passwords for docker-compose postgres init\n# This file is gitignored - do not commit to version control\n${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join('\\n')}\n`;\n\n\tconst envPath = join(workspaceRoot, 'docker', '.env');\n\tawait mkdir(dirname(envPath), { recursive: true });\n\tawait writeFile(envPath, envContent);\n}\n","import { generateFullstackCustomSecrets } from '../setup/fullstack-secrets.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { StageSecrets } from './types.js';\n\nexport interface ReconcileResult {\n\t/** The updated secrets with missing keys backfilled */\n\tsecrets: StageSecrets;\n\t/** Keys that were added */\n\taddedKeys: string[];\n}\n\n/**\n * Reconcile missing custom secrets for a workspace.\n *\n * Compares current secrets against what generateFullstackCustomSecrets()\n * would produce and backfills any missing keys without overwriting\n * existing values.\n *\n * @returns ReconcileResult if keys were added, null if secrets are up-to-date\n */\nexport function reconcileMissingSecrets(\n\tsecrets: StageSecrets,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): ReconcileResult | null {\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (!isMultiApp) {\n\t\treturn null;\n\t}\n\n\tconst expectedCustom = generateFullstackCustomSecrets(workspace, containers);\n\tconst addedKeys: string[] = [];\n\tconst mergedCustom = { ...secrets.custom };\n\n\tfor (const [key, value] of Object.entries(expectedCustom)) {\n\t\tif (!(key in mergedCustom)) {\n\t\t\tmergedCustom[key] = value;\n\t\t\taddedKeys.push(key);\n\t\t}\n\t}\n\n\tif (addedKeys.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\tcustom: mergedCustom,\n\t\t},\n\t\taddedKeys,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __exportAll = (all, no_symbols) => {
|
|
5
|
+
let target = {};
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
13
|
+
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
14
|
+
//#endregion
|
|
15
|
+
export { __require as n, __exportAll as t };
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
//#region
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __exportAll = (all, no_symbols) => {
|
|
9
|
+
let target = {};
|
|
10
|
+
for (var name in all) __defProp(target, name, {
|
|
11
|
+
get: all[name],
|
|
12
|
+
enumerable: true
|
|
13
|
+
});
|
|
14
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
15
|
+
return target;
|
|
16
|
+
};
|
|
8
17
|
var __copyProps = (to, from, except, desc) => {
|
|
9
18
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
19
|
key = keys[i];
|
|
@@ -15,16 +24,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
24
|
}
|
|
16
25
|
return to;
|
|
17
26
|
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
27
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
19
28
|
value: mod,
|
|
20
29
|
enumerable: true
|
|
21
30
|
}) : target, mod));
|
|
22
|
-
|
|
23
31
|
//#endregion
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
Object.defineProperty(exports, "__exportAll", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function() {
|
|
35
|
+
return __exportAll;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(exports, "__toESM", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
get: function() {
|
|
41
|
+
return __toESM;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { GetParameterCommand, ParameterNotFound, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
2
|
+
//#region src/secrets/ssm.ts
|
|
3
|
+
/**
|
|
4
|
+
* A stage's secrets in SSM Parameter Store, in the stage's own AWS account.
|
|
5
|
+
*
|
|
6
|
+
* One parameter per stage, `/gkm/<project>/<stage>/secrets`, a SecureString —
|
|
7
|
+
* encrypted at rest by KMS, so nothing about it needs a key file anywhere.
|
|
8
|
+
* Which account it is in is whichever credentials are active: the stage's
|
|
9
|
+
* OIDC role in a deploy job, or `--profile` on a developer's machine. With
|
|
10
|
+
* staging and production in different accounts, each stage's secrets sit
|
|
11
|
+
* beside its infrastructure, and a staging role cannot read production's.
|
|
12
|
+
*/
|
|
13
|
+
/** The parameter a stage's secrets are kept in. */
|
|
14
|
+
function secretsParameterName(project, stage) {
|
|
15
|
+
return `/gkm/${project}/${stage}/secrets`;
|
|
16
|
+
}
|
|
17
|
+
var SsmSecretsStore = class {
|
|
18
|
+
options;
|
|
19
|
+
client;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.options = options;
|
|
22
|
+
}
|
|
23
|
+
async ssm() {
|
|
24
|
+
if (this.client) return this.client;
|
|
25
|
+
const config = { region: this.options.region };
|
|
26
|
+
if (this.options.profile) {
|
|
27
|
+
const { fromIni } = await import("@aws-sdk/credential-providers");
|
|
28
|
+
config.credentials = fromIni({ profile: this.options.profile });
|
|
29
|
+
}
|
|
30
|
+
if (this.options.endpoint) config.endpoint = this.options.endpoint;
|
|
31
|
+
this.client = new SSMClient(config);
|
|
32
|
+
return this.client;
|
|
33
|
+
}
|
|
34
|
+
async pull(stage) {
|
|
35
|
+
const ssm = await this.ssm();
|
|
36
|
+
try {
|
|
37
|
+
const { Parameter } = await ssm.send(new GetParameterCommand({
|
|
38
|
+
Name: secretsParameterName(this.options.project, stage),
|
|
39
|
+
WithDecryption: true
|
|
40
|
+
}));
|
|
41
|
+
return Parameter?.Value ? JSON.parse(Parameter.Value) : null;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error instanceof ParameterNotFound) return null;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async push(stage, secrets) {
|
|
48
|
+
await (await this.ssm()).send(new PutParameterCommand({
|
|
49
|
+
Name: secretsParameterName(this.options.project, stage),
|
|
50
|
+
Value: JSON.stringify(secrets),
|
|
51
|
+
Type: "SecureString",
|
|
52
|
+
Overwrite: true,
|
|
53
|
+
Description: `gkm secrets for ${this.options.project}/${stage}`
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { SsmSecretsStore };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=ssm-BKN1Cg4z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-BKN1Cg4z.mjs","names":[],"sources":["../src/secrets/ssm.ts"],"sourcesContent":["/**\n * A stage's secrets in SSM Parameter Store, in the stage's own AWS account.\n *\n * One parameter per stage, `/gkm/<project>/<stage>/secrets`, a SecureString —\n * encrypted at rest by KMS, so nothing about it needs a key file anywhere.\n * Which account it is in is whichever credentials are active: the stage's\n * OIDC role in a deploy job, or `--profile` on a developer's machine. With\n * staging and production in different accounts, each stage's secrets sit\n * beside its infrastructure, and a staging role cannot read production's.\n */\n\nimport {\n\tGetParameterCommand,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { SecretsStore } from './store.js';\nimport type { StageSecrets } from './types.js';\n\nexport interface SsmSecretsStoreOptions {\n\t/** The workspace name, which scopes the parameter path. */\n\tproject: string;\n\tregion: string;\n\t/**\n\t * A named AWS profile, resolved with `fromIni` only. The default chain\n\t * reads AWS_* from the environment first, so exported staging keys would\n\t * win over `--profile prod` and put production's secrets in staging.\n\t */\n\tprofile?: string;\n\t/** For tests: an endpoint such as the AWS emulator. */\n\tendpoint?: string;\n}\n\n/** The parameter a stage's secrets are kept in. */\nexport function secretsParameterName(project: string, stage: string): string {\n\treturn `/gkm/${project}/${stage}/secrets`;\n}\n\nexport class SsmSecretsStore implements SecretsStore {\n\tprivate client?: SSMClient;\n\n\tconstructor(private readonly options: SsmSecretsStoreOptions) {}\n\n\tprivate async ssm(): Promise<SSMClient> {\n\t\tif (this.client) return this.client;\n\n\t\tconst config: SSMClientConfig = { region: this.options.region };\n\t\tif (this.options.profile) {\n\t\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: this.options.profile });\n\t\t}\n\t\tif (this.options.endpoint) {\n\t\t\tconfig.endpoint = this.options.endpoint;\n\t\t}\n\n\t\tthis.client = new SSMClient(config);\n\t\treturn this.client;\n\t}\n\n\tasync pull(stage: string): Promise<StageSecrets | null> {\n\t\tconst ssm = await this.ssm();\n\n\t\ttry {\n\t\t\tconst { Parameter } = await ssm.send(\n\t\t\t\tnew GetParameterCommand({\n\t\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\t\tWithDecryption: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn Parameter?.Value\n\t\t\t\t? (JSON.parse(Parameter.Value) as StageSecrets)\n\t\t\t\t: null;\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync push(stage: string, secrets: StageSecrets): Promise<void> {\n\t\tconst ssm = await this.ssm();\n\n\t\tawait ssm.send(\n\t\t\tnew PutParameterCommand({\n\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\tValue: JSON.stringify(secrets),\n\t\t\t\tType: 'SecureString',\n\t\t\t\tOverwrite: true,\n\t\t\t\tDescription: `gkm secrets for ${this.options.project}/${stage}`,\n\t\t\t}),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;AAoCA,SAAgB,qBAAqB,SAAiB,OAAuB;CAC5E,OAAO,QAAQ,QAAQ,GAAG,MAAM;AACjC;AAEA,IAAa,kBAAb,MAAqD;CAGvB;CAF7B;CAEA,YAAY,SAAkD;EAAjC,KAAA,UAAA;CAAkC;CAE/D,MAAc,MAA0B;EACvC,IAAI,KAAK,QAAQ,OAAO,KAAK;EAE7B,MAAM,SAA0B,EAAE,QAAQ,KAAK,QAAQ,OAAO;EAC9D,IAAI,KAAK,QAAQ,SAAS;GACzB,MAAM,EAAE,YAAY,MAAM,OAAO;GACjC,OAAO,cAAc,QAAQ,EAAE,SAAS,KAAK,QAAQ,QAAQ,CAAC;EAC/D;EACA,IAAI,KAAK,QAAQ,UAChB,OAAO,WAAW,KAAK,QAAQ;EAGhC,KAAK,SAAS,IAAI,UAAU,MAAM;EAClC,OAAO,KAAK;CACb;CAEA,MAAM,KAAK,OAA6C;EACvD,MAAM,MAAM,MAAM,KAAK,IAAI;EAE3B,IAAI;GACH,MAAM,EAAE,cAAc,MAAM,IAAI,KAC/B,IAAI,oBAAoB;IACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;IACtD,gBAAgB;GACjB,CAAC,CACF;GACA,OAAO,WAAW,QACd,KAAK,MAAM,UAAU,KAAK,IAC3B;EACJ,SAAS,OAAO;GACf,IAAI,iBAAiB,mBAAmB,OAAO;GAC/C,MAAM;EACP;CACD;CAEA,MAAM,KAAK,OAAe,SAAsC;EAG/D,OAAM,MAFY,KAAK,IAAI,EAAA,CAEjB,KACT,IAAI,oBAAoB;GACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;GACtD,OAAO,KAAK,UAAU,OAAO;GAC7B,MAAM;GACN,WAAW;GACX,aAAa,mBAAmB,KAAK,QAAQ,QAAQ,GAAG;EACzD,CAAC,CACF;CACD;AACD"}
|