@mesh-tech/mesh-cli 0.18.1 → 0.19.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.
Files changed (55) hide show
  1. package/README.md +111 -56
  2. package/dist/bin/mesh.js +4843 -4077
  3. package/dist/bin/mesh.js.map +4 -4
  4. package/dist/build-info.json +2 -2
  5. package/dist/src/commands/create-app.d.ts +28 -0
  6. package/dist/src/commands/create-app.d.ts.map +1 -1
  7. package/dist/src/commands/create-app.js +45 -1
  8. package/dist/src/commands/create-app.js.map +1 -1
  9. package/dist/src/commands/dev-doctor.js +2 -2
  10. package/dist/src/commands/dev-doctor.js.map +1 -1
  11. package/dist/src/commands/init/wizard.d.ts +216 -0
  12. package/dist/src/commands/init/wizard.d.ts.map +1 -0
  13. package/dist/src/commands/init/wizard.js +471 -0
  14. package/dist/src/commands/init/wizard.js.map +1 -0
  15. package/dist/src/commands/init.d.ts +14 -6
  16. package/dist/src/commands/init.d.ts.map +1 -1
  17. package/dist/src/commands/init.js +41 -15
  18. package/dist/src/commands/init.js.map +1 -1
  19. package/dist/src/commands/local/dev-local.d.ts.map +1 -1
  20. package/dist/src/commands/local/dev-local.js +6 -0
  21. package/dist/src/commands/local/dev-local.js.map +1 -1
  22. package/dist/src/commands/login.d.ts +76 -5
  23. package/dist/src/commands/login.d.ts.map +1 -1
  24. package/dist/src/commands/login.js +161 -60
  25. package/dist/src/commands/login.js.map +1 -1
  26. package/dist/src/commands/registry.d.ts +133 -10
  27. package/dist/src/commands/registry.d.ts.map +1 -1
  28. package/dist/src/commands/registry.js +238 -86
  29. package/dist/src/commands/registry.js.map +1 -1
  30. package/dist/src/commands/temporal.js +37 -23
  31. package/dist/src/commands/temporal.js.map +3 -3
  32. package/dist/src/docs/registry-docs.d.ts.map +1 -1
  33. package/dist/src/docs/registry-docs.js +8 -3
  34. package/dist/src/docs/registry-docs.js.map +1 -1
  35. package/dist/src/program.d.ts.map +1 -1
  36. package/dist/src/program.js +5 -1
  37. package/dist/src/program.js.map +1 -1
  38. package/dist/src/utils/auth-preflight.d.ts +51 -20
  39. package/dist/src/utils/auth-preflight.d.ts.map +1 -1
  40. package/dist/src/utils/auth-preflight.js +48 -21
  41. package/dist/src/utils/auth-preflight.js.map +1 -1
  42. package/dist/src/utils/mesh-json.d.ts +58 -0
  43. package/dist/src/utils/mesh-json.d.ts.map +1 -0
  44. package/dist/src/utils/mesh-json.js +85 -0
  45. package/dist/src/utils/mesh-json.js.map +1 -0
  46. package/dist/src/utils/registry-broker.d.ts +12 -29
  47. package/dist/src/utils/registry-broker.d.ts.map +1 -1
  48. package/dist/src/utils/registry-broker.js +12 -29
  49. package/dist/src/utils/registry-broker.js.map +1 -1
  50. package/dist/src/utils/registry-identity.d.ts +170 -0
  51. package/dist/src/utils/registry-identity.d.ts.map +1 -0
  52. package/dist/src/utils/registry-identity.js +273 -0
  53. package/dist/src/utils/registry-identity.js.map +1 -0
  54. package/package.json +3 -2
  55. package/skills/core/SKILL.md +13 -8
@@ -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` already cached, checks the
7
- * caller's role, and returns a CodeArtifact token minted with the BROKER's AWS
8
- * identity. No AWS credential of any kind reaches the laptop.
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, readAllCredentials, readAllContextConfigs } from "../commands/login.js";
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 for a CodeArtifact read grant.
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
- * `interactive: false` on the token lookup this runs inside
147
- * `mesh registry login`, which has its own AWS fallback chain, so an expired
148
- * session must return `no-session` rather than stalling a headless run in a
149
- * device-code poll.
130
+ * The token lookup never promptsan 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":"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"}
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.18.1",
3
+ "version": "0.19.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.1.1",
45
+ "@mesh-tech/tsconfig": "2.2.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",