@geekmidas/cli 10.0.0-alpha.72 → 10.0.0-alpha.74
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/{OpenApiTsGenerator-BlP53kf2.cjs → EndpointGenerator-CP6sBvQV.cjs} +4 -510
- package/dist/EndpointGenerator-CP6sBvQV.cjs.map +1 -0
- package/dist/{OpenApiTsGenerator-Dv0gT2DL.mjs → EndpointGenerator-DftalLYg.mjs} +3 -509
- package/dist/EndpointGenerator-DftalLYg.mjs.map +1 -0
- package/dist/{LegacyStateStore-NSHEinQi.mjs → LegacyStateStore-DTo7z924.mjs} +2 -2
- package/dist/{LegacyStateStore-NSHEinQi.mjs.map → LegacyStateStore-DTo7z924.mjs.map} +1 -1
- package/dist/{LegacyStateStore-Dd5IwiyC.cjs → LegacyStateStore-D_78eaHM.cjs} +2 -2
- package/dist/{LegacyStateStore-Dd5IwiyC.cjs.map → LegacyStateStore-D_78eaHM.cjs.map} +1 -1
- package/dist/{LocalStateStore-DTylG4T4.cjs → LocalStateStore-BhrlQIXD.cjs} +2 -2
- package/dist/{LocalStateStore-DTylG4T4.cjs.map → LocalStateStore-BhrlQIXD.cjs.map} +1 -1
- package/dist/{LocalStateStore-DUoG2wA_.mjs → LocalStateStore-CNjgkRk4.mjs} +2 -2
- package/dist/{LocalStateStore-DUoG2wA_.mjs.map → LocalStateStore-CNjgkRk4.mjs.map} +1 -1
- package/dist/OpenApiTsGenerator-CKBCckKz.cjs +514 -0
- package/dist/OpenApiTsGenerator-CKBCckKz.cjs.map +1 -0
- package/dist/OpenApiTsGenerator-nu1r1NgB.mjs +509 -0
- package/dist/OpenApiTsGenerator-nu1r1NgB.mjs.map +1 -0
- package/dist/{S3StateStore-Dxob3PNA.mjs → S3StateStore-g2P7T_Mo.mjs} +2 -2
- package/dist/{S3StateStore-Dxob3PNA.mjs.map → S3StateStore-g2P7T_Mo.mjs.map} +1 -1
- package/dist/{S3StateStore-D7hrU-sy.cjs → S3StateStore-oCxRs6HM.cjs} +2 -2
- package/dist/{S3StateStore-D7hrU-sy.cjs.map → S3StateStore-oCxRs6HM.cjs.map} +1 -1
- package/dist/{SSMStateStore-Dvl4A8Up.mjs → SSMStateStore-CYenunmK.mjs} +2 -2
- package/dist/{SSMStateStore-Dvl4A8Up.mjs.map → SSMStateStore-CYenunmK.mjs.map} +1 -1
- package/dist/{SSMStateStore-DGIKJ4NN.cjs → SSMStateStore-DXp0m7XI.cjs} +2 -2
- package/dist/{SSMStateStore-DGIKJ4NN.cjs.map → SSMStateStore-DXp0m7XI.cjs.map} +1 -1
- package/dist/SubscriberGenerator-5looQ3gB.mjs +448 -0
- package/dist/SubscriberGenerator-5looQ3gB.mjs.map +1 -0
- package/dist/SubscriberGenerator-CajwOa5W.cjs +489 -0
- package/dist/SubscriberGenerator-CajwOa5W.cjs.map +1 -0
- package/dist/{add-XTLU19_E.mjs → add-BTH7WaH3.mjs} +4 -4
- package/dist/{add-XTLU19_E.mjs.map → add-BTH7WaH3.mjs.map} +1 -1
- package/dist/{add-DeC2Kyyv.cjs → add-Djrr12Xc.cjs} +4 -4
- package/dist/{add-DeC2Kyyv.cjs.map → add-Djrr12Xc.cjs.map} +1 -1
- package/dist/{bundler-CNTVLCCA.mjs → bundler-BUojOkof.mjs} +6 -6
- package/dist/bundler-BUojOkof.mjs.map +1 -0
- package/dist/{bundler-CEaR6Dpb.cjs → bundler-utHuESvL.cjs} +6 -6
- package/dist/bundler-utHuESvL.cjs.map +1 -0
- package/dist/{cli-MMgBrHx7.cjs → cli-Bx0sUzxH.cjs} +4 -4
- package/dist/{cli-MMgBrHx7.cjs.map → cli-Bx0sUzxH.cjs.map} +1 -1
- package/dist/{cli-D1arS0p1.mjs → cli-CyYceKTS.mjs} +4 -4
- package/dist/{cli-D1arS0p1.mjs.map → cli-CyYceKTS.mjs.map} +1 -1
- package/dist/{compose-T3hnnjKZ.mjs → compose-DZp8DJ0A.mjs} +419 -70
- package/dist/compose-DZp8DJ0A.mjs.map +1 -0
- package/dist/{compose-B-MME-4C.cjs → compose-iuw8wfHk.cjs} +420 -71
- package/dist/compose-iuw8wfHk.cjs.map +1 -0
- package/dist/{config-j9zBKaEG.d.cts → config-B38YWicj.d.cts} +3 -3
- package/dist/{config-BN6iXvyR.d.mts.map → config-B38YWicj.d.cts.map} +1 -1
- package/dist/{config-BN6iXvyR.d.mts → config-DA0kRTQe.d.mts} +3 -3
- package/dist/{config-j9zBKaEG.d.cts.map → config-DA0kRTQe.d.mts.map} +1 -1
- package/dist/config.cjs +4 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +4 -1
- package/dist/config.mjs.map +1 -1
- package/dist/{credentialSchemas-BmYxnEz_.mjs → credentialSchemas-BJqRJNK4.mjs} +2 -2
- package/dist/{credentialSchemas-BmYxnEz_.mjs.map → credentialSchemas-BJqRJNK4.mjs.map} +1 -1
- package/dist/{credentialSchemas-BcNL1N5R.cjs → credentialSchemas-DCR4Wd1W.cjs} +2 -2
- package/dist/{credentialSchemas-BcNL1N5R.cjs.map → credentialSchemas-DCR4Wd1W.cjs.map} +1 -1
- package/dist/deploy/public.cjs +7 -7
- package/dist/deploy/public.d.cts +4 -4
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +4 -4
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +7 -7
- package/dist/deploy/sniffer-routes-worker.cjs +2 -2
- package/dist/deploy/sniffer-routes-worker.mjs +2 -2
- package/dist/{deploy-ClC53rc6.mjs → deploy-C17K7Imy.mjs} +12 -6
- package/dist/deploy-C17K7Imy.mjs.map +1 -0
- package/dist/{deploy-CZE0m6jd.cjs → deploy-eWorhvQp.cjs} +12 -6
- package/dist/deploy-eWorhvQp.cjs.map +1 -0
- package/dist/{discover-Buwf1z4P.mjs → discover-BPelzeGW.mjs} +21 -2
- package/dist/discover-BPelzeGW.mjs.map +1 -0
- package/dist/{discover-B_IkPukx.d.cts → discover-CU0paUyH.d.cts} +10 -1
- package/dist/discover-CU0paUyH.d.cts.map +1 -0
- package/dist/{discover-B4VjaFJk.cjs → discover-D1It5r_h.cjs} +21 -2
- package/dist/discover-D1It5r_h.cjs.map +1 -0
- package/dist/{discover-B6yPpvRV.d.mts → discover-DFiJxwfv.d.mts} +10 -1
- package/dist/discover-DFiJxwfv.d.mts.map +1 -0
- package/dist/{dokploy-D1UwQKm3.mjs → dokploy-DKa49Nqm.mjs} +2 -2
- package/dist/{dokploy-D1UwQKm3.mjs.map → dokploy-DKa49Nqm.mjs.map} +1 -1
- package/dist/{dokploy-lwmH05zr.cjs → dokploy-DKzcI-RL.cjs} +2 -2
- package/dist/{dokploy-lwmH05zr.cjs.map → dokploy-DKzcI-RL.cjs.map} +1 -1
- package/dist/drivers-BdvtCKc7.cjs +200 -0
- package/dist/drivers-BdvtCKc7.cjs.map +1 -0
- package/dist/drivers-Ch1rJitn.mjs +177 -0
- package/dist/drivers-Ch1rJitn.mjs.map +1 -0
- package/dist/{encryption-D05sNwED.cjs → encryption-DSkJdoyk.cjs} +2 -2
- package/dist/{encryption-D05sNwED.cjs.map → encryption-DSkJdoyk.cjs.map} +1 -1
- package/dist/{encryption-DcrxWl1s.mjs → encryption-sTMz3aWi.mjs} +2 -2
- package/dist/{encryption-DcrxWl1s.mjs.map → encryption-sTMz3aWi.mjs.map} +1 -1
- package/dist/{engine-DmQS3XHX.mjs → engine-B1b4I34Z.mjs} +117 -17
- package/dist/engine-B1b4I34Z.mjs.map +1 -0
- package/dist/{engine-Cry1vwMz.cjs → engine-Bh76sAHy.cjs} +117 -17
- package/dist/engine-Bh76sAHy.cjs.map +1 -0
- package/dist/{github-BchWoiVx.cjs → github-BvN3CfxM.cjs} +2 -2
- package/dist/{github-BchWoiVx.cjs.map → github-BvN3CfxM.cjs.map} +1 -1
- package/dist/{github-CqYOP8cI.mjs → github-C9ODoyZU.mjs} +2 -2
- package/dist/{github-CqYOP8cI.mjs.map → github-C9ODoyZU.mjs.map} +1 -1
- package/dist/{index-DvoxuTqR.d.mts → index-B-1lLGzy.d.mts} +2 -2
- package/dist/{index-Bk3NY6DN.d.cts.map → index-B-1lLGzy.d.mts.map} +1 -1
- package/dist/{index-Bk3NY6DN.d.cts → index-vMidfqhU.d.cts} +2 -2
- package/dist/{index-DvoxuTqR.d.mts.map → index-vMidfqhU.d.cts.map} +1 -1
- package/dist/index.cjs +130 -473
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +122 -465
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-qKeGYq21.cjs → migrate-B0FCZNkp.cjs} +3 -3
- package/dist/{migrate-qKeGYq21.cjs.map → migrate-B0FCZNkp.cjs.map} +1 -1
- package/dist/{migrate-guck0NJK.mjs → migrate-CTtJhGV9.mjs} +3 -3
- package/dist/{migrate-guck0NJK.mjs.map → migrate-CTtJhGV9.mjs.map} +1 -1
- package/dist/openapi.cjs +3 -2
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +2 -1
- package/dist/openapi.mjs.map +1 -1
- package/dist/ready-BB9xS4S9.cjs +402 -0
- package/dist/ready-BB9xS4S9.cjs.map +1 -0
- package/dist/ready-ZZoNskrr.mjs +373 -0
- package/dist/ready-ZZoNskrr.mjs.map +1 -0
- package/dist/reconcile/public.cjs +1 -1
- package/dist/reconcile/public.d.cts +2 -2
- package/dist/reconcile/public.d.mts +2 -2
- package/dist/reconcile/public.mjs +1 -1
- package/dist/{resolve-BsXEXAUz.mjs → resolve-DSAXj_47.mjs} +3 -3
- package/dist/{resolve-BsXEXAUz.mjs.map → resolve-DSAXj_47.mjs.map} +1 -1
- package/dist/{resolve-wEjEvbJ5.cjs → resolve-D_BU-wKA.cjs} +3 -3
- package/dist/{resolve-wEjEvbJ5.cjs.map → resolve-D_BU-wKA.cjs.map} +1 -1
- package/dist/{rollback-Bk91csFg.mjs → rollback-CWYTUhfW.mjs} +4 -4
- package/dist/{rollback-Bk91csFg.mjs.map → rollback-CWYTUhfW.mjs.map} +1 -1
- package/dist/{rollback-DmcU-efZ.cjs → rollback-DJy3t696.cjs} +4 -4
- package/dist/{rollback-DmcU-efZ.cjs.map → rollback-DJy3t696.cjs.map} +1 -1
- package/dist/{runtime-DHJhe4QI.d.mts → runtime-BzZD5HHi.d.cts} +2 -2
- package/dist/{runtime-CYAO4iZG.d.cts.map → runtime-BzZD5HHi.d.cts.map} +1 -1
- package/dist/{runtime-CYAO4iZG.d.cts → runtime-Cm6J6L7n.d.mts} +2 -2
- package/dist/{runtime-DHJhe4QI.d.mts.map → runtime-Cm6J6L7n.d.mts.map} +1 -1
- package/dist/sandbox/credentials-worker.cjs +2 -2
- package/dist/sandbox/credentials-worker.mjs +2 -2
- package/dist/sandbox/discover-worker.cjs +6 -3
- package/dist/sandbox/discover-worker.cjs.map +1 -1
- package/dist/sandbox/discover-worker.mjs +6 -3
- package/dist/sandbox/discover-worker.mjs.map +1 -1
- package/dist/sandbox/migrate-worker.cjs +1 -1
- package/dist/sandbox/migrate-worker.mjs +1 -1
- package/dist/{sniffer-vAXsU_4G.mjs → sniffer-BFmdZpZ2.mjs} +6 -6
- package/dist/{sniffer-vAXsU_4G.mjs.map → sniffer-BFmdZpZ2.mjs.map} +1 -1
- package/dist/{sniffer-DpHpFZBD.cjs → sniffer-C-T7dSMN.cjs} +6 -6
- package/dist/{sniffer-DpHpFZBD.cjs.map → sniffer-C-T7dSMN.cjs.map} +1 -1
- package/dist/{state-CCuTJNRH.cjs → state-DCwRWyh-.cjs} +954 -29
- package/dist/state-DCwRWyh-.cjs.map +1 -0
- package/dist/{state-BJFherj1.mjs → state-DpkxSwzI.mjs} +889 -24
- package/dist/state-DpkxSwzI.mjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{terminal-CFO3xWoF.cjs → terminal-BL5E0xbR.cjs} +2 -2
- package/dist/{terminal-CFO3xWoF.cjs.map → terminal-BL5E0xbR.cjs.map} +1 -1
- package/dist/{terminal-C6TBo_SA.mjs → terminal-BdvrmkaC.mjs} +2 -2
- package/dist/{terminal-C6TBo_SA.mjs.map → terminal-BdvrmkaC.mjs.map} +1 -1
- package/dist/{types-DkG5WW8l.d.mts → types-Dp9lgx_S.d.mts} +22 -2
- package/dist/types-Dp9lgx_S.d.mts.map +1 -0
- package/dist/{types-BD1jgA85.d.cts → types-TzCChNrA.d.cts} +22 -2
- package/dist/types-TzCChNrA.d.cts.map +1 -0
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace-C7NqCsQF.mjs.map +1 -1
- package/dist/workspace-vdrcRI-m.cjs.map +1 -1
- package/package.json +15 -15
- package/dist/OpenApiTsGenerator-BlP53kf2.cjs.map +0 -1
- package/dist/OpenApiTsGenerator-Dv0gT2DL.mjs.map +0 -1
- package/dist/bundler-CEaR6Dpb.cjs.map +0 -1
- package/dist/bundler-CNTVLCCA.mjs.map +0 -1
- package/dist/compose-B-MME-4C.cjs.map +0 -1
- package/dist/compose-T3hnnjKZ.mjs.map +0 -1
- package/dist/deploy-CZE0m6jd.cjs.map +0 -1
- package/dist/deploy-ClC53rc6.mjs.map +0 -1
- package/dist/discover-B4VjaFJk.cjs.map +0 -1
- package/dist/discover-B6yPpvRV.d.mts.map +0 -1
- package/dist/discover-B_IkPukx.d.cts.map +0 -1
- package/dist/discover-Buwf1z4P.mjs.map +0 -1
- package/dist/engine-Cry1vwMz.cjs.map +0 -1
- package/dist/engine-DmQS3XHX.mjs.map +0 -1
- package/dist/fakes-C9RiT6XG.mjs +0 -125
- package/dist/fakes-C9RiT6XG.mjs.map +0 -1
- package/dist/fakes-zW-jNAbQ.cjs +0 -148
- package/dist/fakes-zW-jNAbQ.cjs.map +0 -1
- package/dist/ready-B-7LayMF.cjs +0 -872
- package/dist/ready-B-7LayMF.cjs.map +0 -1
- package/dist/ready-ULc5BTOb.mjs +0 -819
- package/dist/ready-ULc5BTOb.mjs.map +0 -1
- package/dist/state-BJFherj1.mjs.map +0 -1
- package/dist/state-CCuTJNRH.cjs.map +0 -1
- package/dist/types-BD1jgA85.d.cts.map +0 -1
- package/dist/types-DkG5WW8l.d.mts.map +0 -1
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { r as discover } from "./discover-BPelzeGW.mjs";
|
|
2
|
+
import { t as EndpointGenerator } from "./EndpointGenerator-DftalLYg.mjs";
|
|
3
|
+
import { t as OpenApiTsGenerator } from "./OpenApiTsGenerator-nu1r1NgB.mjs";
|
|
4
|
+
import { n as readFakes, t as SubscriberGenerator } from "./SubscriberGenerator-5looQ3gB.mjs";
|
|
5
|
+
import { n as driversFor, r as eventsBackendsIn, t as cacheBackendsIn } from "./drivers-Ch1rJitn.mjs";
|
|
6
|
+
import { extname, join, relative } from "node:path";
|
|
7
|
+
import { mkdir, readdir, rm, writeFile } from "node:fs/promises";
|
|
8
|
+
import { canonicalId, kebabCase, provideKey, serviceKey } from "@geekmidas/manifest";
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
10
|
+
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
11
|
+
import { serviceContext } from "@geekmidas/services";
|
|
12
|
+
//#region src/test/harness.ts
|
|
13
|
+
/**
|
|
14
|
+
* What `gkm test` writes for a feature test to be built from.
|
|
15
|
+
*
|
|
16
|
+
* `gkm test` already discovers an app's constructs and resolves the test
|
|
17
|
+
* stage's environment; this keeps both, under `.gkm/test/`:
|
|
18
|
+
*
|
|
19
|
+
* - `manifest.json` — which construct and endpoint is exported where, and the
|
|
20
|
+
* environment the test stage resolved, keyed as the constructs derive keys.
|
|
21
|
+
* - `clients/<surface>.ts` — each surface's typed client, from the same
|
|
22
|
+
* generator `gkm build` uses for the app's own.
|
|
23
|
+
* - `index.ts` — the configured `it`, and a `Browser` holding one client per
|
|
24
|
+
* surface and one per auth server, each on the browser's `fetch`.
|
|
25
|
+
*
|
|
26
|
+
* A test imports `it` from there and declares nothing — not a construct, not an
|
|
27
|
+
* environment key, not a client.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* The variable the manifest's path travels in — what
|
|
31
|
+
* `@geekmidas/constructs/testing` reads. Its own constant rather than an import:
|
|
32
|
+
* that entry carries the whole harness (MSW, Hono, Vitest), and importing it
|
|
33
|
+
* here put all of it on the start-up path of every `gkm` command.
|
|
34
|
+
*/
|
|
35
|
+
const TEST_MANIFEST_ENV = "GKM_TEST_MANIFEST";
|
|
36
|
+
/** Where the harness lives, relative to the workspace root. */
|
|
37
|
+
const TEST_HARNESS_DIR = ".gkm/test";
|
|
38
|
+
/**
|
|
39
|
+
* Better-auth's client plugin for each server plugin id.
|
|
40
|
+
*
|
|
41
|
+
* Written down rather than derived: the ids and the client names do not follow
|
|
42
|
+
* one rule (`admin` pairs with `adminClient`, `email-otp` with
|
|
43
|
+
* `emailOTPClient`), and a guess that missed would hand a test a client
|
|
44
|
+
* silently lacking every method of that plugin. A server plugin not listed has
|
|
45
|
+
* no client counterpart — `bearer`, `open-api` — or needs one from another
|
|
46
|
+
* package, and is left out.
|
|
47
|
+
*/
|
|
48
|
+
const CLIENT_PLUGINS = {
|
|
49
|
+
admin: "adminClient",
|
|
50
|
+
anonymous: "anonymousClient",
|
|
51
|
+
"device-authorization": "deviceAuthorizationClient",
|
|
52
|
+
"email-otp": "emailOTPClient",
|
|
53
|
+
jwt: "jwtClient",
|
|
54
|
+
"last-login-method": "lastLoginMethodClient",
|
|
55
|
+
"magic-link": "magicLinkClient",
|
|
56
|
+
"multi-session": "multiSessionClient",
|
|
57
|
+
"oauth-popup": "oauthPopupClient",
|
|
58
|
+
"one-tap": "oneTapClient",
|
|
59
|
+
"one-time-token": "oneTimeTokenClient",
|
|
60
|
+
organization: "organizationClient",
|
|
61
|
+
"phone-number": "phoneNumberClient",
|
|
62
|
+
siwe: "siweClient",
|
|
63
|
+
"two-factor": "twoFactorClient",
|
|
64
|
+
username: "usernameClient"
|
|
65
|
+
};
|
|
66
|
+
/** Where a project keeps its test factories, relative to its root. */
|
|
67
|
+
const DEFAULT_FACTORIES_DIR = "test/factories";
|
|
68
|
+
/** A file in the factories folder that names no database construct. */
|
|
69
|
+
var UnknownFactoryFile = class extends Error {
|
|
70
|
+
file;
|
|
71
|
+
known;
|
|
72
|
+
constructor(file, known) {
|
|
73
|
+
super(`${file} names no database construct, so no test could be handed it. ` + (known.length > 0 ? `The databases: ${known.join(", ")}. ` : "This project declares no database. ") + `Name a factory after its database: test/factories/<construct>.ts.`);
|
|
74
|
+
this.file = file;
|
|
75
|
+
this.known = known;
|
|
76
|
+
this.name = "UnknownFactoryFile";
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/** A factory file that exports no `createFactory`. */
|
|
80
|
+
var FactoryHasNoCreate = class extends Error {
|
|
81
|
+
file;
|
|
82
|
+
constructor(file) {
|
|
83
|
+
super(`${file} is a test factory but exports no \`createFactory\`. Export \`function createFactory(db: Kysely<Database>)\` returning the factory.`);
|
|
84
|
+
this.file = file;
|
|
85
|
+
this.name = "FactoryHasNoCreate";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The factories in a folder, each matched to the database it is named after.
|
|
90
|
+
*
|
|
91
|
+
* A file that names no database, or exports no `createFactory`, is refused
|
|
92
|
+
* rather than skipped: either is a factory no test would ever be handed.
|
|
93
|
+
*/
|
|
94
|
+
async function factorySources(folder, databases) {
|
|
95
|
+
if (!folder) return [];
|
|
96
|
+
const entries = await readdir(folder, { withFileTypes: true }).catch((error) => {
|
|
97
|
+
if (error.code === "ENOENT") return [];
|
|
98
|
+
throw error;
|
|
99
|
+
});
|
|
100
|
+
const found = [];
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
if (!entry.isFile() || !isFactoryFile(entry.name)) continue;
|
|
103
|
+
const file = join(folder, entry.name);
|
|
104
|
+
const id = canonicalId(entry.name.slice(0, -extname(entry.name).length));
|
|
105
|
+
if (!databases.includes(id)) throw new UnknownFactoryFile(file, databases);
|
|
106
|
+
if (typeof (await import(pathToFileURL(file).href)).createFactory !== "function") throw new FactoryHasNoCreate(file);
|
|
107
|
+
found.push({
|
|
108
|
+
file,
|
|
109
|
+
service: serviceKey(id)
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return found.sort((a, b) => a.service < b.service ? -1 : 1);
|
|
113
|
+
}
|
|
114
|
+
function isFactoryFile(file) {
|
|
115
|
+
if (file.endsWith(".d.ts")) return false;
|
|
116
|
+
if (/\.(spec|test)\.[cm]?[jt]s$/.test(file)) return false;
|
|
117
|
+
return [
|
|
118
|
+
".ts",
|
|
119
|
+
".mts",
|
|
120
|
+
".js",
|
|
121
|
+
".mjs"
|
|
122
|
+
].includes(extname(file));
|
|
123
|
+
}
|
|
124
|
+
/** Write the manifest, the clients and the harness; return the manifest path. */
|
|
125
|
+
async function writeTestHarness(options) {
|
|
126
|
+
const sources = {};
|
|
127
|
+
const declared = await discover({
|
|
128
|
+
patterns: options.patterns,
|
|
129
|
+
cwd: options.root,
|
|
130
|
+
sources
|
|
131
|
+
});
|
|
132
|
+
const endpoints = (await new EndpointGenerator().load(options.patterns, options.root)).map(({ key, construct, path }) => ({
|
|
133
|
+
surface: construct.owner ?? construct.surface?.id,
|
|
134
|
+
construct,
|
|
135
|
+
source: {
|
|
136
|
+
file: path.absolute,
|
|
137
|
+
export: key
|
|
138
|
+
}
|
|
139
|
+
})).filter((endpoint) => endpoint.surface !== void 0);
|
|
140
|
+
const subscribers = (await new SubscriberGenerator().load(options.patterns, options.root)).map(({ key, path }) => ({ source: {
|
|
141
|
+
file: path.absolute,
|
|
142
|
+
export: key
|
|
143
|
+
} }));
|
|
144
|
+
const manifest = {
|
|
145
|
+
stage: options.stage,
|
|
146
|
+
constructs: Object.fromEntries(Object.entries(declared).flatMap(([id, declaration]) => {
|
|
147
|
+
const source = sources[id];
|
|
148
|
+
return source ? [[id, {
|
|
149
|
+
kind: declaration.kind,
|
|
150
|
+
source: {
|
|
151
|
+
file: source.file,
|
|
152
|
+
export: source.exportName
|
|
153
|
+
}
|
|
154
|
+
}]] : [];
|
|
155
|
+
})),
|
|
156
|
+
endpoints: endpoints.map(({ surface, source }) => ({
|
|
157
|
+
surface,
|
|
158
|
+
source
|
|
159
|
+
})),
|
|
160
|
+
subscribers,
|
|
161
|
+
env: options.env
|
|
162
|
+
};
|
|
163
|
+
const surfaces = [...new Set(endpoints.map(({ surface }) => surface))];
|
|
164
|
+
const generator = new OpenApiTsGenerator();
|
|
165
|
+
const clients = await Promise.all(surfaces.map(async (surface) => ({
|
|
166
|
+
file: `${kebabCase(surface)}.ts`,
|
|
167
|
+
content: await generator.generate(endpoints.filter((endpoint) => endpoint.surface === surface).map(({ construct }) => construct), {
|
|
168
|
+
title: surface,
|
|
169
|
+
version: "1.0.0"
|
|
170
|
+
})
|
|
171
|
+
})));
|
|
172
|
+
const auths = await authClients(declared, sources, options.env);
|
|
173
|
+
const drivers = driversFor({
|
|
174
|
+
appRoot: options.root,
|
|
175
|
+
cache: cacheBackendsIn(declared, options.cacheBackend),
|
|
176
|
+
events: eventsBackendsIn(declared, options.eventsBackend)
|
|
177
|
+
});
|
|
178
|
+
const owners = new Set(auths.map((auth) => auth.databaseId));
|
|
179
|
+
const databases = databaseSources(declared, sources).filter(({ id, kind }) => !owners.has(id) && kind !== "database-reader");
|
|
180
|
+
const factories = await factorySources(options.factories, databases.map(({ id }) => id));
|
|
181
|
+
const fakes = Object.entries(await readFakes(options.root, declared)).map(([id, { file }]) => ({
|
|
182
|
+
id,
|
|
183
|
+
file
|
|
184
|
+
}));
|
|
185
|
+
const services = serviceSources(declared, sources).filter(({ id }) => !owners.has(id));
|
|
186
|
+
const files = [.../* @__PURE__ */ new Set([
|
|
187
|
+
...Object.values(manifest.constructs).map(({ source }) => source.file),
|
|
188
|
+
...manifest.endpoints.map(({ source }) => source.file),
|
|
189
|
+
...(manifest.subscribers ?? []).map(({ source }) => source.file)
|
|
190
|
+
])];
|
|
191
|
+
const harnessFor = (dir) => harnessModule({
|
|
192
|
+
dir,
|
|
193
|
+
files,
|
|
194
|
+
databases,
|
|
195
|
+
surfaces: surfaces.map((id, index) => ({
|
|
196
|
+
id,
|
|
197
|
+
secured: clients[index].content.includes("authStrategies:")
|
|
198
|
+
})),
|
|
199
|
+
auths,
|
|
200
|
+
drivers,
|
|
201
|
+
factories,
|
|
202
|
+
fakes,
|
|
203
|
+
services,
|
|
204
|
+
mail: Object.values(declared).some(({ kind }) => kind === "email")
|
|
205
|
+
});
|
|
206
|
+
const json = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
207
|
+
return (await Promise.all([...new Set(options.targets)].map(async (target) => {
|
|
208
|
+
const dir = join(target, TEST_HARNESS_DIR);
|
|
209
|
+
await rm(dir, {
|
|
210
|
+
recursive: true,
|
|
211
|
+
force: true
|
|
212
|
+
});
|
|
213
|
+
await mkdir(join(dir, "clients"), { recursive: true });
|
|
214
|
+
await writeFile(join(dir, "manifest.json"), json);
|
|
215
|
+
await writeFile(join(dir, "index.ts"), harnessFor(dir));
|
|
216
|
+
for (const client of clients) await writeFile(join(dir, "clients", client.file), client.content);
|
|
217
|
+
return join(dir, "manifest.json");
|
|
218
|
+
})))[0];
|
|
219
|
+
}
|
|
220
|
+
/** Each auth server, with the client plugins its server plugins pair with. */
|
|
221
|
+
async function authClients(declared, sources, env) {
|
|
222
|
+
const clients = [];
|
|
223
|
+
const envParser = new EnvironmentParser({ ...env });
|
|
224
|
+
for (const [id, declaration] of Object.entries(declared)) {
|
|
225
|
+
const source = sources[id];
|
|
226
|
+
if (declaration.kind !== "rest-api" || !source) continue;
|
|
227
|
+
const exported = (await import(source.file))[source.exportName];
|
|
228
|
+
if (!isBetterAuth(exported) || exported.id !== id) continue;
|
|
229
|
+
const ids = await exported.pluginIds({
|
|
230
|
+
envParser,
|
|
231
|
+
context: serviceContext
|
|
232
|
+
});
|
|
233
|
+
clients.push({
|
|
234
|
+
id,
|
|
235
|
+
basePath: exported.basePath,
|
|
236
|
+
plugins: ids.flatMap((plugin) => CLIENT_PLUGINS[plugin] ?? []),
|
|
237
|
+
databaseId: exported.databaseId
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return clients;
|
|
241
|
+
}
|
|
242
|
+
function isBetterAuth(value) {
|
|
243
|
+
return typeof value === "object" && value !== null && "pluginIds" in value && "basePath" in value;
|
|
244
|
+
}
|
|
245
|
+
/** `Api` → `api`, `AdminApi` → `adminApi`: a construct id as a property name. */
|
|
246
|
+
function propertyOf(id) {
|
|
247
|
+
return id.charAt(0).toLowerCase() + id.slice(1);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Every database construct the app declares — a database, a schema tenant, a
|
|
251
|
+
* reader — keyed as a test is handed its transaction.
|
|
252
|
+
*/
|
|
253
|
+
function databaseSources(declared, sources) {
|
|
254
|
+
return Object.entries(declared).filter(([id, declaration]) => Boolean(sources[id] && declaration.kind.startsWith("database"))).map(([id, declaration]) => ({
|
|
255
|
+
id,
|
|
256
|
+
kind: declaration.kind,
|
|
257
|
+
service: serviceKey(id),
|
|
258
|
+
source: sources[id]
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
/** The kinds whose construct hands a handler a client — what `services` reaches. */
|
|
262
|
+
const SERVICE_KINDS = /* @__PURE__ */ new Set([
|
|
263
|
+
"cache",
|
|
264
|
+
"credential",
|
|
265
|
+
"database",
|
|
266
|
+
"database-schema",
|
|
267
|
+
"database-reader",
|
|
268
|
+
"email",
|
|
269
|
+
"encryption",
|
|
270
|
+
"external-api",
|
|
271
|
+
"file-server",
|
|
272
|
+
"objects",
|
|
273
|
+
"queue",
|
|
274
|
+
"topic"
|
|
275
|
+
]);
|
|
276
|
+
function serviceSources(declared, sources) {
|
|
277
|
+
return Object.entries(declared).filter(([id, declaration]) => Boolean(sources[id] && SERVICE_KINDS.has(declaration.kind))).map(([id, declaration]) => ({
|
|
278
|
+
id,
|
|
279
|
+
kind: declaration.kind,
|
|
280
|
+
service: serviceKey(id),
|
|
281
|
+
source: sources[id]
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
/** An import specifier for `file`, from the harness written into `dir`. */
|
|
285
|
+
function specifierFrom(dir, file) {
|
|
286
|
+
const path = relative(dir, file).replace(/\.tsx?$/, ".js");
|
|
287
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
288
|
+
}
|
|
289
|
+
function harnessModule(options) {
|
|
290
|
+
const { surfaces, auths, drivers, databases, services, dir, files, factories, fakes, mail } = options;
|
|
291
|
+
const magicLinks = mail ? auths.filter(({ plugins }) => plugins.includes("magicLinkClient")) : [];
|
|
292
|
+
const signIn = magicLinks.length === 1 ? magicLinks[0] : void 0;
|
|
293
|
+
const plugins = [...new Set(auths.flatMap(({ plugins }) => plugins))].sort();
|
|
294
|
+
const imports = [
|
|
295
|
+
`import {${services.length ? " type ClientOf," : ""}${databases.length ? " type DatabaseOf," : ""} featureTest, loadTestManifest${signIn ? ", signInWithMagicLink" : ""} } from '@geekmidas/constructs/testing';`,
|
|
296
|
+
...[...new Map([...databases, ...services].map((construct) => [construct.id, construct])).values()].map(({ id, source }) => `import type { ${source.exportName} as __${id} } from '${specifierFrom(dir, source.file)}';`),
|
|
297
|
+
`import { Browser as TestBrowser } from '@geekmidas/testkit/browser';`,
|
|
298
|
+
...surfaces.map(({ id }) => `import { createApi as create${id} } from './clients/${kebabCase(id)}.js';`),
|
|
299
|
+
...auths.length ? [`import { createAuthClient } from 'better-auth/client';`] : [],
|
|
300
|
+
...plugins.length ? [`import { ${plugins.join(", ")} } from 'better-auth/client/plugins';`] : [],
|
|
301
|
+
...drivers.imports ? [drivers.imports] : [],
|
|
302
|
+
...factories.map(({ file, service }) => `import { createFactory as __${service}Factory } from '${specifierFrom(dir, file)}';`),
|
|
303
|
+
...fakes.map(({ id, file }) => `import __${id}Fake from '${specifierFrom(dir, file)}';`),
|
|
304
|
+
...files.map((file, index) => `import * as __module${index} from '${specifierFrom(dir, file)}';`)
|
|
305
|
+
];
|
|
306
|
+
const url = (id) => `manifest.env[${JSON.stringify(provideKey(id, "url"))}]!`;
|
|
307
|
+
const members = [
|
|
308
|
+
...surfaces.map(({ id, secured }) => ` /** \`${id}\`, at ${provideKey(id, "url")}. */
|
|
309
|
+
readonly ${propertyOf(id)} = create${id}({
|
|
310
|
+
baseURL: ${url(id)},
|
|
311
|
+
fetch: this.fetch,${secured ? `
|
|
312
|
+
// Served in-process: no authorizer runs, so nothing is signed. A scheme
|
|
313
|
+
// with no strategy sends its request without credentials.
|
|
314
|
+
authStrategies: {} as never,` : ""}
|
|
315
|
+
});`),
|
|
316
|
+
...auths.map((auth) => ` /** \`${auth.id}\`, at ${provideKey(auth.id, "url")}. */
|
|
317
|
+
readonly ${propertyOf(auth.id)} = createAuthClient({
|
|
318
|
+
baseURL: \`\${${url(auth.id)}}${auth.basePath}\`,
|
|
319
|
+
plugins: [${auth.plugins.map((plugin) => `${plugin}()`).join(", ")}],
|
|
320
|
+
fetchOptions: { customFetchImpl: this.fetch },
|
|
321
|
+
});`),
|
|
322
|
+
...signIn ? [` /**
|
|
323
|
+
* Sign in as \`email\` through \`${signIn.id}\`'s magic link, the way a person
|
|
324
|
+
* does — the email opened, the link followed. The session it then reports.
|
|
325
|
+
* Without an address, as somebody new: \`user.email\` says who.
|
|
326
|
+
*/
|
|
327
|
+
signIn(email?: string) {
|
|
328
|
+
return signInWithMagicLink(this, this.${propertyOf(signIn.id)}, email);
|
|
329
|
+
}`] : []
|
|
330
|
+
];
|
|
331
|
+
const factoriesType = factories.length ? `{ ${factories.map(({ service }) => `${service}: typeof __${service}Factory`).join("; ")} }` : "";
|
|
332
|
+
const factoriesOption = factories.length ? `, factories: { ${factories.map(({ service }) => `${service}: __${service}Factory`).join(", ")} }` : "";
|
|
333
|
+
const fakesOption = fakes.length ? `, fakes: { ${fakes.map(({ id }) => `${id}: __${id}Fake`).join(", ")} }` : "";
|
|
334
|
+
const databasesType = `{ ${databases.map(({ id, service }) => `${service}: DatabaseOf<typeof __${id}>`).join("; ")} }`;
|
|
335
|
+
const servicesType = services.length ? `{ ${services.map(({ id, service }) => `${service}: ClientOf<typeof __${id}>`).join("; ")} }` : "";
|
|
336
|
+
const generics = databases.length || factoriesType || servicesType ? `<Browser, ${databases.length ? databasesType : "{}"}${factoriesType || servicesType ? `, ${factoriesType || "{}"}` : ""}${servicesType ? `, ${servicesType}` : ""}>` : "";
|
|
337
|
+
return `// Generated by \`gkm test\` from the app's constructs — do not edit.
|
|
338
|
+
${imports.join("\n")}
|
|
339
|
+
|
|
340
|
+
${drivers.setup ? `// The drivers the app's server entry registers, registered the same way.\n${drivers.setup}\n\n` : ""}const manifest = loadTestManifest(new URL('./manifest.json', import.meta.url));
|
|
341
|
+
|
|
342
|
+
/** A browser with a client for every surface the app declares. */
|
|
343
|
+
export class Browser extends TestBrowser {
|
|
344
|
+
${members.join("\n\n")}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** The app's modules, by the path the manifest records for each. */
|
|
348
|
+
const modules = {
|
|
349
|
+
${files.map((file, index) => `\t${JSON.stringify(file)}: __module${index},`).join("\n")}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/** \`it\`, for a test that drives the app the way it runs deployed. */
|
|
353
|
+
export const it = featureTest${generics}({ manifest, modules, browser: Browser${factoriesOption}${fakesOption} });
|
|
354
|
+
`;
|
|
355
|
+
}
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region src/test/ready.ts
|
|
358
|
+
/**
|
|
359
|
+
* The hand-off between `gkm test` and the Vitest global setup.
|
|
360
|
+
*
|
|
361
|
+
* `gkm test` reconciles and migrates the test stage before Vitest starts; the
|
|
362
|
+
* setup, run inside Vitest, only has to load what that left. Started by plain
|
|
363
|
+
* `vitest` instead, the setup runs `gkm test --setup` itself first — so there is
|
|
364
|
+
* one way the stage gets ready, whichever started the suite.
|
|
365
|
+
*/
|
|
366
|
+
/** Set on the Vitest process by `gkm test`: the stage is ready, here. */
|
|
367
|
+
const TEST_READY_ENV = "GKM_TEST_READY";
|
|
368
|
+
/** Where `gkm test` records what it prepared, from where it ran. */
|
|
369
|
+
const TEST_READY_FILE = ".gkm/test-ready.json";
|
|
370
|
+
//#endregion
|
|
371
|
+
export { writeTestHarness as a, TEST_MANIFEST_ENV as i, TEST_READY_FILE as n, DEFAULT_FACTORIES_DIR as r, TEST_READY_ENV as t };
|
|
372
|
+
|
|
373
|
+
//# sourceMappingURL=ready-ZZoNskrr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ready-ZZoNskrr.mjs","names":[],"sources":["../src/test/harness.ts","../src/test/ready.ts"],"sourcesContent":["/**\n * What `gkm test` writes for a feature test to be built from.\n *\n * `gkm test` already discovers an app's constructs and resolves the test\n * stage's environment; this keeps both, under `.gkm/test/`:\n *\n * - `manifest.json` — which construct and endpoint is exported where, and the\n * environment the test stage resolved, keyed as the constructs derive keys.\n * - `clients/<surface>.ts` — each surface's typed client, from the same\n * generator `gkm build` uses for the app's own.\n * - `index.ts` — the configured `it`, and a `Browser` holding one client per\n * surface and one per auth server, each on the browser's `fetch`.\n *\n * A test imports `it` from there and declares nothing — not a construct, not an\n * environment key, not a client.\n */\n\nimport { mkdir, readdir, rm, writeFile } from 'node:fs/promises';\nimport { extname, join, relative } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { BetterAuth } from '@geekmidas/constructs/auth';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { TestManifest } from '@geekmidas/constructs/testing';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport {\n\tcanonicalId,\n\tkebabCase,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport { serviceContext } from '@geekmidas/services';\nimport {\n\tcacheBackendsIn,\n\tdriversFor,\n\teventsBackendsIn,\n\ttype RuntimeDrivers,\n} from '../generators/drivers.js';\nimport { EndpointGenerator } from '../generators/EndpointGenerator.js';\nimport { OpenApiTsGenerator } from '../generators/OpenApiTsGenerator.js';\nimport { SubscriberGenerator } from '../generators/SubscriberGenerator.js';\nimport { type ConstructSource, discover } from '../reconcile/discover.js';\nimport { readFakes } from '../reconcile/fakes.js';\nimport type { CacheBackend, EventsBackend } from '../types.js';\n\n/**\n * The variable the manifest's path travels in — what\n * `@geekmidas/constructs/testing` reads. Its own constant rather than an import:\n * that entry carries the whole harness (MSW, Hono, Vitest), and importing it\n * here put all of it on the start-up path of every `gkm` command.\n */\nexport const TEST_MANIFEST_ENV = 'GKM_TEST_MANIFEST';\n\n/** Where the harness lives, relative to the workspace root. */\nexport const TEST_HARNESS_DIR = '.gkm/test';\n\n/**\n * Better-auth's client plugin for each server plugin id.\n *\n * Written down rather than derived: the ids and the client names do not follow\n * one rule (`admin` pairs with `adminClient`, `email-otp` with\n * `emailOTPClient`), and a guess that missed would hand a test a client\n * silently lacking every method of that plugin. A server plugin not listed has\n * no client counterpart — `bearer`, `open-api` — or needs one from another\n * package, and is left out.\n */\nconst CLIENT_PLUGINS: Readonly<Record<string, string>> = {\n\tadmin: 'adminClient',\n\tanonymous: 'anonymousClient',\n\t'device-authorization': 'deviceAuthorizationClient',\n\t'email-otp': 'emailOTPClient',\n\tjwt: 'jwtClient',\n\t'last-login-method': 'lastLoginMethodClient',\n\t'magic-link': 'magicLinkClient',\n\t'multi-session': 'multiSessionClient',\n\t'oauth-popup': 'oauthPopupClient',\n\t'one-tap': 'oneTapClient',\n\t'one-time-token': 'oneTimeTokenClient',\n\torganization: 'organizationClient',\n\t'phone-number': 'phoneNumberClient',\n\tsiwe: 'siweClient',\n\t'two-factor': 'twoFactorClient',\n\tusername: 'usernameClient',\n};\n\nexport interface WriteTestHarnessOptions {\n\t/** The workspace root: where discovery runs from. */\n\troot: string;\n\t/**\n\t * The directories to write `.gkm/test/` into — each app's own. A package\n\t * maps its `#test` import only to a path inside itself, so each app gets its\n\t * own copy of the harness rather than one at the root it cannot reach.\n\t */\n\ttargets: string[];\n\t/** The constructs glob — the same patterns reconcile and the build use. */\n\tpatterns: string[];\n\t/** The stage the environment was resolved for. */\n\tstage: string;\n\t/** The environment the suite runs with. */\n\tenv: Record<string, string>;\n\t/**\n\t * Where a cache lives when it names nowhere — the target's default, which\n\t * the build's server entry registers a driver for.\n\t */\n\tcacheBackend: CacheBackend;\n\t/**\n\t * The broker the target puts topics and queues on, which the server entry\n\t * registers a driver for when the app declares one.\n\t */\n\teventsBackend: EventsBackend;\n\t/**\n\t * The folder of test factories, absolute: `test/factories` at the root, or\n\t * where `test.factories` in the config points. Absent or empty, a test is\n\t * handed no factories.\n\t */\n\tfactories?: string;\n}\n\n/** Where a project keeps its test factories, relative to its root. */\nexport const DEFAULT_FACTORIES_DIR = 'test/factories';\n\n/** A file in the factories folder that names no database construct. */\nexport class UnknownFactoryFile extends Error {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${file} names no database construct, so no test could be handed it. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `The databases: ${known.join(', ')}. `\n\t\t\t\t\t: 'This project declares no database. ') +\n\t\t\t\t`Name a factory after its database: test/factories/<construct>.ts.`,\n\t\t);\n\t\tthis.name = 'UnknownFactoryFile';\n\t}\n}\n\n/** A factory file that exports no `createFactory`. */\nexport class FactoryHasNoCreate extends Error {\n\tconstructor(readonly file: string) {\n\t\tsuper(\n\t\t\t`${file} is a test factory but exports no \\`createFactory\\`. ` +\n\t\t\t\t`Export \\`function createFactory(db: Kysely<Database>)\\` returning ` +\n\t\t\t\t`the factory.`,\n\t\t);\n\t\tthis.name = 'FactoryHasNoCreate';\n\t}\n}\n\n/** One database's factory: the file, and the service name a test keys it by. */\nexport interface FactorySource {\n\tfile: string;\n\tservice: string;\n}\n\n/**\n * The factories in a folder, each matched to the database it is named after.\n *\n * A file that names no database, or exports no `createFactory`, is refused\n * rather than skipped: either is a factory no test would ever be handed.\n */\nexport async function factorySources(\n\tfolder: string | undefined,\n\tdatabases: readonly string[],\n): Promise<FactorySource[]> {\n\tif (!folder) return [];\n\n\tconst entries = await readdir(folder, { withFileTypes: true }).catch(\n\t\t(error: NodeJS.ErrnoException) => {\n\t\t\tif (error.code === 'ENOENT') return [];\n\t\t\tthrow error;\n\t\t},\n\t);\n\n\tconst found: FactorySource[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.isFile() || !isFactoryFile(entry.name)) continue;\n\n\t\tconst file = join(folder, entry.name);\n\t\tconst id = canonicalId(entry.name.slice(0, -extname(entry.name).length));\n\t\tif (!databases.includes(id)) {\n\t\t\tthrow new UnknownFactoryFile(file, databases);\n\t\t}\n\n\t\tconst module = (await import(pathToFileURL(file).href)) as {\n\t\t\tcreateFactory?: unknown;\n\t\t};\n\t\tif (typeof module.createFactory !== 'function') {\n\t\t\tthrow new FactoryHasNoCreate(file);\n\t\t}\n\n\t\tfound.push({ file, service: serviceKey(id) });\n\t}\n\n\treturn found.sort((a, b) => (a.service < b.service ? -1 : 1));\n}\n\nfunction isFactoryFile(file: string): boolean {\n\tif (file.endsWith('.d.ts')) return false;\n\tif (/\\.(spec|test)\\.[cm]?[jt]s$/.test(file)) return false;\n\treturn ['.ts', '.mts', '.js', '.mjs'].includes(extname(file));\n}\n\n/** Write the manifest, the clients and the harness; return the manifest path. */\nexport async function writeTestHarness(\n\toptions: WriteTestHarnessOptions,\n): Promise<string> {\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst declared = await discover({\n\t\tpatterns: options.patterns,\n\t\tcwd: options.root,\n\t\tsources,\n\t});\n\n\tconst loaded = await new EndpointGenerator().load(\n\t\toptions.patterns,\n\t\toptions.root,\n\t);\n\tconst endpoints = loaded\n\t\t.map(({ key, construct, path }) => ({\n\t\t\tsurface: construct.owner ?? construct.surface?.id,\n\t\t\tconstruct,\n\t\t\tsource: { file: path.absolute, export: key },\n\t\t}))\n\t\t.filter(\n\t\t\t(endpoint): endpoint is typeof endpoint & { surface: string } =>\n\t\t\t\tendpoint.surface !== undefined,\n\t\t);\n\n\t// Topic subscribers, which a test delivers to. Not constructs, so the build\n\t// finds them the way it finds endpoints.\n\tconst subscribers = (\n\t\tawait new SubscriberGenerator().load(options.patterns, options.root)\n\t).map(({ key, path }) => ({ source: { file: path.absolute, export: key } }));\n\n\tconst manifest: TestManifest = {\n\t\tstage: options.stage,\n\t\tconstructs: Object.fromEntries(\n\t\t\tObject.entries(declared).flatMap(([id, declaration]) => {\n\t\t\t\tconst source = sources[id];\n\t\t\t\treturn source\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tkind: declaration.kind,\n\t\t\t\t\t\t\t\t\tsource: { file: source.file, export: source.exportName },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\t}),\n\t\t),\n\t\tendpoints: endpoints.map(({ surface, source }) => ({ surface, source })),\n\t\tsubscribers,\n\t\tenv: options.env,\n\t};\n\t// One typed client per surface, from the generator the build uses.\n\tconst surfaces = [...new Set(endpoints.map(({ surface }) => surface))];\n\tconst generator = new OpenApiTsGenerator();\n\tconst clients = await Promise.all(\n\t\tsurfaces.map(async (surface) => ({\n\t\t\tfile: `${kebabCase(surface)}.ts`,\n\t\t\tcontent: await generator.generate(\n\t\t\t\tendpoints\n\t\t\t\t\t.filter((endpoint) => endpoint.surface === surface)\n\t\t\t\t\t.map(({ construct }) => construct as Endpoint<any, any, any, any>),\n\t\t\t\t{ title: surface, version: '1.0.0' },\n\t\t\t),\n\t\t})),\n\t);\n\n\tconst auths = await authClients(declared, sources, options.env);\n\t// The drivers the server entry registers — which cache and storage clients\n\t// exist is the entry's decision, and the harness stands where the entry does.\n\tconst drivers = driversFor({\n\t\tappRoot: options.root,\n\t\tcache: cacheBackendsIn(declared, options.cacheBackend),\n\t\tevents: eventsBackendsIn(declared, options.eventsBackend),\n\t});\n\n\t// The app's own databases: not a tenant an auth server owns — reached\n\t// through that server — and not a reader of one. What a test is handed.\n\tconst owners = new Set(auths.map((auth) => auth.databaseId));\n\tconst databases = databaseSources(declared, sources).filter(\n\t\t({ id, kind }) => !owners.has(id) && kind !== 'database-reader',\n\t);\n\tconst factories = await factorySources(\n\t\toptions.factories,\n\t\tdatabases.map(({ id }) => id),\n\t);\n\t// Each external API's fake, from the convention rather than the construct —\n\t// which is what keeps a fake out of every deployed bundle.\n\tconst fakes = Object.entries(await readFakes(options.root, declared)).map(\n\t\t([id, { file }]) => ({ id, file }),\n\t);\n\t// Every construct a handler can depend on — what a test reaches through\n\t// `services.get(…)`, typed by the client its service registers. A tenant an\n\t// auth server owns is reached through that server, as databases are.\n\tconst services = serviceSources(declared, sources).filter(\n\t\t({ id }) => !owners.has(id),\n\t);\n\tconst files = [\n\t\t...new Set([\n\t\t\t...Object.values(manifest.constructs).map(({ source }) => source.file),\n\t\t\t...manifest.endpoints.map(({ source }) => source.file),\n\t\t\t// Delivery loads each subscriber too. Left to a dynamic import, it is\n\t\t\t// resolved by Node — which knows nothing of the app's tsconfig paths, so\n\t\t\t// a subscriber importing `~/…` failed every test file that delivered.\n\t\t\t...(manifest.subscribers ?? []).map(({ source }) => source.file),\n\t\t]),\n\t];\n\tconst harnessFor = (dir: string) =>\n\t\tharnessModule({\n\t\t\tdir,\n\t\t\tfiles,\n\t\t\tdatabases,\n\t\t\tsurfaces: surfaces.map((id, index) => ({\n\t\t\t\tid,\n\t\t\t\t// The client the generator writes for a surface with authorizers\n\t\t\t\t// takes a strategy per scheme; one without takes none.\n\t\t\t\tsecured: clients[index]!.content.includes('authStrategies:'),\n\t\t\t})),\n\t\t\tauths,\n\t\t\tdrivers,\n\t\t\tfactories,\n\t\t\tfakes,\n\t\t\tservices,\n\t\t\tmail: Object.values(declared).some(({ kind }) => kind === 'email'),\n\t\t});\n\tconst json = `${JSON.stringify(manifest, null, 2)}\\n`;\n\n\tconst written = await Promise.all(\n\t\t[...new Set(options.targets)].map(async (target) => {\n\t\t\tconst dir = join(target, TEST_HARNESS_DIR);\n\t\t\t// Rewritten whole on every run: a client for a surface that no longer\n\t\t\t// exists is not something a test should be able to import.\n\t\t\tawait rm(dir, { recursive: true, force: true });\n\t\t\tawait mkdir(join(dir, 'clients'), { recursive: true });\n\t\t\tawait writeFile(join(dir, 'manifest.json'), json);\n\t\t\tawait writeFile(join(dir, 'index.ts'), harnessFor(dir));\n\t\t\tfor (const client of clients) {\n\t\t\t\tawait writeFile(join(dir, 'clients', client.file), client.content);\n\t\t\t}\n\t\t\treturn join(dir, 'manifest.json');\n\t\t}),\n\t);\n\n\treturn written[0]!;\n}\n\ninterface AuthClient {\n\tid: string;\n\tbasePath: string;\n\tplugins: string[];\n\t/** The schema tenant it owns — reached through it, never by a test. */\n\tdatabaseId: string;\n}\n\n/** Each auth server, with the client plugins its server plugins pair with. */\nasync function authClients(\n\tdeclared: Awaited<ReturnType<typeof discover>>,\n\tsources: Record<string, ConstructSource>,\n\tenv: Record<string, string>,\n): Promise<AuthClient[]> {\n\tconst clients: AuthClient[] = [];\n\tconst envParser = new EnvironmentParser({ ...env });\n\n\tfor (const [id, declaration] of Object.entries(declared)) {\n\t\tconst source = sources[id];\n\t\tif (declaration.kind !== 'rest-api' || !source) continue;\n\n\t\tconst exported = (await import(source.file))[source.exportName] as unknown;\n\t\tif (!isBetterAuth(exported) || exported.id !== id) continue;\n\n\t\tconst ids = await exported.pluginIds({\n\t\t\tenvParser,\n\t\t\tcontext: serviceContext,\n\t\t});\n\t\tclients.push({\n\t\t\tid,\n\t\t\tbasePath: exported.basePath,\n\t\t\tplugins: ids.flatMap((plugin) => CLIENT_PLUGINS[plugin] ?? []),\n\t\t\tdatabaseId: exported.databaseId,\n\t\t});\n\t}\n\n\treturn clients;\n}\n\nfunction isBetterAuth(value: unknown): value is BetterAuth {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'pluginIds' in value &&\n\t\t'basePath' in value\n\t);\n}\n\n/** `Api` → `api`, `AdminApi` → `adminApi`: a construct id as a property name. */\nfunction propertyOf(id: string): string {\n\treturn id.charAt(0).toLowerCase() + id.slice(1);\n}\n\n/**\n * The database a test's `db` is — the one the endpoints were given with\n * `.database()`, found by the service they hold, which is the construct's own.\n * The same rule `featureTest` applies at runtime, applied here so `db` can be\n * typed by the construct's schema.\n */\n/** A database construct: its id, its service name, and where it is exported. */\ninterface DatabaseSource {\n\tid: string;\n\tkind: string;\n\tservice: string;\n\tsource: ConstructSource;\n}\n\n/**\n * Every database construct the app declares — a database, a schema tenant, a\n * reader — keyed as a test is handed its transaction.\n */\nfunction databaseSources(\n\tdeclared: Awaited<ReturnType<typeof discover>>,\n\tsources: Record<string, ConstructSource>,\n): DatabaseSource[] {\n\treturn Object.entries(declared)\n\t\t.filter(([id, declaration]) =>\n\t\t\tBoolean(sources[id] && declaration.kind.startsWith('database')),\n\t\t)\n\t\t.map(([id, declaration]) => ({\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tservice: serviceKey(id),\n\t\t\tsource: sources[id]!,\n\t\t}));\n}\n\n/** The kinds whose construct hands a handler a client — what `services` reaches. */\nconst SERVICE_KINDS = new Set([\n\t'cache',\n\t'credential',\n\t'database',\n\t'database-schema',\n\t'database-reader',\n\t'email',\n\t'encryption',\n\t'external-api',\n\t'file-server',\n\t'objects',\n\t'queue',\n\t'topic',\n]);\n\nfunction serviceSources(\n\tdeclared: Awaited<ReturnType<typeof discover>>,\n\tsources: Record<string, ConstructSource>,\n): DatabaseSource[] {\n\treturn Object.entries(declared)\n\t\t.filter(([id, declaration]) =>\n\t\t\tBoolean(sources[id] && SERVICE_KINDS.has(declaration.kind)),\n\t\t)\n\t\t.map(([id, declaration]) => ({\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tservice: serviceKey(id),\n\t\t\tsource: sources[id]!,\n\t\t}));\n}\n\n/** An import specifier for `file`, from the harness written into `dir`. */\nfunction specifierFrom(dir: string, file: string): string {\n\tconst path = relative(dir, file).replace(/\\.tsx?$/, '.js');\n\treturn path.startsWith('.') ? path : `./${path}`;\n}\n\nfunction harnessModule(options: {\n\tdir: string;\n\t/** Every module the manifest points at, by absolute path. */\n\tfiles: string[];\n\tdatabases: DatabaseSource[];\n\t/** Every construct a test reaches through `services`, by service name. */\n\tservices: DatabaseSource[];\n\tsurfaces: { id: string; secured: boolean }[];\n\tauths: AuthClient[];\n\tdrivers: RuntimeDrivers;\n\tfactories: FactorySource[];\n\t/** Each external API's fake, by construct id and the file it lives in. */\n\tfakes: { id: string; file: string }[];\n\t/** Whether the app sends mail — what a magic-link sign-in is read from. */\n\tmail: boolean;\n}): string {\n\tconst {\n\t\tsurfaces,\n\t\tauths,\n\t\tdrivers,\n\t\tdatabases,\n\t\tservices,\n\t\tdir,\n\t\tfiles,\n\t\tfactories,\n\t\tfakes,\n\t\tmail,\n\t} = options;\n\t// One auth server a test can sign in to without a person: a magic link,\n\t// read from the app's inbox. With two, which one \\`signIn\\` means is a\n\t// guess, so neither gets it.\n\tconst magicLinks = mail\n\t\t? auths.filter(({ plugins }) => plugins.includes('magicLinkClient'))\n\t\t: [];\n\tconst signIn = magicLinks.length === 1 ? magicLinks[0] : undefined;\n\tconst plugins = [...new Set(auths.flatMap(({ plugins }) => plugins))].sort();\n\n\tconst imports = [\n\t\t`import {${services.length ? ' type ClientOf,' : ''}${databases.length ? ' type DatabaseOf,' : ''} featureTest, loadTestManifest${signIn ? ', signInWithMagicLink' : ''} } from '@geekmidas/constructs/testing';`,\n\t\t// A type import per construct the types name: each database, and each\n\t\t// construct a test reaches through `services` — once, though a database\n\t\t// is both.\n\t\t...[\n\t\t\t...new Map(\n\t\t\t\t[...databases, ...services].map((construct) => [\n\t\t\t\t\tconstruct.id,\n\t\t\t\t\tconstruct,\n\t\t\t\t]),\n\t\t\t).values(),\n\t\t].map(\n\t\t\t({ id, source }) =>\n\t\t\t\t`import type { ${source.exportName} as __${id} } from '${specifierFrom(dir, source.file)}';`,\n\t\t),\n\t\t`import { Browser as TestBrowser } from '@geekmidas/testkit/browser';`,\n\t\t...surfaces.map(\n\t\t\t({ id }) =>\n\t\t\t\t`import { createApi as create${id} } from './clients/${kebabCase(id)}.js';`,\n\t\t),\n\t\t...(auths.length\n\t\t\t? [`import { createAuthClient } from 'better-auth/client';`]\n\t\t\t: []),\n\t\t...(plugins.length\n\t\t\t? [`import { ${plugins.join(', ')} } from 'better-auth/client/plugins';`]\n\t\t\t: []),\n\t\t...(drivers.imports ? [drivers.imports] : []),\n\t\t...factories.map(\n\t\t\t({ file, service }) =>\n\t\t\t\t`import { createFactory as __${service}Factory } from '${specifierFrom(dir, file)}';`,\n\t\t),\n\t\t...fakes.map(\n\t\t\t({ id, file }) =>\n\t\t\t\t`import __${id}Fake from '${specifierFrom(dir, file)}';`,\n\t\t),\n\t\t// Every construct and endpoint module, imported here — inside the app,\n\t\t// where its tsconfig paths resolve — rather than by path from the kit.\n\t\t...files.map(\n\t\t\t(file, index) =>\n\t\t\t\t`import * as __module${index} from '${specifierFrom(dir, file)}';`,\n\t\t),\n\t];\n\n\tconst url = (id: string) =>\n\t\t`manifest.env[${JSON.stringify(provideKey(id, 'url'))}]!`;\n\n\tconst members = [\n\t\t...surfaces.map(\n\t\t\t({ id, secured }) => `\t/** \\`${id}\\`, at ${provideKey(id, 'url')}. */\n\treadonly ${propertyOf(id)} = create${id}({\n\t\tbaseURL: ${url(id)},\n\t\tfetch: this.fetch,${\n\t\t\tsecured\n\t\t\t\t? `\n\t\t// Served in-process: no authorizer runs, so nothing is signed. A scheme\n\t\t// with no strategy sends its request without credentials.\n\t\tauthStrategies: {} as never,`\n\t\t\t\t: ''\n\t\t}\n\t});`,\n\t\t),\n\t\t...auths.map(\n\t\t\t(auth) => `\t/** \\`${auth.id}\\`, at ${provideKey(auth.id, 'url')}. */\n\treadonly ${propertyOf(auth.id)} = createAuthClient({\n\t\tbaseURL: \\`\\${${url(auth.id)}}${auth.basePath}\\`,\n\t\tplugins: [${auth.plugins.map((plugin) => `${plugin}()`).join(', ')}],\n\t\tfetchOptions: { customFetchImpl: this.fetch },\n\t});`,\n\t\t),\n\t\t...(signIn\n\t\t\t? [\n\t\t\t\t\t`\t/**\n\t * Sign in as \\`email\\` through \\`${signIn.id}\\`'s magic link, the way a person\n\t * does — the email opened, the link followed. The session it then reports.\n\t * Without an address, as somebody new: \\`user.email\\` says who.\n\t */\n\tsignIn(email?: string) {\n\t\treturn signInWithMagicLink(this, this.${propertyOf(signIn.id)}, email);\n\t}`,\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\n\t// Each database's factory, keyed as the test is handed it.\n\tconst factoriesType = factories.length\n\t\t? `{ ${factories.map(({ service }) => `${service}: typeof __${service}Factory`).join('; ')} }`\n\t\t: '';\n\tconst factoriesOption = factories.length\n\t\t? `, factories: { ${factories.map(({ service }) => `${service}: __${service}Factory`).join(', ')} }`\n\t\t: '';\n\tconst fakesOption = fakes.length\n\t\t? `, fakes: { ${fakes.map(({ id }) => `${id}: __${id}Fake`).join(', ')} }`\n\t\t: '';\n\t// Each database's schema, keyed as the test is handed its transaction.\n\tconst databasesType = `{ ${databases.map(({ id, service }) => `${service}: DatabaseOf<typeof __${id}>`).join('; ')} }`;\n\t// Each construct's client, keyed as `services.get(…)` is called.\n\tconst servicesType = services.length\n\t\t? `{ ${services.map(({ id, service }) => `${service}: ClientOf<typeof __${id}>`).join('; ')} }`\n\t\t: '';\n\t// Positional, so a later one needs those before it, even when empty.\n\tconst generics =\n\t\tdatabases.length || factoriesType || servicesType\n\t\t\t? `<Browser, ${databases.length ? databasesType : '{}'}${\n\t\t\t\t\tfactoriesType || servicesType ? `, ${factoriesType || '{}'}` : ''\n\t\t\t\t}${servicesType ? `, ${servicesType}` : ''}>`\n\t\t\t: '';\n\n\treturn `// Generated by \\`gkm test\\` from the app's constructs — do not edit.\n${imports.join('\\n')}\n\n${drivers.setup ? `// The drivers the app's server entry registers, registered the same way.\\n${drivers.setup}\\n\\n` : ''}const manifest = loadTestManifest(new URL('./manifest.json', import.meta.url));\n\n/** A browser with a client for every surface the app declares. */\nexport class Browser extends TestBrowser {\n${members.join('\\n\\n')}\n}\n\n/** The app's modules, by the path the manifest records for each. */\nconst modules = {\n${files.map((file, index) => `\\t${JSON.stringify(file)}: __module${index},`).join('\\n')}\n};\n\n/** \\`it\\`, for a test that drives the app the way it runs deployed. */\nexport const it = featureTest${generics}({ manifest, modules, browser: Browser${factoriesOption}${fakesOption} });\n`;\n}\n","/**\n * The hand-off between `gkm test` and the Vitest global setup.\n *\n * `gkm test` reconciles and migrates the test stage before Vitest starts; the\n * setup, run inside Vitest, only has to load what that left. Started by plain\n * `vitest` instead, the setup runs `gkm test --setup` itself first — so there is\n * one way the stage gets ready, whichever started the suite.\n */\n\n/** Set on the Vitest process by `gkm test`: the stage is ready, here. */\nexport const TEST_READY_ENV = 'GKM_TEST_READY';\n\n/** Where `gkm test` records what it prepared, from where it ran. */\nexport const TEST_READY_FILE = '.gkm/test-ready.json';\n\nexport interface TestReady {\n\t/** The resolved environment, as a JSON object of strings. */\n\tenv: string;\n\t/** The test manifest the `#test` harness reads. */\n\tmanifest?: string;\n\t/**\n\t * The test stage's databases this run created, and the port of the\n\t * Postgres that holds them: what `gkm test --teardown` drops when the\n\t * suite ends — or, if a run was killed before its teardown, what the next\n\t * one drops before it starts.\n\t */\n\tdatabases?: { port: number; names: string[] };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_discover = require("../discover-
|
|
2
|
+
const require_discover = require("../discover-D1It5r_h.cjs");
|
|
3
3
|
const require_emit = require("../emit-Dmc1nvdS.cjs");
|
|
4
4
|
exports.discover = require_discover.discover;
|
|
5
5
|
exports.isDeclarable = require_discover.isDeclarable;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as EmailBackend, t as CacheBackend } from "../types-
|
|
2
|
-
import { a as isDeclarable, i as discover, r as DiscoverOptions } from "../discover-
|
|
1
|
+
import { n as EmailBackend, t as CacheBackend } from "../types-TzCChNrA.cjs";
|
|
2
|
+
import { a as isDeclarable, i as discover, r as DiscoverOptions } from "../discover-CU0paUyH.cjs";
|
|
3
3
|
import { ConstructManifest, RouteInfo } from "@geekmidas/manifest";
|
|
4
4
|
//#region src/reconcile/emit.d.ts
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as EmailBackend, t as CacheBackend } from "../types-
|
|
2
|
-
import { a as isDeclarable, i as discover, r as DiscoverOptions } from "../discover-
|
|
1
|
+
import { n as EmailBackend, t as CacheBackend } from "../types-Dp9lgx_S.mjs";
|
|
2
|
+
import { a as isDeclarable, i as discover, r as DiscoverOptions } from "../discover-DFiJxwfv.mjs";
|
|
3
3
|
import { ConstructManifest, RouteInfo } from "@geekmidas/manifest";
|
|
4
4
|
//#region src/reconcile/emit.d.ts
|
|
5
5
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as isDeclarable, r as discover } from "../discover-
|
|
1
|
+
import { a as isDeclarable, r as discover } from "../discover-BPelzeGW.mjs";
|
|
2
2
|
import { r as withRoutes, t as manifestModule } from "../emit-C1e8qD08.mjs";
|
|
3
3
|
export { discover, isDeclarable, manifestModule, withRoutes };
|
|
@@ -199,8 +199,8 @@ var InvalidTargetOptions = class extends Error {
|
|
|
199
199
|
};
|
|
200
200
|
/** The built-ins `gkm deploy` deploys through, loaded only when used. */
|
|
201
201
|
const BUILTIN_LOADERS = {
|
|
202
|
-
dokploy: async () => (await import("./dokploy-
|
|
203
|
-
compose: async () => (await import("./compose-
|
|
202
|
+
dokploy: async () => (await import("./dokploy-DKa49Nqm.mjs")).dokployTarget,
|
|
203
|
+
compose: async () => (await import("./compose-DZp8DJ0A.mjs").then((n) => n.n)).composeTarget(),
|
|
204
204
|
sst: async () => (await import("./sst-DRi3H5TB.mjs").then((n) => n.n)).sstTarget
|
|
205
205
|
};
|
|
206
206
|
/** The target `name` means, in this workspace, for this host. */
|
|
@@ -259,4 +259,4 @@ async function parseTargetOptions(resolved) {
|
|
|
259
259
|
//#endregion
|
|
260
260
|
export { parseTargetOptions as a, runtimeOf as c, TargetRuntimeMismatch as i, TargetPackageNotFound as l, TargetEntryInvalid as n, resolveTarget as o, TargetPackageInvalid as r, TargetRuntimeUndeclared as s, InvalidTargetOptions as t };
|
|
261
261
|
|
|
262
|
-
//# sourceMappingURL=resolve-
|
|
262
|
+
//# sourceMappingURL=resolve-DSAXj_47.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-BsXEXAUz.mjs","names":[],"sources":["../src/target/package.ts","../src/target/runtime.ts","../src/target/resolve.ts"],"sourcesContent":["/**\n * A target package, found the way the project would find it.\n *\n * From the workspace root, never from the CLI's own location or the process's\n * working directory: the package is the project's dependency, and a CLI run\n * through `pnpm dlx` — or a host deploying a checkout elsewhere — has neither\n * in common with the project.\n */\n\nimport { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nexport interface TargetPackageManifest {\n\tname?: string;\n\tmain?: string;\n\tmodule?: string;\n\texports?: unknown;\n\tgkm?: { runtime?: unknown };\n}\n\nexport interface LocatedPackage {\n\t/** The package's directory, symlinks resolved. */\n\tdir: string;\n\tmanifest: TargetPackageManifest;\n}\n\n/** A target package the project does not have installed. */\nexport class TargetPackageNotFound extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly from: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names the package \"${packageName}\", which is not installed in ${from}. Add it to the workspace root: pnpm add -D ${packageName}`,\n\t\t);\n\t\tthis.name = 'TargetPackageNotFound';\n\t}\n}\n\n/**\n * `name`'s directory and `package.json`, from the nearest `node_modules` at\n * or above `from` — Node's own lookup, without the exports map getting in\n * the way of reading `package.json`.\n */\nexport function locatePackage(\n\tname: string,\n\tfrom: string,\n): LocatedPackage | undefined {\n\tlet dir = from;\n\twhile (true) {\n\t\tconst manifestPath = join(dir, 'node_modules', name, 'package.json');\n\t\tif (existsSync(manifestPath)) {\n\t\t\treturn {\n\t\t\t\tdir: realpathSync(dirname(manifestPath)),\n\t\t\t\tmanifest: JSON.parse(\n\t\t\t\t\treadFileSync(manifestPath, 'utf-8'),\n\t\t\t\t) as TargetPackageManifest,\n\t\t\t};\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return undefined;\n\t\tdir = parent;\n\t}\n}\n\n/** The first file a conditions object leads to, as an `import` would. */\nfunction pick(node: unknown): string | undefined {\n\tif (typeof node === 'string') return node;\n\tif (Array.isArray(node)) {\n\t\tfor (const option of node) {\n\t\t\tconst found = pick(option);\n\t\t\tif (found) return found;\n\t\t}\n\t\treturn undefined;\n\t}\n\tif (node && typeof node === 'object') {\n\t\tconst conditions = node as Record<string, unknown>;\n\t\tfor (const condition of ['import', 'node', 'default', 'require']) {\n\t\t\tif (condition in conditions) {\n\t\t\t\tconst found = pick(conditions[condition]);\n\t\t\t\tif (found) return found;\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** The file `import(name)` loads, relative to the package directory. */\nexport function packageEntry(manifest: TargetPackageManifest): string {\n\tconst { exports } = manifest;\n\tlet root: unknown = exports;\n\tif (exports && typeof exports === 'object' && !Array.isArray(exports)) {\n\t\tconst keys = Object.keys(exports);\n\t\t// A subpath map — `{ \".\": …, \"./x\": … }` — rather than one conditions\n\t\t// object for the root.\n\t\tif (keys.some((key) => key.startsWith('.'))) {\n\t\t\troot = (exports as Record<string, unknown>)['.'];\n\t\t}\n\t}\n\treturn pick(root) ?? manifest.module ?? manifest.main ?? 'index.js';\n}\n\n/** The module `name` is, imported from where the project would import it. */\nexport async function importPackage(\n\ttarget: string,\n\tname: string,\n\tfrom: string,\n): Promise<Record<string, unknown>> {\n\tconst located = locatePackage(name, from);\n\tif (!located) throw new TargetPackageNotFound(target, name, from);\n\n\tconst entry = join(located.dir, packageEntry(located.manifest));\n\treturn (await import(pathToFileURL(entry).href)) as Record<string, unknown>;\n}\n","/**\n * A target's runtime, without loading the target.\n *\n * `gkm dev` and `gkm build` choose a project's backends by it on every start,\n * synchronously, and must not import a deploy plugin to do so — a plugin may\n * pull in a cloud SDK, and a broken one would stop `gkm dev` for a project\n * that is only being developed. So a built-in's runtime is in the table, an\n * inline target carries its own, and a package declares it in its\n * `package.json`:\n *\n * ```json\n * { \"name\": \"@acme/gkm-target\", \"gkm\": { \"runtime\": \"server\" } }\n * ```\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { locatePackage, TargetPackageNotFound } from './package';\nimport type { DeployRuntime, DeployTargetEntry } from './types';\n\nconst RUNTIMES: readonly DeployRuntime[] = ['server', 'aws'];\n\n/** A target package whose `package.json` does not say where it runs. */\nexport class TargetRuntimeUndeclared extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\t/** What `gkm.runtime` held instead, when it held anything. */\n\t\treadonly found?: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" (${packageName}) does not declare its runtime${found === undefined ? '' : ` (gkm.runtime is ${JSON.stringify(found)})`}. Its package.json needs \"gkm\": { \"runtime\": \"server\" } or \"aws\", so gkm dev and gkm build can choose backends without loading it.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeUndeclared';\n\t}\n}\n\n/** What a workspace's deploy config is read for here. */\nexport interface TargetSource {\n\t/** Where the target packages are installed from. */\n\troot?: string;\n\tdeploy?:\n\t\t| { default?: string; targets?: Record<string, DeployTargetEntry> }\n\t\t| undefined;\n}\n\n/** The runtime a target package declares in `package.json#gkm.runtime`. */\nexport function declaredRuntime(\n\ttarget: string,\n\tpackageName: string,\n\troot: string | undefined,\n): DeployRuntime {\n\tconst located = root ? locatePackage(packageName, root) : undefined;\n\tif (!located) {\n\t\tthrow new TargetPackageNotFound(\n\t\t\ttarget,\n\t\t\tpackageName,\n\t\t\troot ?? 'the workspace',\n\t\t);\n\t}\n\tconst runtime = located.manifest.gkm?.runtime;\n\tif (!RUNTIMES.includes(runtime as DeployRuntime)) {\n\t\tthrow new TargetRuntimeUndeclared(target, packageName, runtime);\n\t}\n\treturn runtime as DeployRuntime;\n}\n\n/** The runtime of the target `name`, as the workspace resolves it. */\nexport function runtimeOf(\n\tname: string,\n\tworkspace: TargetSource,\n): DeployRuntime {\n\tconst builtin = builtinTarget(name);\n\tif (builtin) return builtin.runtime;\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst implementation = Array.isArray(entry) ? entry[0] : entry;\n\treturn typeof implementation === 'string'\n\t\t? declaredRuntime(name, implementation, workspace.root)\n\t\t: (implementation as { runtime: DeployRuntime }).runtime;\n}\n","/**\n * From a target's name to the target.\n *\n * In this order, the first that has the name wins:\n *\n * 1. the host's own targets — what a program calling `deploy()` passes\n * 2. the built-ins — `dokploy`, `compose`, `sst`\n * 3. `deploy.targets` in gkm.config.ts — a package, an object, or either\n * with options\n *\n * Built-ins come before the config so that a dependency cannot take over\n * `dokploy` by being listed under its name. A name nothing has is\n * `UnknownDeployTarget`. There is deliberately no fourth step that guesses a\n * package from the name (`acme` → `@acme/gkm-target`): an npm scope nobody\n * has claimed can be claimed by anyone, and a deploy would then run their\n * code with the stage's credentials. A target is installed and named.\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tDeployTargetNotYetSupported,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { isDeployTarget } from './define';\nimport { importPackage } from './package';\nimport { declaredRuntime } from './runtime';\nimport type {\n\tAnyDeployTarget,\n\tDeployRuntime,\n\tDeployTargetEntry,\n\tTargetOptionsIssue,\n} from './types';\n\n/** Where a target came from. */\nexport type TargetSourceKind = 'host' | 'builtin' | 'config';\n\nexport interface ResolvedTarget {\n\t/** The name it was asked for by. */\n\tname: string;\n\ttarget: AnyDeployTarget;\n\tsource: TargetSourceKind;\n\t/** Its options as written in the config, before its schema parsed them. */\n\toptions: unknown;\n}\n\nexport interface ResolveTargetOptions {\n\t/** The workspace whose `deploy.targets` is consulted. */\n\tworkspace: {\n\t\troot: string;\n\t\tdeploy?: { targets?: Record<string, DeployTargetEntry> } | undefined;\n\t};\n\t/** The host's targets, consulted first. */\n\thost?: Record<string, AnyDeployTarget>;\n\t/** The stage being deployed, for what to do instead of a refused target. */\n\tstage: string;\n}\n\n/** A target package whose default export is not a target. */\nexport class TargetPackageInvalid extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names \"${packageName}\", whose default export is not a deploy target. A target package exports one as default: export default defineTarget({ … }) from '@geekmidas/cli/target'.`,\n\t\t);\n\t\tthis.name = 'TargetPackageInvalid';\n\t}\n}\n\n/** A `deploy.targets` entry that is not a target, a package name or a pair. */\nexport class TargetEntryInvalid extends Error {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} must be a package name, a target object (defineTarget), or [package or target, options].`,\n\t\t);\n\t\tthis.name = 'TargetEntryInvalid';\n\t}\n}\n\n/** A target whose `runtime` is not the one its package declares. */\nexport class TargetRuntimeMismatch extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly declared: DeployRuntime,\n\t\treadonly actual: DeployRuntime,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" runs on \"${actual}\", but ${packageName}'s package.json declares gkm.runtime \"${declared}\". gkm dev and gkm build chose backends for \"${declared}\", so the two must agree — fix the package.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeMismatch';\n\t}\n}\n\n/** Options a target's schema rejected. */\nexport class InvalidTargetOptions extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly issues: readonly TargetOptionsIssue[],\n\t) {\n\t\tconst lines = issues.map((issue) => {\n\t\t\tconst path = (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\t\t\treturn ` - ${path ? `${path}: ` : ''}${issue.message}`;\n\t\t});\n\t\tsuper(\n\t\t\t`The options for deploy target \"${target}\" are invalid — fix them in deploy.targets.${target} in gkm.config.ts:\\n${lines.join('\\n')}`,\n\t\t);\n\t\tthis.name = 'InvalidTargetOptions';\n\t}\n}\n\n/** The built-ins `gkm deploy` deploys through, loaded only when used. */\nconst BUILTIN_LOADERS: Record<string, () => Promise<AnyDeployTarget>> = {\n\tdokploy: async () => (await import('./dokploy')).dokployTarget,\n\tcompose: async () => (await import('./compose/index')).composeTarget(),\n\tsst: async () => (await import('./sst/index')).sstTarget,\n};\n\n/** The target `name` means, in this workspace, for this host. */\nexport async function resolveTarget(\n\tname: string,\n\t{ workspace, host, stage }: ResolveTargetOptions,\n): Promise<ResolvedTarget> {\n\tif (host && Object.hasOwn(host, name)) {\n\t\treturn { name, target: host[name]!, source: 'host', options: undefined };\n\t}\n\n\tconst builtin = builtinTarget(name);\n\tif (builtin) {\n\t\tconst load = BUILTIN_LOADERS[name];\n\t\tif (builtin.status !== 'available' || !load) {\n\t\t\tthrow new DeployTargetNotYetSupported(name, builtin.instead?.(stage));\n\t\t}\n\t\treturn {\n\t\t\tname,\n\t\t\ttarget: await load(),\n\t\t\tsource: 'builtin',\n\t\t\toptions: undefined,\n\t\t};\n\t}\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst [implementation, options] = Array.isArray(entry)\n\t\t? (entry as readonly [unknown, unknown])\n\t\t: [entry, undefined];\n\n\tif (typeof implementation === 'string') {\n\t\t// Before the import: a package that does not say where it runs is\n\t\t// refused without running any of its code.\n\t\tconst declared = declaredRuntime(name, implementation, workspace.root);\n\t\tconst loaded = await importPackage(name, implementation, workspace.root);\n\t\tconst target = loaded.default;\n\t\tif (!isDeployTarget(target)) {\n\t\t\tthrow new TargetPackageInvalid(name, implementation);\n\t\t}\n\t\tif (target.runtime !== declared) {\n\t\t\tthrow new TargetRuntimeMismatch(\n\t\t\t\tname,\n\t\t\t\timplementation,\n\t\t\t\tdeclared,\n\t\t\t\ttarget.runtime,\n\t\t\t);\n\t\t}\n\t\treturn { name, target, source: 'config', options };\n\t}\n\n\tif (!isDeployTarget(implementation)) throw new TargetEntryInvalid(name);\n\treturn { name, target: implementation, source: 'config', options };\n}\n\n/** The target's options, parsed by its schema. */\nexport async function parseTargetOptions(\n\tresolved: ResolvedTarget,\n): Promise<unknown> {\n\tconst { name, target, options } = resolved;\n\tif (!target.options) {\n\t\tif (options !== undefined) {\n\t\t\tthrow new InvalidTargetOptions(name, [\n\t\t\t\t{ message: 'this target takes no options' },\n\t\t\t]);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconst result = await target.options['~standard'].validate(options);\n\tif (result.issues) throw new InvalidTargetOptions(name, result.issues);\n\treturn result.value;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolve-DSAXj_47.mjs","names":[],"sources":["../src/target/package.ts","../src/target/runtime.ts","../src/target/resolve.ts"],"sourcesContent":["/**\n * A target package, found the way the project would find it.\n *\n * From the workspace root, never from the CLI's own location or the process's\n * working directory: the package is the project's dependency, and a CLI run\n * through `pnpm dlx` — or a host deploying a checkout elsewhere — has neither\n * in common with the project.\n */\n\nimport { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nexport interface TargetPackageManifest {\n\tname?: string;\n\tmain?: string;\n\tmodule?: string;\n\texports?: unknown;\n\tgkm?: { runtime?: unknown };\n}\n\nexport interface LocatedPackage {\n\t/** The package's directory, symlinks resolved. */\n\tdir: string;\n\tmanifest: TargetPackageManifest;\n}\n\n/** A target package the project does not have installed. */\nexport class TargetPackageNotFound extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly from: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names the package \"${packageName}\", which is not installed in ${from}. Add it to the workspace root: pnpm add -D ${packageName}`,\n\t\t);\n\t\tthis.name = 'TargetPackageNotFound';\n\t}\n}\n\n/**\n * `name`'s directory and `package.json`, from the nearest `node_modules` at\n * or above `from` — Node's own lookup, without the exports map getting in\n * the way of reading `package.json`.\n */\nexport function locatePackage(\n\tname: string,\n\tfrom: string,\n): LocatedPackage | undefined {\n\tlet dir = from;\n\twhile (true) {\n\t\tconst manifestPath = join(dir, 'node_modules', name, 'package.json');\n\t\tif (existsSync(manifestPath)) {\n\t\t\treturn {\n\t\t\t\tdir: realpathSync(dirname(manifestPath)),\n\t\t\t\tmanifest: JSON.parse(\n\t\t\t\t\treadFileSync(manifestPath, 'utf-8'),\n\t\t\t\t) as TargetPackageManifest,\n\t\t\t};\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return undefined;\n\t\tdir = parent;\n\t}\n}\n\n/** The first file a conditions object leads to, as an `import` would. */\nfunction pick(node: unknown): string | undefined {\n\tif (typeof node === 'string') return node;\n\tif (Array.isArray(node)) {\n\t\tfor (const option of node) {\n\t\t\tconst found = pick(option);\n\t\t\tif (found) return found;\n\t\t}\n\t\treturn undefined;\n\t}\n\tif (node && typeof node === 'object') {\n\t\tconst conditions = node as Record<string, unknown>;\n\t\tfor (const condition of ['import', 'node', 'default', 'require']) {\n\t\t\tif (condition in conditions) {\n\t\t\t\tconst found = pick(conditions[condition]);\n\t\t\t\tif (found) return found;\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** The file `import(name)` loads, relative to the package directory. */\nexport function packageEntry(manifest: TargetPackageManifest): string {\n\tconst { exports } = manifest;\n\tlet root: unknown = exports;\n\tif (exports && typeof exports === 'object' && !Array.isArray(exports)) {\n\t\tconst keys = Object.keys(exports);\n\t\t// A subpath map — `{ \".\": …, \"./x\": … }` — rather than one conditions\n\t\t// object for the root.\n\t\tif (keys.some((key) => key.startsWith('.'))) {\n\t\t\troot = (exports as Record<string, unknown>)['.'];\n\t\t}\n\t}\n\treturn pick(root) ?? manifest.module ?? manifest.main ?? 'index.js';\n}\n\n/** The module `name` is, imported from where the project would import it. */\nexport async function importPackage(\n\ttarget: string,\n\tname: string,\n\tfrom: string,\n): Promise<Record<string, unknown>> {\n\tconst located = locatePackage(name, from);\n\tif (!located) throw new TargetPackageNotFound(target, name, from);\n\n\tconst entry = join(located.dir, packageEntry(located.manifest));\n\treturn (await import(pathToFileURL(entry).href)) as Record<string, unknown>;\n}\n","/**\n * A target's runtime, without loading the target.\n *\n * `gkm dev` and `gkm build` choose a project's backends by it on every start,\n * synchronously, and must not import a deploy plugin to do so — a plugin may\n * pull in a cloud SDK, and a broken one would stop `gkm dev` for a project\n * that is only being developed. So a built-in's runtime is in the table, an\n * inline target carries its own, and a package declares it in its\n * `package.json`:\n *\n * ```json\n * { \"name\": \"@acme/gkm-target\", \"gkm\": { \"runtime\": \"server\" } }\n * ```\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { locatePackage, TargetPackageNotFound } from './package';\nimport type { DeployRuntime, DeployTargetEntry } from './types';\n\nconst RUNTIMES: readonly DeployRuntime[] = ['server', 'aws'];\n\n/** A target package whose `package.json` does not say where it runs. */\nexport class TargetRuntimeUndeclared extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\t/** What `gkm.runtime` held instead, when it held anything. */\n\t\treadonly found?: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" (${packageName}) does not declare its runtime${found === undefined ? '' : ` (gkm.runtime is ${JSON.stringify(found)})`}. Its package.json needs \"gkm\": { \"runtime\": \"server\" } or \"aws\", so gkm dev and gkm build can choose backends without loading it.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeUndeclared';\n\t}\n}\n\n/** What a workspace's deploy config is read for here. */\nexport interface TargetSource {\n\t/** Where the target packages are installed from. */\n\troot?: string;\n\tdeploy?:\n\t\t| { default?: string; targets?: Record<string, DeployTargetEntry> }\n\t\t| undefined;\n}\n\n/** The runtime a target package declares in `package.json#gkm.runtime`. */\nexport function declaredRuntime(\n\ttarget: string,\n\tpackageName: string,\n\troot: string | undefined,\n): DeployRuntime {\n\tconst located = root ? locatePackage(packageName, root) : undefined;\n\tif (!located) {\n\t\tthrow new TargetPackageNotFound(\n\t\t\ttarget,\n\t\t\tpackageName,\n\t\t\troot ?? 'the workspace',\n\t\t);\n\t}\n\tconst runtime = located.manifest.gkm?.runtime;\n\tif (!RUNTIMES.includes(runtime as DeployRuntime)) {\n\t\tthrow new TargetRuntimeUndeclared(target, packageName, runtime);\n\t}\n\treturn runtime as DeployRuntime;\n}\n\n/** The runtime of the target `name`, as the workspace resolves it. */\nexport function runtimeOf(\n\tname: string,\n\tworkspace: TargetSource,\n): DeployRuntime {\n\tconst builtin = builtinTarget(name);\n\tif (builtin) return builtin.runtime;\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst implementation = Array.isArray(entry) ? entry[0] : entry;\n\treturn typeof implementation === 'string'\n\t\t? declaredRuntime(name, implementation, workspace.root)\n\t\t: (implementation as { runtime: DeployRuntime }).runtime;\n}\n","/**\n * From a target's name to the target.\n *\n * In this order, the first that has the name wins:\n *\n * 1. the host's own targets — what a program calling `deploy()` passes\n * 2. the built-ins — `dokploy`, `compose`, `sst`\n * 3. `deploy.targets` in gkm.config.ts — a package, an object, or either\n * with options\n *\n * Built-ins come before the config so that a dependency cannot take over\n * `dokploy` by being listed under its name. A name nothing has is\n * `UnknownDeployTarget`. There is deliberately no fourth step that guesses a\n * package from the name (`acme` → `@acme/gkm-target`): an npm scope nobody\n * has claimed can be claimed by anyone, and a deploy would then run their\n * code with the stage's credentials. A target is installed and named.\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tDeployTargetNotYetSupported,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { isDeployTarget } from './define';\nimport { importPackage } from './package';\nimport { declaredRuntime } from './runtime';\nimport type {\n\tAnyDeployTarget,\n\tDeployRuntime,\n\tDeployTargetEntry,\n\tTargetOptionsIssue,\n} from './types';\n\n/** Where a target came from. */\nexport type TargetSourceKind = 'host' | 'builtin' | 'config';\n\nexport interface ResolvedTarget {\n\t/** The name it was asked for by. */\n\tname: string;\n\ttarget: AnyDeployTarget;\n\tsource: TargetSourceKind;\n\t/** Its options as written in the config, before its schema parsed them. */\n\toptions: unknown;\n}\n\nexport interface ResolveTargetOptions {\n\t/** The workspace whose `deploy.targets` is consulted. */\n\tworkspace: {\n\t\troot: string;\n\t\tdeploy?: { targets?: Record<string, DeployTargetEntry> } | undefined;\n\t};\n\t/** The host's targets, consulted first. */\n\thost?: Record<string, AnyDeployTarget>;\n\t/** The stage being deployed, for what to do instead of a refused target. */\n\tstage: string;\n}\n\n/** A target package whose default export is not a target. */\nexport class TargetPackageInvalid extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names \"${packageName}\", whose default export is not a deploy target. A target package exports one as default: export default defineTarget({ … }) from '@geekmidas/cli/target'.`,\n\t\t);\n\t\tthis.name = 'TargetPackageInvalid';\n\t}\n}\n\n/** A `deploy.targets` entry that is not a target, a package name or a pair. */\nexport class TargetEntryInvalid extends Error {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} must be a package name, a target object (defineTarget), or [package or target, options].`,\n\t\t);\n\t\tthis.name = 'TargetEntryInvalid';\n\t}\n}\n\n/** A target whose `runtime` is not the one its package declares. */\nexport class TargetRuntimeMismatch extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly declared: DeployRuntime,\n\t\treadonly actual: DeployRuntime,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" runs on \"${actual}\", but ${packageName}'s package.json declares gkm.runtime \"${declared}\". gkm dev and gkm build chose backends for \"${declared}\", so the two must agree — fix the package.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeMismatch';\n\t}\n}\n\n/** Options a target's schema rejected. */\nexport class InvalidTargetOptions extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly issues: readonly TargetOptionsIssue[],\n\t) {\n\t\tconst lines = issues.map((issue) => {\n\t\t\tconst path = (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\t\t\treturn ` - ${path ? `${path}: ` : ''}${issue.message}`;\n\t\t});\n\t\tsuper(\n\t\t\t`The options for deploy target \"${target}\" are invalid — fix them in deploy.targets.${target} in gkm.config.ts:\\n${lines.join('\\n')}`,\n\t\t);\n\t\tthis.name = 'InvalidTargetOptions';\n\t}\n}\n\n/** The built-ins `gkm deploy` deploys through, loaded only when used. */\nconst BUILTIN_LOADERS: Record<string, () => Promise<AnyDeployTarget>> = {\n\tdokploy: async () => (await import('./dokploy')).dokployTarget,\n\tcompose: async () => (await import('./compose/index')).composeTarget(),\n\tsst: async () => (await import('./sst/index')).sstTarget,\n};\n\n/** The target `name` means, in this workspace, for this host. */\nexport async function resolveTarget(\n\tname: string,\n\t{ workspace, host, stage }: ResolveTargetOptions,\n): Promise<ResolvedTarget> {\n\tif (host && Object.hasOwn(host, name)) {\n\t\treturn { name, target: host[name]!, source: 'host', options: undefined };\n\t}\n\n\tconst builtin = builtinTarget(name);\n\tif (builtin) {\n\t\tconst load = BUILTIN_LOADERS[name];\n\t\tif (builtin.status !== 'available' || !load) {\n\t\t\tthrow new DeployTargetNotYetSupported(name, builtin.instead?.(stage));\n\t\t}\n\t\treturn {\n\t\t\tname,\n\t\t\ttarget: await load(),\n\t\t\tsource: 'builtin',\n\t\t\toptions: undefined,\n\t\t};\n\t}\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst [implementation, options] = Array.isArray(entry)\n\t\t? (entry as readonly [unknown, unknown])\n\t\t: [entry, undefined];\n\n\tif (typeof implementation === 'string') {\n\t\t// Before the import: a package that does not say where it runs is\n\t\t// refused without running any of its code.\n\t\tconst declared = declaredRuntime(name, implementation, workspace.root);\n\t\tconst loaded = await importPackage(name, implementation, workspace.root);\n\t\tconst target = loaded.default;\n\t\tif (!isDeployTarget(target)) {\n\t\t\tthrow new TargetPackageInvalid(name, implementation);\n\t\t}\n\t\tif (target.runtime !== declared) {\n\t\t\tthrow new TargetRuntimeMismatch(\n\t\t\t\tname,\n\t\t\t\timplementation,\n\t\t\t\tdeclared,\n\t\t\t\ttarget.runtime,\n\t\t\t);\n\t\t}\n\t\treturn { name, target, source: 'config', options };\n\t}\n\n\tif (!isDeployTarget(implementation)) throw new TargetEntryInvalid(name);\n\treturn { name, target: implementation, source: 'config', options };\n}\n\n/** The target's options, parsed by its schema. */\nexport async function parseTargetOptions(\n\tresolved: ResolvedTarget,\n): Promise<unknown> {\n\tconst { name, target, options } = resolved;\n\tif (!target.options) {\n\t\tif (options !== undefined) {\n\t\t\tthrow new InvalidTargetOptions(name, [\n\t\t\t\t{ message: 'this target takes no options' },\n\t\t\t]);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconst result = await target.options['~standard'].validate(options);\n\tif (result.issues) throw new InvalidTargetOptions(name, result.issues);\n\treturn result.value;\n}\n"],"mappings":"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"}
|
|
@@ -199,8 +199,8 @@ var InvalidTargetOptions = class extends Error {
|
|
|
199
199
|
};
|
|
200
200
|
/** The built-ins `gkm deploy` deploys through, loaded only when used. */
|
|
201
201
|
const BUILTIN_LOADERS = {
|
|
202
|
-
dokploy: async () => (await Promise.resolve().then(() => require("./dokploy-
|
|
203
|
-
compose: async () => (await Promise.resolve().then(() => require("./compose-
|
|
202
|
+
dokploy: async () => (await Promise.resolve().then(() => require("./dokploy-DKzcI-RL.cjs"))).dokployTarget,
|
|
203
|
+
compose: async () => (await Promise.resolve().then(() => require("./compose-iuw8wfHk.cjs")).then((n) => n.compose_exports)).composeTarget(),
|
|
204
204
|
sst: async () => (await Promise.resolve().then(() => require("./sst-hBrKouBy.cjs")).then((n) => n.sst_exports)).sstTarget
|
|
205
205
|
};
|
|
206
206
|
/** The target `name` means, in this workspace, for this host. */
|
|
@@ -312,4 +312,4 @@ Object.defineProperty(exports, "runtimeOf", {
|
|
|
312
312
|
}
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
-
//# sourceMappingURL=resolve-
|
|
315
|
+
//# sourceMappingURL=resolve-D_BU-wKA.cjs.map
|