@m-kopa/launchpad-cli 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +116 -0
- package/dist/auth/flow.d.ts +7 -3
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/auth/gateway-flow.d.ts +76 -0
- package/dist/auth/gateway-flow.d.ts.map +1 -0
- package/dist/auth/session.d.ts +35 -2
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/cli.js +871 -331
- package/dist/commands/deploy.d.ts +10 -13
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/destroy.d.ts +1 -1
- package/dist/commands/destroy.d.ts.map +1 -1
- package/dist/commands/envvars.d.ts +2 -2
- package/dist/commands/envvars.d.ts.map +1 -1
- package/dist/commands/infer-slug.d.ts +37 -0
- package/dist/commands/infer-slug.d.ts.map +1 -0
- package/dist/commands/login.d.ts +10 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/logout.d.ts +7 -0
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/merge.d.ts +2 -2
- package/dist/commands/merge.d.ts.map +1 -1
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/recover.d.ts +12 -0
- package/dist/commands/recover.d.ts.map +1 -0
- package/dist/commands/review.d.ts +2 -2
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/status.d.ts +13 -3
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/skills/launchpad-content-pr/SKILL.md +1 -1
- package/skills/launchpad-deploy/SKILL.md +1 -1
- package/skills/launchpad-deploy-status/SKILL.md +6 -4
- package/skills/launchpad-destroy/SKILL.md +1 -1
- package/skills/launchpad-onboard/SKILL.md +1 -1
- package/skills/launchpad-status/SKILL.md +13 -6
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,122 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html);
|
|
7
7
|
pre-1.0 minor bumps may carry breaking changes per ADR 0005.
|
|
8
8
|
|
|
9
|
+
## 0.27.0 — 2026-06-12
|
|
10
|
+
|
|
11
|
+
`launchpad login` moves onto the platform's auth gateway (sp-cli7kq
|
|
12
|
+
Task 3, ADR 0026). Dual-path: gateway first, legacy Cloudflare Access
|
|
13
|
+
as a deprecated fallback for the duration of the dual-auth window.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Gateway login is the default.** `launchpad login` now authenticates
|
|
18
|
+
against the auth gateway's `cli-session` grant
|
|
19
|
+
(`auth.launchpad.m-kopa.us`): loopback Authorization-Code + PKCE into
|
|
20
|
+
the Entra SSO, yielding a short-lived (15-minute) RS256 access token
|
|
21
|
+
plus an opaque refresh token that **rotates on every refresh**. No
|
|
22
|
+
discovery, no dynamic client registration — the endpoints are fixed.
|
|
23
|
+
Sessions persist as a new `version: 2` shape in
|
|
24
|
+
`~/.launchpad/session.json` (same location, same `0600` mode); the
|
|
25
|
+
rotated refresh token is persisted atomically (write-rename) **before**
|
|
26
|
+
the new access token is used, so a crash can never strand the session
|
|
27
|
+
on a rotated-away token.
|
|
28
|
+
- **Server-side logout.** `launchpad logout` now revokes gateway
|
|
29
|
+
sessions at the gateway (`POST /__cli_logout`) before clearing the
|
|
30
|
+
local file: refresh dies immediately; in-flight access tokens expire
|
|
31
|
+
within 15 minutes. Offline-safe — if the gateway is unreachable the
|
|
32
|
+
local session is still cleared with a warning, exit code `0`.
|
|
33
|
+
- **Kill-switch.** `LAUNCHPAD_AUTH_LEGACY=1` forces the legacy
|
|
34
|
+
Cloudflare Access login outright (no gateway attempt).
|
|
35
|
+
`LAUNCHPAD_AUTH_GATEWAY_URL` overrides the gateway base URL for
|
|
36
|
+
tests/previews.
|
|
37
|
+
- Gateway `429` rate-limit responses are honoured: short `Retry-After`
|
|
38
|
+
waits are absorbed with a single retry; longer ones surface a clear
|
|
39
|
+
"session intact, retry shortly" error without burning the refresh
|
|
40
|
+
token.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- A revoked / idle-expired (7 days) / capped (30 days) gateway session
|
|
45
|
+
now clears itself locally and prompts ``run `launchpad login` ``;
|
|
46
|
+
authenticated verbs keep the exact exit-`3` contract for auth
|
|
47
|
+
failures.
|
|
48
|
+
- The legacy Cloudflare Access login path is **deprecated but intact**
|
|
49
|
+
— it runs automatically (with a notice) when the gateway flow fails,
|
|
50
|
+
and will be deleted after the dual-auth window closes (AC-DECOM).
|
|
51
|
+
- `launchpad update`'s installer-bearer channel auth (ADR 0023) is
|
|
52
|
+
untouched by all of the above.
|
|
53
|
+
|
|
54
|
+
## 0.26.1 — 2026-06-11
|
|
55
|
+
|
|
56
|
+
Two `launchpad status` UX faults found live by the owner (fast-track,
|
|
57
|
+
type:bug).
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **Slug inference now reads the local manifest** (Fault 1). Bare
|
|
62
|
+
`launchpad status` in a directory named e.g. `AI-Audit-Assistant/`
|
|
63
|
+
containing a valid `launchpad.yaml` (`metadata.name: ai-audit`) used
|
|
64
|
+
to fail with "slug not provided + cannot infer from cwd" — inference
|
|
65
|
+
only knew the `launchpad-app-<slug>` directory-name convention and the
|
|
66
|
+
manifest's own declared slug was ignored. Resolution order is now:
|
|
67
|
+
(1) explicit positional / `--slug`, (2) the local manifest's slug
|
|
68
|
+
(`./launchpad.yaml` or `--file`; v1 `metadata.name` / v2
|
|
69
|
+
`metadata.slug`), (3) the directory-name convention. When the manifest
|
|
70
|
+
and the directory name disagree, the manifest wins with a stderr note.
|
|
71
|
+
Applied consistently across every verb that infers (`status`, `pull`,
|
|
72
|
+
`recover`, `logs`, `review`, `merge`, `envvars`, `destroy`, legacy
|
|
73
|
+
`deploy`) — the five drifted copies of the helper are centralised in
|
|
74
|
+
one module (`recover`'s inference was dirname-first; it is now
|
|
75
|
+
manifest-first like everything else).
|
|
76
|
+
- **`launchpad status <slug>` no longer demands a local manifest**
|
|
77
|
+
(Fault 2). With an explicit (or inferred) slug and no local
|
|
78
|
+
`launchpad.yaml`, status used to exit 2 on ENOENT — after already
|
|
79
|
+
fetching the lifecycle and even saying the app was live in its own
|
|
80
|
+
error text. It now degrades to the live-truth-only view: lifecycle +
|
|
81
|
+
deployment block (live/failed/in-progress, trigger, build outcome,
|
|
82
|
+
standing exceptions) plus a one-line "drift not checked" note, exit 0.
|
|
83
|
+
`--json` carries `"drift": null` and the `live_drift_unknown` state as
|
|
84
|
+
the not-evaluated discriminant. `--strict` without a manifest exits 0
|
|
85
|
+
(drift can't be evaluated; status says so) unless the live build
|
|
86
|
+
itself failed, which exits 1. The hard exit-2 error remains for a
|
|
87
|
+
present-but-unreadable or invalid manifest, and the usage error
|
|
88
|
+
remains when no slug can be resolved at all.
|
|
89
|
+
|
|
90
|
+
(Note: 0.26.0 was never published to npm — a failed docs gate, since
|
|
91
|
+
fixed — so this release ships 0.26.0's `recover` verb and these fixes
|
|
92
|
+
together.)
|
|
93
|
+
|
|
94
|
+
## 0.26.0 — 2026-06-11
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- **`launchpad recover [<slug>]`** (sp-devlp1 AC12). Repairs an app whose
|
|
99
|
+
registry record is stuck at a terminal provisioning failure although the
|
|
100
|
+
app is actually live (the ai-audit class: a since-fixed platform bug
|
|
101
|
+
failed the record after content shipped, leaving `launchpad status`
|
|
102
|
+
short-circuited on the failed lifecycle with no CLI way out). The bot
|
|
103
|
+
verifies LIVE Cloudflare state first — Pages project exists + a
|
|
104
|
+
successful production deployment is serving — and only then reconciles
|
|
105
|
+
the record to `live`, preserving every non-lifecycle field. A not-live
|
|
106
|
+
app is refused with exactly what was checked and the next steps
|
|
107
|
+
(`deploy --resume` / `--abandon` / re-deploy): recover never fabricates
|
|
108
|
+
a live state. Owner/editor/break-glass gated, audited, fail-closed
|
|
109
|
+
(Cloudflare unreachable → nothing changes). Recovering a healthy app is
|
|
110
|
+
a no-op success.
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- **`launchpad deploy` usage text no longer advertises the removed
|
|
115
|
+
`--platform-repo` flag** (apply runs server-side via portal-bot). The
|
|
116
|
+
banner now reflects the real mode surface, and a misused flag (e.g.
|
|
117
|
+
bare `deploy --yes`) prints a pointed one-line error instead of a wall
|
|
118
|
+
of stale usage.
|
|
119
|
+
- **Policy-rejected deploys now say the retry is clean.** A
|
|
120
|
+
bundle-policy / app-boundary / build-command rejection leaves no
|
|
121
|
+
residue (nothing committed, no slug claimed, no staged bundle) — the
|
|
122
|
+
error now states that explicitly: fix the file and re-run
|
|
123
|
+
`launchpad deploy`.
|
|
124
|
+
|
|
9
125
|
## 0.25.0 — 2026-06-11
|
|
10
126
|
|
|
11
127
|
### Changed
|
package/dist/auth/flow.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { type CliSession } from "./session.js";
|
|
1
|
+
import { type AnyCliSession, type CliSession } from "./session.js";
|
|
2
2
|
export declare class LoginRequiredError extends Error {
|
|
3
3
|
readonly code: "login_required";
|
|
4
4
|
}
|
|
5
5
|
/** Refresh-window buffer: refresh `refreshSkewMs` before expiry
|
|
6
6
|
* so a request fired right at the edge doesn't hit a 401. */
|
|
7
7
|
export declare const REFRESH_SKEW_MS = 30000;
|
|
8
|
+
/** A gateway 429 with Retry-After at or under this is absorbed
|
|
9
|
+
* in-process (wait, then retry the refresh ONCE). Anything longer is
|
|
10
|
+
* surfaced to the user instead of silently stalling a verb. */
|
|
11
|
+
export declare const MAX_ABSORBED_RETRY_AFTER_SEC = 10;
|
|
8
12
|
export interface LoginOptions {
|
|
9
13
|
readonly botUrl: string;
|
|
10
14
|
readonly sessionPath: string;
|
|
@@ -32,8 +36,8 @@ export declare function login(opts: LoginOptions): Promise<CliSession>;
|
|
|
32
36
|
* `now` is injected for tests so we can simulate expiry without
|
|
33
37
|
* mocking the system clock.
|
|
34
38
|
*/
|
|
35
|
-
export declare function getValidAccessToken(sessionPath: string, fetcher?: typeof fetch, now?: () => number): Promise<{
|
|
39
|
+
export declare function getValidAccessToken(sessionPath: string, fetcher?: typeof fetch, now?: () => number, sleep?: (ms: number) => Promise<void>): Promise<{
|
|
36
40
|
accessToken: string;
|
|
37
|
-
session:
|
|
41
|
+
session: AnyCliSession;
|
|
38
42
|
}>;
|
|
39
43
|
//# sourceMappingURL=flow.d.ts.map
|
package/dist/auth/flow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/auth/flow.ts"],"names":[],"mappings":"AAwCA,OAAO,
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/auth/flow.ts"],"names":[],"mappings":"AAwCA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,UAAU,EAGhB,MAAM,cAAc,CAAC;AAQtB,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAG,gBAAgB,CAAU;CAC3C;AAED;8DAC8D;AAC9D,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC;;gEAEgE;AAChE,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;sDAEkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CA8DnE;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,OAAO,KAAa,EAC7B,GAAG,GAAE,MAAM,MAAiB,EAC5B,KAAK,GAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CACI,GACtC,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC,CAuD1D"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type GatewayCliSession } from "./session.js";
|
|
2
|
+
export declare const CLI_SESSION_AUTH_PATH = "/__cli_session_auth";
|
|
3
|
+
export declare const CLI_SESSION_TOKEN_PATH = "/__cli_session_token";
|
|
4
|
+
export declare const CLI_LOGOUT_PATH = "/__cli_logout";
|
|
5
|
+
/** The gateway is unreachable or not serving the cli-session grant
|
|
6
|
+
* (404 wrong host / 503 config missing / network error). The login
|
|
7
|
+
* command treats this as "fall back to the legacy flow". */
|
|
8
|
+
export declare class GatewayUnavailableError extends Error {
|
|
9
|
+
readonly code: "gateway_unavailable";
|
|
10
|
+
}
|
|
11
|
+
/** Non-2xx from the session-token or logout endpoint. `httpStatus`
|
|
12
|
+
* lets flow.ts distinguish "session dead — re-login" (400/401) from
|
|
13
|
+
* transient server trouble (5xx). */
|
|
14
|
+
export declare class GatewayTokenError extends Error {
|
|
15
|
+
readonly code: "gateway_token_error";
|
|
16
|
+
readonly httpStatus?: number;
|
|
17
|
+
constructor(message: string, httpStatus?: number);
|
|
18
|
+
}
|
|
19
|
+
/** 429 from the gateway. The request was rejected BEFORE the body was
|
|
20
|
+
* read (the gateway rate-limits pre-parse), so a rate-limited refresh
|
|
21
|
+
* has NOT consumed the refresh token — the session is intact and the
|
|
22
|
+
* caller must NOT clear it. */
|
|
23
|
+
export declare class GatewayRateLimitError extends Error {
|
|
24
|
+
readonly code: "gateway_rate_limited";
|
|
25
|
+
readonly retryAfterSec: number;
|
|
26
|
+
constructor(retryAfterSec: number);
|
|
27
|
+
}
|
|
28
|
+
export interface GatewayTokenPair {
|
|
29
|
+
readonly accessToken: string;
|
|
30
|
+
readonly refreshToken: string;
|
|
31
|
+
readonly expiresInSec: number;
|
|
32
|
+
}
|
|
33
|
+
export interface GatewayLoginOptions {
|
|
34
|
+
readonly gatewayUrl: string;
|
|
35
|
+
readonly sessionPath: string;
|
|
36
|
+
/** Receives the auth URL once the localhost server is bound — the
|
|
37
|
+
* CLI verb prints it so the user can copy-paste if the browser
|
|
38
|
+
* doesn't open. */
|
|
39
|
+
readonly onAuthUrl?: (url: string) => void;
|
|
40
|
+
/** Injection points for tests. */
|
|
41
|
+
readonly fetcher?: typeof fetch;
|
|
42
|
+
readonly browserOpener?: (url: string) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Run the gateway cli-session login and persist the v2 session.
|
|
46
|
+
*
|
|
47
|
+
* Probes the gateway FIRST (one cheap GET) so an unreachable gateway
|
|
48
|
+
* or a host without the grant fails fast with `GatewayUnavailableError`
|
|
49
|
+
* — before any browser opens — and the verb can fall back to the
|
|
50
|
+
* legacy flow instead of hanging on a callback that will never come.
|
|
51
|
+
*/
|
|
52
|
+
export declare function gatewayLogin(opts: GatewayLoginOptions): Promise<GatewayCliSession>;
|
|
53
|
+
/**
|
|
54
|
+
* Refresh-token grant. Returns the new pair — with a ROTATED refresh
|
|
55
|
+
* token the caller MUST persist before first use of the access token
|
|
56
|
+
* (flow.ts owns that ordering). Throws:
|
|
57
|
+
* * GatewayRateLimitError on 429 (token NOT consumed),
|
|
58
|
+
* * GatewayTokenError with httpStatus on any other non-2xx
|
|
59
|
+
* (400/401 = session dead; 5xx = transient),
|
|
60
|
+
* * GatewayTokenError without httpStatus on network failure.
|
|
61
|
+
*/
|
|
62
|
+
export declare function refreshGatewayTokens(params: {
|
|
63
|
+
readonly gatewayUrl: string;
|
|
64
|
+
readonly refreshToken: string;
|
|
65
|
+
}, fetcher?: typeof fetch): Promise<GatewayTokenPair>;
|
|
66
|
+
/**
|
|
67
|
+
* `POST /__cli_logout` — server-side revocation. 204 = revoked (or
|
|
68
|
+
* idempotently already-gone). Throws on anything else; `launchpad
|
|
69
|
+
* logout` catches, warns, and clears the local session anyway (logout
|
|
70
|
+
* must work offline).
|
|
71
|
+
*/
|
|
72
|
+
export declare function revokeGatewaySession(params: {
|
|
73
|
+
readonly gatewayUrl: string;
|
|
74
|
+
readonly refreshToken: string;
|
|
75
|
+
}, fetcher?: typeof fetch): Promise<void>;
|
|
76
|
+
//# sourceMappingURL=gateway-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-flow.d.ts","sourceRoot":"","sources":["../../src/auth/gateway-flow.ts"],"names":[],"mappings":"AA0CA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAC3D,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAC7D,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C;;6DAE6D;AAC7D,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;CAChD;AAED;;sCAEsC;AACtC,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBACjB,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAKjD;AAED;;;gCAGgC;AAChC,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAG,sBAAsB,CAAU;IAChD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;gBACnB,aAAa,EAAE,MAAM;CAOlC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;wBAEoB;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAkD5B;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACtE,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAS3B;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACtE,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,IAAI,CAAC,CAsBf"}
|
package/dist/auth/session.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const SESSION_VERSION = 1;
|
|
2
|
+
export declare const GATEWAY_SESSION_VERSION = 2;
|
|
2
3
|
export interface CliSession {
|
|
3
4
|
readonly version: typeof SESSION_VERSION;
|
|
4
5
|
/** OAuth `access_token`. Sent to the bot as `Authorization: Bearer <accessToken>`. */
|
|
@@ -27,6 +28,38 @@ export interface CliSession {
|
|
|
27
28
|
* by `whoami` (slice 3) for diagnostic display only. */
|
|
28
29
|
readonly issuedAt: string;
|
|
29
30
|
}
|
|
31
|
+
/** A `version: 2` session minted by the auth gateway's cli-session
|
|
32
|
+
* grant (ADR 0026, sp-cli7kq). Differences from the legacy shape:
|
|
33
|
+
* no `clientId`/`tokenEndpoint`/`resource` (the gateway endpoints
|
|
34
|
+
* are fixed — no discovery, no RFC 7591 registration), and the
|
|
35
|
+
* refresh token is OPAQUE and ROTATES on every refresh — a stale
|
|
36
|
+
* copy is not just useless, presenting it after rotation revokes
|
|
37
|
+
* the whole session server-side (the replay tripwire). That makes
|
|
38
|
+
* the write-before-use persistence ordering in `flow.ts`
|
|
39
|
+
* load-bearing, not cosmetic. */
|
|
40
|
+
export interface GatewayCliSession {
|
|
41
|
+
readonly version: typeof GATEWAY_SESSION_VERSION;
|
|
42
|
+
/** Discriminator for future non-gateway v2 shapes; always "gateway". */
|
|
43
|
+
readonly kind: "gateway";
|
|
44
|
+
/** RS256 `typ: cli-session` JWT. Sent to the bot as
|
|
45
|
+
* `Authorization: Bearer <accessToken>`. */
|
|
46
|
+
readonly accessToken: string;
|
|
47
|
+
/** Opaque rotating refresh token (`<jti>.<random>`). NEVER reuse a
|
|
48
|
+
* rotated-away value — the gateway treats reuse as theft. */
|
|
49
|
+
readonly refreshToken: string;
|
|
50
|
+
/** Epoch milliseconds at which `accessToken` ceases to be valid. */
|
|
51
|
+
readonly accessTokenExpiresAt: number;
|
|
52
|
+
/** Base URL of the auth gateway that minted this session — refresh
|
|
53
|
+
* and logout go back to the same issuer. */
|
|
54
|
+
readonly gatewayUrl: string;
|
|
55
|
+
/** ISO-8601 UTC timestamp of when this session was written. */
|
|
56
|
+
readonly issuedAt: string;
|
|
57
|
+
}
|
|
58
|
+
/** Either on-disk session shape. Readers that only need the common
|
|
59
|
+
* fields (accessToken / accessTokenExpiresAt / issuedAt) can stay
|
|
60
|
+
* agnostic; refresh + logout must dispatch on `isGatewaySession`. */
|
|
61
|
+
export type AnyCliSession = CliSession | GatewayCliSession;
|
|
62
|
+
export declare function isGatewaySession(s: AnyCliSession): s is GatewayCliSession;
|
|
30
63
|
export declare class SessionParseError extends Error {
|
|
31
64
|
readonly code: "session_parse_error";
|
|
32
65
|
}
|
|
@@ -37,13 +70,13 @@ export declare class SessionParseError extends Error {
|
|
|
37
70
|
* than to silently re-prompt for login when the storage is
|
|
38
71
|
* actually broken.
|
|
39
72
|
*/
|
|
40
|
-
export declare function readSession(sessionPath: string): Promise<
|
|
73
|
+
export declare function readSession(sessionPath: string): Promise<AnyCliSession | null>;
|
|
41
74
|
/**
|
|
42
75
|
* Atomic-ish write: writes to `<path>.tmp` then renames into
|
|
43
76
|
* place. The whole-directory chmod is best-effort (Windows ignores
|
|
44
77
|
* mode bits) — the per-file mode is the load-bearing one.
|
|
45
78
|
*/
|
|
46
|
-
export declare function writeSession(sessionPath: string, session:
|
|
79
|
+
export declare function writeSession(sessionPath: string, session: AnyCliSession): Promise<void>;
|
|
47
80
|
/**
|
|
48
81
|
* `launchpad logout`: zero out the session file. Idempotent —
|
|
49
82
|
* already-absent file is a no-op success. Returns whether a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,eAAe,CAAC;IACzC,sFAAsF;IACtF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;qDACiD;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;wEACoE;IACpE,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;uCACmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;6CACyC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;;2BAMuB;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;6DACyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;kCAQkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,uBAAuB,CAAC;IACjD,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB;iDAC6C;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;kEAC8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;iDAC6C;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;sEAEsE;AACtE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,iBAAiB,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,IAAI,iBAAiB,CAEzE;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;CAChD;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAsD/B;AA0BD;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQxE"}
|