@mesh-tech/mesh-cli 0.18.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -56
- package/dist/bin/mesh.js +5158 -4302
- package/dist/bin/mesh.js.map +4 -4
- package/dist/build-info.json +2 -2
- package/dist/src/commands/create-app.d.ts +28 -0
- package/dist/src/commands/create-app.d.ts.map +1 -1
- package/dist/src/commands/create-app.js +45 -1
- package/dist/src/commands/create-app.js.map +1 -1
- package/dist/src/commands/dev-doctor.js +2 -2
- package/dist/src/commands/dev-doctor.js.map +1 -1
- package/dist/src/commands/dev.d.ts +7 -0
- package/dist/src/commands/dev.d.ts.map +1 -1
- package/dist/src/commands/dev.js +1 -0
- package/dist/src/commands/dev.js.map +1 -1
- package/dist/src/commands/hub/index.d.ts.map +1 -1
- package/dist/src/commands/hub/index.js +5 -0
- package/dist/src/commands/hub/index.js.map +1 -1
- package/dist/src/commands/init/wizard.d.ts +216 -0
- package/dist/src/commands/init/wizard.d.ts.map +1 -0
- package/dist/src/commands/init/wizard.js +471 -0
- package/dist/src/commands/init/wizard.js.map +1 -0
- package/dist/src/commands/init.d.ts +14 -6
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +41 -15
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/local/auth-provision.d.ts +4 -0
- package/dist/src/commands/local/auth-provision.d.ts.map +1 -1
- package/dist/src/commands/local/auth-provision.js +20 -0
- package/dist/src/commands/local/auth-provision.js.map +1 -1
- package/dist/src/commands/local/dev-local.d.ts +32 -0
- package/dist/src/commands/local/dev-local.d.ts.map +1 -1
- package/dist/src/commands/local/dev-local.js +88 -2
- package/dist/src/commands/local/dev-local.js.map +1 -1
- package/dist/src/commands/local/seed.d.ts +9 -0
- package/dist/src/commands/local/seed.d.ts.map +1 -1
- package/dist/src/commands/local/seed.js +49 -10
- package/dist/src/commands/local/seed.js.map +1 -1
- package/dist/src/commands/login.d.ts +76 -5
- package/dist/src/commands/login.d.ts.map +1 -1
- package/dist/src/commands/login.js +161 -60
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/registry.d.ts +133 -10
- package/dist/src/commands/registry.d.ts.map +1 -1
- package/dist/src/commands/registry.js +238 -86
- package/dist/src/commands/registry.js.map +1 -1
- package/dist/src/commands/temporal.js +54 -24
- package/dist/src/commands/temporal.js.map +3 -3
- package/dist/src/docs/registry-docs.d.ts.map +1 -1
- package/dist/src/docs/registry-docs.js +8 -3
- package/dist/src/docs/registry-docs.js.map +1 -1
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +5 -1
- package/dist/src/program.js.map +1 -1
- package/dist/src/utils/auth-preflight.d.ts +51 -20
- package/dist/src/utils/auth-preflight.d.ts.map +1 -1
- package/dist/src/utils/auth-preflight.js +48 -21
- package/dist/src/utils/auth-preflight.js.map +1 -1
- package/dist/src/utils/mesh-json.d.ts +58 -0
- package/dist/src/utils/mesh-json.d.ts.map +1 -0
- package/dist/src/utils/mesh-json.js +85 -0
- package/dist/src/utils/mesh-json.js.map +1 -0
- package/dist/src/utils/registry-broker.d.ts +12 -29
- package/dist/src/utils/registry-broker.d.ts.map +1 -1
- package/dist/src/utils/registry-broker.js +12 -29
- package/dist/src/utils/registry-broker.js.map +1 -1
- package/dist/src/utils/registry-identity.d.ts +170 -0
- package/dist/src/utils/registry-identity.d.ts.map +1 -0
- package/dist/src/utils/registry-identity.js +273 -0
- package/dist/src/utils/registry-identity.js.map +1 -0
- package/package.json +3 -2
- package/skills/core/SKILL.md +8 -7
- package/templates/apps-repo/gitignore +4 -0
|
@@ -3,35 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This is the path that lets a brand-new Trabian developer install
|
|
5
5
|
* `@mesh-tech/*` with **no AWS account, no AWS CLI and no ~/.aws/config**: the
|
|
6
|
-
* broker verifies the Zitadel id token `mesh login`
|
|
7
|
-
* caller's role, and returns a CodeArtifact
|
|
8
|
-
* identity. No AWS credential of any kind
|
|
6
|
+
* broker verifies the Zitadel id token `mesh registry login` cached for the
|
|
7
|
+
* registry's own issuer, checks the caller's role, and returns a CodeArtifact
|
|
8
|
+
* token minted with the BROKER's AWS identity. No AWS credential of any kind
|
|
9
|
+
* reaches the laptop. Which broker to call comes from the registry's global
|
|
10
|
+
* identity (`registry-identity.ts`), never from a platform context.
|
|
9
11
|
*
|
|
10
12
|
* Everything here is pure or dependency-injected so the fallback behaviour —
|
|
11
13
|
* which is what decides whether a broker hiccup breaks an install — is
|
|
12
14
|
* unit-testable without a network.
|
|
13
15
|
*/
|
|
14
|
-
import { getContextConfig, getValidToken
|
|
15
|
-
/**
|
|
16
|
-
* Pick a context for a `mesh registry login` invoked with none.
|
|
17
|
-
*
|
|
18
|
-
* A context-less call used to skip the broker outright, which quietly sent
|
|
19
|
-
* anyone following a remediation that omits the context straight back to the
|
|
20
|
-
* AWS chain — the exact routing this feature removes. So: if exactly one cached
|
|
21
|
-
* context publishes a `registryBroker`, use it. Zero or several is genuinely
|
|
22
|
-
* ambiguous and the caller must say which.
|
|
23
|
-
*
|
|
24
|
-
* Deliberately narrow. Guessing among several contexts would post the user's id
|
|
25
|
-
* token to a broker they did not name.
|
|
26
|
-
*/
|
|
27
|
-
export function resolveDefaultBrokerContext(configs = readAllContextConfigs(), credentials = readAllCredentials()) {
|
|
28
|
-
const candidates = Object.entries(configs)
|
|
29
|
-
.filter(([name, cfg]) => Boolean(cfg?.registryBroker) && name in credentials)
|
|
30
|
-
.map(([name]) => name);
|
|
31
|
-
if (candidates.length === 1)
|
|
32
|
-
return { context: candidates[0] };
|
|
33
|
-
return { reason: candidates.length === 0 ? "none" : "ambiguous", candidates };
|
|
34
|
-
}
|
|
16
|
+
import { getContextConfig, getValidToken } from "../commands/login.js";
|
|
35
17
|
/**
|
|
36
18
|
* Resolve the broker URL, preferring the platform-published value from
|
|
37
19
|
* discovery (`ContextConfig.registryBroker`) and falling back to DNS-convention
|
|
@@ -141,12 +123,13 @@ export async function classifyBrokerResponse(res) {
|
|
|
141
123
|
};
|
|
142
124
|
}
|
|
143
125
|
/**
|
|
144
|
-
* Exchange the cached Zitadel id token
|
|
126
|
+
* Exchange the cached Zitadel id token under `context` (the reserved registry
|
|
127
|
+
* key, or any cached context whose issuer matches the registry's) for a
|
|
128
|
+
* CodeArtifact read grant.
|
|
145
129
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* device-code poll.
|
|
130
|
+
* The token lookup never prompts — an expired session with no refresh token
|
|
131
|
+
* comes back as `no-session` for the caller to decide about, rather than
|
|
132
|
+
* stalling a headless run in a device-code poll.
|
|
150
133
|
*/
|
|
151
134
|
export async function fetchRegistryGrant(context, brokerUrl, deps) {
|
|
152
135
|
const token = await deps.getValidToken(context);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-broker.js","sourceRoot":"","sources":["../../../src/utils/registry-broker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry-broker.js","sourceRoot":"","sources":["../../../src/utils/registry-broker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE identity behind `@mesh-tech` package access.
|
|
3
|
+
*
|
|
4
|
+
* Every reader of the registry — `pnpm install`, `mesh create-app`,
|
|
5
|
+
* `mesh docs start`, the Hub image build under `mesh start` — talks to the same
|
|
6
|
+
* CodeArtifact domain, and that domain is owned by exactly one Mesh platform:
|
|
7
|
+
* `dev.platform.meshtech.io`. So the registry has a single, global identity
|
|
8
|
+
* (issuer + CLI client id + broker URL) that never depends on which tenant
|
|
9
|
+
* platform, if any, the developer deploys to.
|
|
10
|
+
*
|
|
11
|
+
* This module keeps that identity separate from platform contexts:
|
|
12
|
+
*
|
|
13
|
+
* - The domain comes from the compiled-in first-party alias table and nowhere
|
|
14
|
+
* else — not an argument, not an environment variable, not an unpinned
|
|
15
|
+
* config value. That is the same trust anchor `mesh login` relies on, so the
|
|
16
|
+
* ≥2-dot anti-phishing guard stays intact.
|
|
17
|
+
* - The Zitadel session for the registry is cached under a **reserved**
|
|
18
|
+
* credential key (`registry`) that no `<tenant>.<env>` context can collide
|
|
19
|
+
* with, and `mesh login` / `mesh logout` refuse it.
|
|
20
|
+
* - A developer who already signed in to the registry's own platform
|
|
21
|
+
* (`mesh login mesh.dev`) is reused rather than sent through the browser a
|
|
22
|
+
* second time: any cached session whose issuer matches the registry's counts.
|
|
23
|
+
*
|
|
24
|
+
* Nothing here touches `~/.npmrc` or the broker — that is `mesh registry
|
|
25
|
+
* login`'s job. This module only answers "who is the registry?" and "do I hold
|
|
26
|
+
* a session for it?".
|
|
27
|
+
*/
|
|
28
|
+
import { MeshCliError } from "./errors.js";
|
|
29
|
+
/**
|
|
30
|
+
* The first-party alias of the platform that owns the `@mesh-tech` registry.
|
|
31
|
+
* The alias is the key in `FIRST_PARTY_CONTEXTS`; the domain is looked up
|
|
32
|
+
* from that reviewed table, never typed here twice.
|
|
33
|
+
*/
|
|
34
|
+
export declare const REGISTRY_ALIAS = "mesh.dev";
|
|
35
|
+
/** The pinned domain anonymous discovery runs against, e.g. `dev.platform.meshtech.io`. */
|
|
36
|
+
export declare const REGISTRY_DOMAIN: string;
|
|
37
|
+
/**
|
|
38
|
+
* The reserved context name the registry session and identity are cached under
|
|
39
|
+
* in `credentials.json` / `config.json`. Deliberately has no dot, so it can
|
|
40
|
+
* never parse as a `<tenant>.<env>` platform context.
|
|
41
|
+
*/
|
|
42
|
+
export declare const REGISTRY_CREDENTIAL_KEY: string;
|
|
43
|
+
/** True when a context name is the reserved registry key. */
|
|
44
|
+
export declare function isReservedRegistryContext(context: string): boolean;
|
|
45
|
+
/** What the registry's platform publishes about itself, plus when we fetched it. */
|
|
46
|
+
export interface RegistryIdentity {
|
|
47
|
+
/** Zitadel issuer URL for the registry's platform. */
|
|
48
|
+
issuer: string;
|
|
49
|
+
/** The CLI's OIDC client id on that issuer. */
|
|
50
|
+
clientId: string;
|
|
51
|
+
/** The `registry-auth` broker that exchanges an id token for a CodeArtifact grant. */
|
|
52
|
+
registryBroker: string;
|
|
53
|
+
/** ISO timestamp of the discovery that produced this record. */
|
|
54
|
+
discoveredAt: string;
|
|
55
|
+
}
|
|
56
|
+
/** Raised when the registry's identity cannot be resolved (offline, endpoint down). */
|
|
57
|
+
export declare class RegistryIdentityError extends MeshCliError {
|
|
58
|
+
constructor(detail: string);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the registry's identity: the cached record under the reserved key,
|
|
62
|
+
* or a fresh anonymous HTTPS discovery on the pinned domain which is then
|
|
63
|
+
* cached there. `refresh: true` skips the cache.
|
|
64
|
+
*
|
|
65
|
+
* Never consults SSM and never takes the domain from anything but the alias
|
|
66
|
+
* table. Throws `RegistryIdentityError` when discovery is impossible and
|
|
67
|
+
* nothing is cached.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const { registryBroker } = await resolveRegistryIdentity();
|
|
71
|
+
* // → "https://registry-auth.dev.platform.meshtech.io"
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveRegistryIdentity(opts?: {
|
|
74
|
+
refresh?: boolean;
|
|
75
|
+
}): Promise<RegistryIdentity>;
|
|
76
|
+
/**
|
|
77
|
+
* The cached contexts whose session can stand in for the registry's: the
|
|
78
|
+
* reserved key first, then the registry's own alias and domain — but only
|
|
79
|
+
* when the cached config for that name points at the SAME issuer, so a
|
|
80
|
+
* pre-repoint `mesh.dev` entry (a different platform) is never mistaken for
|
|
81
|
+
* the registry. With no known issuer (nothing discovered yet) only the
|
|
82
|
+
* reserved key counts: a guess about which platform session "is" the
|
|
83
|
+
* registry is the mistake this function exists to prevent.
|
|
84
|
+
*
|
|
85
|
+
* Pure over the two files' contents; exported for tests.
|
|
86
|
+
*/
|
|
87
|
+
export declare function registrySessionCandidates(issuer: string | null, configs?: Record<string, {
|
|
88
|
+
issuer?: string;
|
|
89
|
+
} | undefined>, credentials?: Record<string, unknown>): string[];
|
|
90
|
+
/** A live registry session and the context key it is cached under. */
|
|
91
|
+
export interface RegistrySession {
|
|
92
|
+
/** Which `credentials.json` entry holds the session (reserved key, alias, or domain). */
|
|
93
|
+
context: string;
|
|
94
|
+
email: string;
|
|
95
|
+
expiresAt: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The registry session as cached right now — no refresh, no network. Null when
|
|
99
|
+
* no candidate context holds an unexpired token.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const s = readRegistrySession();
|
|
103
|
+
* if (s) console.log(`signed in as ${s.email}`);
|
|
104
|
+
*/
|
|
105
|
+
export declare function readRegistrySession(): RegistrySession | null;
|
|
106
|
+
/** Why `ensureRegistrySession` could not produce a session. */
|
|
107
|
+
export type RegistrySessionFailure = {
|
|
108
|
+
ok: false;
|
|
109
|
+
reason: "no-identity";
|
|
110
|
+
detail: string;
|
|
111
|
+
} | {
|
|
112
|
+
ok: false;
|
|
113
|
+
reason: "no-tty";
|
|
114
|
+
detail: string;
|
|
115
|
+
} | {
|
|
116
|
+
ok: false;
|
|
117
|
+
reason: "login-failed";
|
|
118
|
+
detail: string;
|
|
119
|
+
};
|
|
120
|
+
export type RegistrySessionResult = ({
|
|
121
|
+
ok: true;
|
|
122
|
+
} & RegistrySession) | RegistrySessionFailure;
|
|
123
|
+
/**
|
|
124
|
+
* Get a valid Zitadel session for the registry's issuer, signing in when
|
|
125
|
+
* there is none.
|
|
126
|
+
*
|
|
127
|
+
* Reuses ANY cached session whose issuer matches — a developer already signed
|
|
128
|
+
* in to `mesh.dev` gets no second browser trip — refreshing an expired one
|
|
129
|
+
* through its refresh token first. Only when no candidate can be refreshed
|
|
130
|
+
* does it run the sign-in (browser PKCE, or device code with `device: true`
|
|
131
|
+
* or in a remote/non-TTY environment) and store the result under the
|
|
132
|
+
* reserved key.
|
|
133
|
+
*
|
|
134
|
+
* `interactive: false` means "cached or nothing": callers that cannot open a
|
|
135
|
+
* browser or print a device code get `no-tty` back instead of a hung prompt.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* const session = await ensureRegistrySession({ interactive: true });
|
|
139
|
+
* if (session.ok) console.log(session.email);
|
|
140
|
+
*/
|
|
141
|
+
export declare function ensureRegistrySession(opts: {
|
|
142
|
+
device?: boolean;
|
|
143
|
+
interactive: boolean;
|
|
144
|
+
}): Promise<RegistrySessionResult>;
|
|
145
|
+
/**
|
|
146
|
+
* Forget the registry: the session AND the pinned identity record, so the
|
|
147
|
+
* next `mesh registry login` re-discovers the registry from the pinned
|
|
148
|
+
* domain. Clears the reserved key only — a platform session under `mesh.dev`
|
|
149
|
+
* that happened to double as the registry's is a platform login and stays.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* clearRegistrySession(); // `mesh registry logout`
|
|
153
|
+
*/
|
|
154
|
+
export declare function clearRegistrySession(): void;
|
|
155
|
+
/**
|
|
156
|
+
* True when two identity records disagree on anything that matters for a
|
|
157
|
+
* broker call — the signal that a re-discovery is worth a retry.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* identityChanged(a, { ...a, registryBroker: "https://moved" }); // → true
|
|
161
|
+
*/
|
|
162
|
+
export declare function identityChanged(before: RegistryIdentity, after: RegistryIdentity): boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Human-readable time left on a session, e.g. `11h 42m`; `expired` when the
|
|
165
|
+
* expiry has passed. Pure; exported for the status line's test.
|
|
166
|
+
*/
|
|
167
|
+
export declare function describeSessionExpiry(expiresAt: string, now?: number): string;
|
|
168
|
+
/** Log the one-line identity banner `mesh registry login` opens with. */
|
|
169
|
+
export declare function logRegistryIdentity(identity: RegistryIdentity): void;
|
|
170
|
+
//# sourceMappingURL=registry-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-identity.d.ts","sourceRoot":"","sources":["../../../src/utils/registry-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAmBH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;GAIG;AACH,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC,2FAA2F;AAC3F,eAAO,MAAM,eAAe,EAAE,MAM1B,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAkC,CAAC;AAEzE,6DAA6D;AAC7D,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,cAAc,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;CACtB;AASD,uFAAuF;AACvF,qBAAa,qBAAsB,SAAQ,YAAY;gBACzC,MAAM,EAAE,MAAM;CAQ3B;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqBzG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAA2B,EAClF,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAwB,GAC1D,MAAM,EAAE,CAQV;AAED,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,GAAG,IAAI,CAS5D;AAED,+DAA+D;AAC/D,MAAM,MAAM,sBAAsB,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,MAAM,qBAAqB,GAAG,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,eAAe,CAAC,GAAG,sBAAsB,CAAC;AAE9F;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAuDjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAM1F;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAOjF;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAQpE"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE identity behind `@mesh-tech` package access.
|
|
3
|
+
*
|
|
4
|
+
* Every reader of the registry — `pnpm install`, `mesh create-app`,
|
|
5
|
+
* `mesh docs start`, the Hub image build under `mesh start` — talks to the same
|
|
6
|
+
* CodeArtifact domain, and that domain is owned by exactly one Mesh platform:
|
|
7
|
+
* `dev.platform.meshtech.io`. So the registry has a single, global identity
|
|
8
|
+
* (issuer + CLI client id + broker URL) that never depends on which tenant
|
|
9
|
+
* platform, if any, the developer deploys to.
|
|
10
|
+
*
|
|
11
|
+
* This module keeps that identity separate from platform contexts:
|
|
12
|
+
*
|
|
13
|
+
* - The domain comes from the compiled-in first-party alias table and nowhere
|
|
14
|
+
* else — not an argument, not an environment variable, not an unpinned
|
|
15
|
+
* config value. That is the same trust anchor `mesh login` relies on, so the
|
|
16
|
+
* ≥2-dot anti-phishing guard stays intact.
|
|
17
|
+
* - The Zitadel session for the registry is cached under a **reserved**
|
|
18
|
+
* credential key (`registry`) that no `<tenant>.<env>` context can collide
|
|
19
|
+
* with, and `mesh login` / `mesh logout` refuse it.
|
|
20
|
+
* - A developer who already signed in to the registry's own platform
|
|
21
|
+
* (`mesh login mesh.dev`) is reused rather than sent through the browser a
|
|
22
|
+
* second time: any cached session whose issuer matches the registry's counts.
|
|
23
|
+
*
|
|
24
|
+
* Nothing here touches `~/.npmrc` or the broker — that is `mesh registry
|
|
25
|
+
* login`'s job. This module only answers "who is the registry?" and "do I hold
|
|
26
|
+
* a session for it?".
|
|
27
|
+
*/
|
|
28
|
+
import { clearContextConfig, clearCredentials, discoverConfigFromWellKnown, getContextConfig, getValidToken, readAllContextConfigs, readAllCredentials, readCredentials, runLoginFlow, tokenStillValid, writeContextConfig, RESERVED_REGISTRY_CONTEXT, } from "../commands/login.js";
|
|
29
|
+
import { firstPartyDomainFor } from "./first-party-contexts.js";
|
|
30
|
+
import { deriveRegistryBroker } from "./registry-broker.js";
|
|
31
|
+
import { MeshCliError } from "./errors.js";
|
|
32
|
+
import { logInfo } from "./log.js";
|
|
33
|
+
/**
|
|
34
|
+
* The first-party alias of the platform that owns the `@mesh-tech` registry.
|
|
35
|
+
* The alias is the key in `FIRST_PARTY_CONTEXTS`; the domain is looked up
|
|
36
|
+
* from that reviewed table, never typed here twice.
|
|
37
|
+
*/
|
|
38
|
+
export const REGISTRY_ALIAS = "mesh.dev";
|
|
39
|
+
/** The pinned domain anonymous discovery runs against, e.g. `dev.platform.meshtech.io`. */
|
|
40
|
+
export const REGISTRY_DOMAIN = (() => {
|
|
41
|
+
const domain = firstPartyDomainFor(REGISTRY_ALIAS);
|
|
42
|
+
if (!domain) {
|
|
43
|
+
throw new Error(`FIRST_PARTY_CONTEXTS has no entry for the registry alias "${REGISTRY_ALIAS}"`);
|
|
44
|
+
}
|
|
45
|
+
return domain;
|
|
46
|
+
})();
|
|
47
|
+
/**
|
|
48
|
+
* The reserved context name the registry session and identity are cached under
|
|
49
|
+
* in `credentials.json` / `config.json`. Deliberately has no dot, so it can
|
|
50
|
+
* never parse as a `<tenant>.<env>` platform context.
|
|
51
|
+
*/
|
|
52
|
+
export const REGISTRY_CREDENTIAL_KEY = RESERVED_REGISTRY_CONTEXT;
|
|
53
|
+
/** True when a context name is the reserved registry key. */
|
|
54
|
+
export function isReservedRegistryContext(context) {
|
|
55
|
+
return context === REGISTRY_CREDENTIAL_KEY;
|
|
56
|
+
}
|
|
57
|
+
/** Raised when the registry's identity cannot be resolved (offline, endpoint down). */
|
|
58
|
+
export class RegistryIdentityError extends MeshCliError {
|
|
59
|
+
constructor(detail) {
|
|
60
|
+
super(`Could not resolve the Mesh package registry (${detail}).\n` +
|
|
61
|
+
` Discovery endpoint: https://cli.${REGISTRY_DOMAIN}/.well-known/mesh.json`, { remediation: { command: "mesh registry login # retry once you are online" } });
|
|
62
|
+
this.name = "RegistryIdentityError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function toIdentity(cfg) {
|
|
66
|
+
if (!cfg?.issuer || !cfg.clientId)
|
|
67
|
+
return null;
|
|
68
|
+
const registryBroker = cfg.registryBroker ?? deriveRegistryBroker(REGISTRY_CREDENTIAL_KEY, () => cfg);
|
|
69
|
+
if (!registryBroker)
|
|
70
|
+
return null;
|
|
71
|
+
return {
|
|
72
|
+
issuer: cfg.issuer,
|
|
73
|
+
clientId: cfg.clientId,
|
|
74
|
+
registryBroker,
|
|
75
|
+
discoveredAt: cfg.discoveredAt ?? new Date(0).toISOString(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the registry's identity: the cached record under the reserved key,
|
|
80
|
+
* or a fresh anonymous HTTPS discovery on the pinned domain which is then
|
|
81
|
+
* cached there. `refresh: true` skips the cache.
|
|
82
|
+
*
|
|
83
|
+
* Never consults SSM and never takes the domain from anything but the alias
|
|
84
|
+
* table. Throws `RegistryIdentityError` when discovery is impossible and
|
|
85
|
+
* nothing is cached.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* const { registryBroker } = await resolveRegistryIdentity();
|
|
89
|
+
* // → "https://registry-auth.dev.platform.meshtech.io"
|
|
90
|
+
*/
|
|
91
|
+
export async function resolveRegistryIdentity(opts = {}) {
|
|
92
|
+
if (!opts.refresh) {
|
|
93
|
+
const cached = toIdentity(getContextConfig(REGISTRY_CREDENTIAL_KEY));
|
|
94
|
+
if (cached)
|
|
95
|
+
return cached;
|
|
96
|
+
}
|
|
97
|
+
const discovered = await discoverConfigFromWellKnown(REGISTRY_DOMAIN, REGISTRY_CREDENTIAL_KEY, {
|
|
98
|
+
quiet: true,
|
|
99
|
+
});
|
|
100
|
+
if (!discovered) {
|
|
101
|
+
throw new RegistryIdentityError(`discovery on ${REGISTRY_DOMAIN} failed — are you online?`);
|
|
102
|
+
}
|
|
103
|
+
const stored = { ...discovered, discoveredAt: new Date().toISOString() };
|
|
104
|
+
const identity = toIdentity(stored);
|
|
105
|
+
if (!identity) {
|
|
106
|
+
throw new RegistryIdentityError(`the discovery document names no registry broker`);
|
|
107
|
+
}
|
|
108
|
+
writeContextConfig(REGISTRY_CREDENTIAL_KEY, stored);
|
|
109
|
+
return identity;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The cached contexts whose session can stand in for the registry's: the
|
|
113
|
+
* reserved key first, then the registry's own alias and domain — but only
|
|
114
|
+
* when the cached config for that name points at the SAME issuer, so a
|
|
115
|
+
* pre-repoint `mesh.dev` entry (a different platform) is never mistaken for
|
|
116
|
+
* the registry. With no known issuer (nothing discovered yet) only the
|
|
117
|
+
* reserved key counts: a guess about which platform session "is" the
|
|
118
|
+
* registry is the mistake this function exists to prevent.
|
|
119
|
+
*
|
|
120
|
+
* Pure over the two files' contents; exported for tests.
|
|
121
|
+
*/
|
|
122
|
+
export function registrySessionCandidates(issuer, configs = readAllContextConfigs(), credentials = readAllCredentials()) {
|
|
123
|
+
const names = issuer ? [REGISTRY_CREDENTIAL_KEY, REGISTRY_ALIAS, REGISTRY_DOMAIN] : [REGISTRY_CREDENTIAL_KEY];
|
|
124
|
+
return names.filter((name) => {
|
|
125
|
+
if (!(name in credentials))
|
|
126
|
+
return false;
|
|
127
|
+
const cfg = configs[name];
|
|
128
|
+
if (!cfg?.issuer)
|
|
129
|
+
return false;
|
|
130
|
+
return issuer ? cfg.issuer === issuer : true;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The registry session as cached right now — no refresh, no network. Null when
|
|
135
|
+
* no candidate context holds an unexpired token.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* const s = readRegistrySession();
|
|
139
|
+
* if (s) console.log(`signed in as ${s.email}`);
|
|
140
|
+
*/
|
|
141
|
+
export function readRegistrySession() {
|
|
142
|
+
const identity = toIdentity(getContextConfig(REGISTRY_CREDENTIAL_KEY));
|
|
143
|
+
for (const context of registrySessionCandidates(identity?.issuer ?? null)) {
|
|
144
|
+
const creds = readCredentials(context);
|
|
145
|
+
if (creds && tokenStillValid(creds.expiresAt)) {
|
|
146
|
+
return { context, email: creds.email ?? "unknown", expiresAt: creds.expiresAt };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get a valid Zitadel session for the registry's issuer, signing in when
|
|
153
|
+
* there is none.
|
|
154
|
+
*
|
|
155
|
+
* Reuses ANY cached session whose issuer matches — a developer already signed
|
|
156
|
+
* in to `mesh.dev` gets no second browser trip — refreshing an expired one
|
|
157
|
+
* through its refresh token first. Only when no candidate can be refreshed
|
|
158
|
+
* does it run the sign-in (browser PKCE, or device code with `device: true`
|
|
159
|
+
* or in a remote/non-TTY environment) and store the result under the
|
|
160
|
+
* reserved key.
|
|
161
|
+
*
|
|
162
|
+
* `interactive: false` means "cached or nothing": callers that cannot open a
|
|
163
|
+
* browser or print a device code get `no-tty` back instead of a hung prompt.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* const session = await ensureRegistrySession({ interactive: true });
|
|
167
|
+
* if (session.ok) console.log(session.email);
|
|
168
|
+
*/
|
|
169
|
+
export async function ensureRegistrySession(opts) {
|
|
170
|
+
let identity;
|
|
171
|
+
try {
|
|
172
|
+
identity = await resolveRegistryIdentity();
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
return { ok: false, reason: "no-identity", detail: err.message };
|
|
176
|
+
}
|
|
177
|
+
for (const context of registrySessionCandidates(identity.issuer)) {
|
|
178
|
+
const token = await getValidToken(context);
|
|
179
|
+
if (!token)
|
|
180
|
+
continue;
|
|
181
|
+
const creds = readCredentials(context);
|
|
182
|
+
if (creds)
|
|
183
|
+
return { ok: true, context, email: creds.email ?? "unknown", expiresAt: creds.expiresAt };
|
|
184
|
+
}
|
|
185
|
+
if (!opts.interactive) {
|
|
186
|
+
return {
|
|
187
|
+
ok: false,
|
|
188
|
+
reason: "no-tty",
|
|
189
|
+
detail: "no registry session is cached and this run cannot open a sign-in",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// The reserved key gets the registry's identity as its config so the
|
|
193
|
+
// ordinary token machinery (refresh included) works for it unchanged.
|
|
194
|
+
const stored = getContextConfig(REGISTRY_CREDENTIAL_KEY);
|
|
195
|
+
if (!stored) {
|
|
196
|
+
writeContextConfig(REGISTRY_CREDENTIAL_KEY, {
|
|
197
|
+
issuer: identity.issuer,
|
|
198
|
+
clientId: identity.clientId,
|
|
199
|
+
registryBroker: identity.registryBroker,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// Said here, not by the caller: only now is it known that no cached session
|
|
203
|
+
// could be refreshed, so this line never precedes a silent refresh.
|
|
204
|
+
logInfo(opts.device
|
|
205
|
+
? "No registry session — sign in with the device code below…"
|
|
206
|
+
: "No registry session — opening your browser to sign in… (headless? use --device)");
|
|
207
|
+
try {
|
|
208
|
+
await runLoginFlow(REGISTRY_CREDENTIAL_KEY, identity, { device: opts.device });
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
return { ok: false, reason: "login-failed", detail: err.message };
|
|
212
|
+
}
|
|
213
|
+
const creds = readCredentials(REGISTRY_CREDENTIAL_KEY);
|
|
214
|
+
if (!creds) {
|
|
215
|
+
return { ok: false, reason: "login-failed", detail: "sign-in completed but no session was cached" };
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
ok: true,
|
|
219
|
+
context: REGISTRY_CREDENTIAL_KEY,
|
|
220
|
+
email: creds.email ?? "unknown",
|
|
221
|
+
expiresAt: creds.expiresAt,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Forget the registry: the session AND the pinned identity record, so the
|
|
226
|
+
* next `mesh registry login` re-discovers the registry from the pinned
|
|
227
|
+
* domain. Clears the reserved key only — a platform session under `mesh.dev`
|
|
228
|
+
* that happened to double as the registry's is a platform login and stays.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* clearRegistrySession(); // `mesh registry logout`
|
|
232
|
+
*/
|
|
233
|
+
export function clearRegistrySession() {
|
|
234
|
+
clearCredentials(REGISTRY_CREDENTIAL_KEY);
|
|
235
|
+
clearContextConfig(REGISTRY_CREDENTIAL_KEY);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* True when two identity records disagree on anything that matters for a
|
|
239
|
+
* broker call — the signal that a re-discovery is worth a retry.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* identityChanged(a, { ...a, registryBroker: "https://moved" }); // → true
|
|
243
|
+
*/
|
|
244
|
+
export function identityChanged(before, after) {
|
|
245
|
+
return (before.issuer !== after.issuer ||
|
|
246
|
+
before.clientId !== after.clientId ||
|
|
247
|
+
before.registryBroker !== after.registryBroker);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Human-readable time left on a session, e.g. `11h 42m`; `expired` when the
|
|
251
|
+
* expiry has passed. Pure; exported for the status line's test.
|
|
252
|
+
*/
|
|
253
|
+
export function describeSessionExpiry(expiresAt, now = Date.now()) {
|
|
254
|
+
const ms = new Date(expiresAt).getTime() - now;
|
|
255
|
+
if (!(ms > 0))
|
|
256
|
+
return "expired";
|
|
257
|
+
const totalMinutes = Math.floor(ms / 60_000);
|
|
258
|
+
const h = Math.floor(totalMinutes / 60);
|
|
259
|
+
const m = totalMinutes % 60;
|
|
260
|
+
return h > 0 ? `${h}h ${m}m` : `${m}m`;
|
|
261
|
+
}
|
|
262
|
+
/** Log the one-line identity banner `mesh registry login` opens with. */
|
|
263
|
+
export function logRegistryIdentity(identity) {
|
|
264
|
+
let host = identity.registryBroker;
|
|
265
|
+
try {
|
|
266
|
+
host = new URL(identity.registryBroker).host;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// keep the raw value when it is not a URL
|
|
270
|
+
}
|
|
271
|
+
logInfo(`Mesh package registry: mesh-platform (broker ${host})`);
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=registry-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-identity.js","sourceRoot":"","sources":["../../../src/utils/registry-identity.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mesh-tech/mesh-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "CLI for Mesh platform development utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@mesh-tech/agent-contracts": "0.2.0",
|
|
45
|
-
"@mesh-tech/tsconfig": "2.
|
|
45
|
+
"@mesh-tech/tsconfig": "2.3.0",
|
|
46
46
|
"@mesh-tech/workflow-viz": "0.3.0",
|
|
47
47
|
"@tanstack/intent": "^0.3.6",
|
|
48
48
|
"@types/node": "^20.0.0",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"@aws-sdk/client-ssm": "^3.700.0",
|
|
55
55
|
"@aws-sdk/client-sts": "^3.700.0",
|
|
56
56
|
"@inquirer/checkbox": "^4.2.0",
|
|
57
|
+
"@inquirer/confirm": "^5.1.14",
|
|
57
58
|
"@inquirer/input": "^4.2.1",
|
|
58
59
|
"@inquirer/password": "^4.0.17",
|
|
59
60
|
"@inquirer/select": "^4.3.1",
|