@sequenceholdings/studio-cli 0.1.13 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +258 -38
  2. package/dist/agents/apply-chunks.d.ts +13 -0
  3. package/dist/agents/apply-chunks.js +43 -0
  4. package/dist/agents/commands.d.ts +10 -0
  5. package/dist/agents/commands.js +218 -0
  6. package/dist/agents/scaffold.d.ts +2 -0
  7. package/dist/agents/scaffold.js +77 -0
  8. package/dist/agents/source.d.ts +18 -0
  9. package/dist/agents/source.js +121 -0
  10. package/dist/artifact/delegate.d.ts +2 -2
  11. package/dist/artifact/delegate.js +31 -73
  12. package/dist/atlas-client.js +52 -37
  13. package/dist/auth-cmds/commands.d.ts +1 -1
  14. package/dist/auth-cmds/commands.js +12 -7
  15. package/dist/auth.d.ts +104 -24
  16. package/dist/auth.js +456 -94
  17. package/dist/config.d.ts +3 -3
  18. package/dist/config.js +18 -13
  19. package/dist/env-catalog.js +13 -3
  20. package/dist/env-flags.d.ts +2 -0
  21. package/dist/env-flags.js +2 -0
  22. package/dist/env-registry.d.ts +27 -0
  23. package/dist/env-registry.js +204 -0
  24. package/dist/envs/commands.d.ts +1 -1
  25. package/dist/envs/commands.js +41 -3
  26. package/dist/file-lock.d.ts +5 -0
  27. package/dist/file-lock.js +187 -0
  28. package/dist/functions/commands.d.ts +10 -10
  29. package/dist/functions/commands.js +87 -53
  30. package/dist/functions/manifest.d.ts +1 -0
  31. package/dist/functions/manifest.js +36 -0
  32. package/dist/functions/source-selection.d.ts +24 -0
  33. package/dist/functions/source-selection.js +67 -0
  34. package/dist/login.d.ts +8 -3
  35. package/dist/login.js +46 -34
  36. package/dist/main.d.ts +3 -1
  37. package/dist/main.js +41 -12
  38. package/dist/orm/delegate.js +25 -7
  39. package/dist/pat-hints.js +2 -2
  40. package/dist/pipeline/commands.d.ts +58 -0
  41. package/dist/pipeline/commands.js +330 -0
  42. package/dist/pipeline/lifecycle.d.ts +58 -0
  43. package/dist/pipeline/lifecycle.js +348 -0
  44. package/dist/pipeline/pinning.d.ts +5 -0
  45. package/dist/pipeline/pinning.js +9 -0
  46. package/dist/pipeline/templates.d.ts +11 -0
  47. package/dist/pipeline/templates.js +166 -0
  48. package/dist/process/build.d.ts +4 -0
  49. package/dist/process/build.js +33 -2
  50. package/dist/process/codegen.js +19 -1
  51. package/dist/process/commands.js +97 -47
  52. package/dist/process/compiler-subprocess.d.ts +29 -0
  53. package/dist/process/compiler-subprocess.js +99 -0
  54. package/dist/process/compiler-worker.d.ts +1 -0
  55. package/dist/process/compiler-worker.js +38 -0
  56. package/dist/process/lint.d.ts +8 -0
  57. package/dist/process/lint.js +84 -29
  58. package/dist/process/repo-install.js +18 -2
  59. package/dist/repos/commands.d.ts +1 -1
  60. package/dist/repos/commands.js +17 -12
  61. package/dist/secrets/commands.d.ts +1 -1
  62. package/dist/secrets/commands.js +18 -18
  63. package/package.json +12 -5
@@ -4,6 +4,7 @@
4
4
  * consistent across both Sequence CLIs. Token + baseUrl are passed in by
5
5
  * the caller — this file knows nothing about token files or config TOMLs.
6
6
  */
7
+ import { authenticatedRequestUrl } from '@sequenceholdings/artifact-studio/deployment-validation';
7
8
  import { PREVIEW_DOMAIN } from './preview.js';
8
9
  const MAX_503_RETRIES = 5;
9
10
  const DEFAULT_RETRY_AFTER_SECONDS = 2;
@@ -34,6 +35,18 @@ async function fetchWith503Retry(input, init) {
34
35
  await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
35
36
  }
36
37
  }
38
+ async function authenticatedFetch({ baseUrl, init = {}, path, token, }) {
39
+ const url = authenticatedRequestUrl({ baseUrl, path });
40
+ return fetchWith503Retry(url, {
41
+ ...init,
42
+ redirect: 'manual',
43
+ headers: {
44
+ ...previewAccessHeaders(baseUrl),
45
+ ...init.headers,
46
+ Authorization: `Bearer ${token}`,
47
+ },
48
+ });
49
+ }
37
50
  function previewAccessHeaders(baseUrl) {
38
51
  const secret = process.env.PREVIEW_ACCESS_HEADER?.trim();
39
52
  if (!secret)
@@ -89,17 +102,13 @@ async function responseError(response, path) {
89
102
  return new AtlasApiError(response.status, message, path, response.statusText, body);
90
103
  }
91
104
  export async function getJson({ baseUrl, token, path, }) {
92
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
93
- headers: { ...previewAccessHeaders(baseUrl), Authorization: `Bearer ${token}` },
94
- });
105
+ const response = await authenticatedFetch({ baseUrl, token, path });
95
106
  if (!response.ok)
96
107
  throw await responseError(response, path);
97
108
  return response.json();
98
109
  }
99
110
  export async function getJsonOr404({ baseUrl, token, path, }) {
100
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
101
- headers: { ...previewAccessHeaders(baseUrl), Authorization: `Bearer ${token}` },
102
- });
111
+ const response = await authenticatedFetch({ baseUrl, token, path });
103
112
  if (response.status === 404)
104
113
  return null;
105
114
  if (!response.ok)
@@ -107,56 +116,60 @@ export async function getJsonOr404({ baseUrl, token, path, }) {
107
116
  return response.json();
108
117
  }
109
118
  export async function postJson({ baseUrl, token, path, body, }) {
110
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
111
- method: 'POST',
112
- headers: {
113
- ...previewAccessHeaders(baseUrl),
114
- Authorization: `Bearer ${token}`,
115
- 'Content-Type': 'application/json',
119
+ const response = await authenticatedFetch({
120
+ baseUrl,
121
+ token,
122
+ path,
123
+ init: {
124
+ method: 'POST',
125
+ headers: { 'Content-Type': 'application/json' },
126
+ body: body === undefined ? undefined : JSON.stringify(body),
116
127
  },
117
- body: body === undefined ? undefined : JSON.stringify(body),
118
128
  });
119
129
  if (!response.ok)
120
130
  throw await responseError(response, path);
121
131
  return response.json();
122
132
  }
123
133
  export async function putJson({ baseUrl, token, path, body, }) {
124
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
125
- method: 'PUT',
126
- headers: {
127
- ...previewAccessHeaders(baseUrl),
128
- Authorization: `Bearer ${token}`,
129
- 'Content-Type': 'application/json',
134
+ const response = await authenticatedFetch({
135
+ baseUrl,
136
+ token,
137
+ path,
138
+ init: {
139
+ method: 'PUT',
140
+ headers: { 'Content-Type': 'application/json' },
141
+ body: body === undefined ? undefined : JSON.stringify(body),
130
142
  },
131
- body: body === undefined ? undefined : JSON.stringify(body),
132
143
  });
133
144
  if (!response.ok)
134
145
  throw await responseError(response, path);
135
146
  return response.json();
136
147
  }
137
148
  export async function patchJson({ baseUrl, token, path, body, }) {
138
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
139
- method: 'PATCH',
140
- headers: {
141
- ...previewAccessHeaders(baseUrl),
142
- Authorization: `Bearer ${token}`,
143
- 'Content-Type': 'application/json',
149
+ const response = await authenticatedFetch({
150
+ baseUrl,
151
+ token,
152
+ path,
153
+ init: {
154
+ method: 'PATCH',
155
+ headers: { 'Content-Type': 'application/json' },
156
+ body: body === undefined ? undefined : JSON.stringify(body),
144
157
  },
145
- body: body === undefined ? undefined : JSON.stringify(body),
146
158
  });
147
159
  if (!response.ok)
148
160
  throw await responseError(response, path);
149
161
  return response.json();
150
162
  }
151
163
  export async function deleteJson({ baseUrl, token, path, body, }) {
152
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
153
- method: 'DELETE',
154
- headers: {
155
- ...previewAccessHeaders(baseUrl),
156
- Authorization: `Bearer ${token}`,
157
- 'Content-Type': 'application/json',
164
+ const response = await authenticatedFetch({
165
+ baseUrl,
166
+ token,
167
+ path,
168
+ init: {
169
+ method: 'DELETE',
170
+ headers: { 'Content-Type': 'application/json' },
171
+ body: body === undefined ? undefined : JSON.stringify(body),
158
172
  },
159
- body: body === undefined ? undefined : JSON.stringify(body),
160
173
  });
161
174
  if (!response.ok)
162
175
  throw await responseError(response, path);
@@ -164,9 +177,11 @@ export async function deleteJson({ baseUrl, token, path, body, }) {
164
177
  }
165
178
  /** DELETE for endpoints that return 204 with an empty body (deleteJson would choke on it). */
166
179
  export async function deleteNoContent({ baseUrl, token, path, }) {
167
- const response = await fetchWith503Retry(`${baseUrl}${path}`, {
168
- method: 'DELETE',
169
- headers: { ...previewAccessHeaders(baseUrl), Authorization: `Bearer ${token}` },
180
+ const response = await authenticatedFetch({
181
+ baseUrl,
182
+ token,
183
+ path,
184
+ init: { method: 'DELETE' },
170
185
  });
171
186
  if (!response.ok)
172
187
  throw await responseError(response, path);
@@ -1,7 +1,7 @@
1
1
  import type { ParsedArgs } from '../process/commands.js';
2
2
  declare const PAT_SCOPES: readonly ["repo:read", "repo:write", "repo:admin"];
3
3
  type PatScope = (typeof PAT_SCOPES)[number];
4
- export declare const AUTH_USAGE = "usage:\n seq-studio auth pat create --name <n> [--scopes repo:read,repo:write] [-e env]\n [--expires 7d|30d|90d|1y|never] [--store-credentials]\n seq-studio auth pat list [-e env]\n seq-studio auth pat revoke <id> [-e env] [--yes]\n\n Issue a personal access token for git clone / git push against the platform\n git service.\n\n Authenticate with `seq-studio login`, then run `auth pat create`.\n Alternatively, open Atlas \u2192 Settings \u2192 Tokens:\n https://<atlas-host>/settings/tokens\n Sign in, create a token (repo:read / repo:write), copy once, then:\n export ATLAS_GIT_PAT=<token>\n\n On create the raw token is printed ONCE \u2014 store it; Atlas cannot re-show it.\n Git Basic auth: any username (e.g. git), PAT as the password.\n\n Flags: -e/--env <env> (see: seq-studio envs list)\n";
4
+ export declare const AUTH_USAGE = "usage:\n seq-studio auth pat create --name <n> -e <env> [--scopes repo:read,repo:write]\n [--expires 7d|30d|90d|1y|never] [--store-credentials]\n seq-studio auth pat list -e <env>\n seq-studio auth pat revoke <id> -e <env> [--yes]\n\n Issue a personal access token for git clone / git push against the platform\n git service.\n\n Authenticate with `seq-studio login`, then run `auth pat create -e <env>`.\n Alternatively, open Atlas \u2192 Settings \u2192 Tokens:\n https://<atlas-host>/settings/tokens\n Sign in, create a token (repo:read / repo:write), copy once, then:\n export ATLAS_GIT_PAT=<token>\n\n On create the raw token is printed ONCE \u2014 store it; Atlas cannot re-show it.\n Git Basic auth: any username (e.g. git), PAT as the password.\n\n Flags: -e/--env <env> (required; see: seq-studio envs list)\n";
5
5
  export declare function parsePatScopes(raw: string | undefined): PatScope[];
6
6
  /**
7
7
  * Map UI-style duration choices to an absolute ISO-8601 expiresAt, or undefined
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { deleteNoContent, getJson, postJson } from '../atlas-client.js';
12
12
  import { printCliError } from '../cli-errors.js';
13
+ import { REQUIRE_EXPLICIT_ENV_MESSAGE } from '../env-flags.js';
13
14
  import { buildContext, clientOptions, flagBool, LOG, } from '../functions/commands.js';
14
15
  import { readConfig } from '../config.js';
15
16
  import { confirmYes } from '../prompt.js';
@@ -38,15 +39,15 @@ function stringFlag(flags, key) {
38
39
  return value;
39
40
  }
40
41
  export const AUTH_USAGE = `usage:
41
- seq-studio auth pat create --name <n> [--scopes repo:read,repo:write] [-e env]
42
+ seq-studio auth pat create --name <n> -e <env> [--scopes repo:read,repo:write]
42
43
  [--expires 7d|30d|90d|1y|never] [--store-credentials]
43
- seq-studio auth pat list [-e env]
44
- seq-studio auth pat revoke <id> [-e env] [--yes]
44
+ seq-studio auth pat list -e <env>
45
+ seq-studio auth pat revoke <id> -e <env> [--yes]
45
46
 
46
47
  Issue a personal access token for git clone / git push against the platform
47
48
  git service.
48
49
 
49
- Authenticate with \`seq-studio login\`, then run \`auth pat create\`.
50
+ Authenticate with \`seq-studio login\`, then run \`auth pat create -e <env>\`.
50
51
  Alternatively, open Atlas → Settings → Tokens:
51
52
  https://<atlas-host>/settings/tokens
52
53
  Sign in, create a token (repo:read / repo:write), copy once, then:
@@ -55,7 +56,7 @@ export const AUTH_USAGE = `usage:
55
56
  On create the raw token is printed ONCE — store it; Atlas cannot re-show it.
56
57
  Git Basic auth: any username (e.g. git), PAT as the password.
57
58
 
58
- Flags: -e/--env <env> (see: seq-studio envs list)
59
+ Flags: -e/--env <env> (required; see: seq-studio envs list)
59
60
  `;
60
61
  async function authContext(args) {
61
62
  if (args.flags.env === true || args.flags.e === true) {
@@ -66,6 +67,10 @@ async function authContext(args) {
66
67
  }
67
68
  catch (err) {
68
69
  const message = err instanceof Error ? err.message : String(err);
70
+ // Missing `-e` is actionable on its own — don't bury it under login/PAT
71
+ // setup advice (that wrap is for real auth/token failures).
72
+ if (message === REQUIRE_EXPLICIT_ENV_MESSAGE)
73
+ throw err;
69
74
  // buildContext failed before we know the env URL; offer CLI login and
70
75
  // render the tokens-page URLs from the environments visible to this
71
76
  // identity (third-party / OpCo developers only see their own hosts).
@@ -119,7 +124,7 @@ export function resolveExpiresAt(choice) {
119
124
  export async function authPatCreateCommand(args) {
120
125
  const name = stringFlag(args.flags, 'name');
121
126
  if (!name) {
122
- console.error('usage: seq-studio auth pat create --name <n> [--scopes ...] [-e env]');
127
+ console.error('usage: seq-studio auth pat create --name <n> -e <env> [--scopes ...]');
123
128
  return 1;
124
129
  }
125
130
  if (name.length < 3) {
@@ -193,7 +198,7 @@ export async function authPatListCommand(args) {
193
198
  export async function authPatRevokeCommand(args) {
194
199
  const id = args.positional[0];
195
200
  if (!id) {
196
- console.error('usage: seq-studio auth pat revoke <id> [-e env] [--yes]');
201
+ console.error('usage: seq-studio auth pat revoke <id> -e <env> [--yes]');
197
202
  return 1;
198
203
  }
199
204
  const ctx = await authContext(args);
package/dist/auth.d.ts CHANGED
@@ -5,27 +5,66 @@
5
5
  *
6
6
  * Two token sources, in the SAME precedence order as seqapi's
7
7
  * `get_access_token` (`shared/seqapi/seqapi/auth.py`):
8
- * 1. M2M service accountAuth0 client-credentials grant, used when
9
- * `AUTH0_M2M_CLIENT_SECRET` is set. This is the headless path: CI /
10
- * cloud agents with no interactive login can still push.
8
+ * 1. Cached user access token read from the seqapi token file. When it
9
+ * expires, an interactive session performs a bounded PKCE login again.
10
+ * 2. M2M service account Auth0 client-credentials grant when the realm's
11
+ * `AUTH0_M2M_CLIENT_SECRET` (or suffixed OpCo variant) is set. Used when
12
+ * no valid user session exists, or when `SEQAPI_AUTH_MODE=m2m` forces it.
11
13
  * (M2M carries app scopes but NO user identity / workspace membership
12
14
  * — see the `atlas-test-access` rule.)
13
- * 2. Cached user token — read from the seqapi token file and refreshed
14
- * via the Auth0 refresh-token grant when near expiry.
15
15
  *
16
- * Login and refresh both write the shared file. This mirrors
17
- * `seqapi._save_tokens` exactly:
16
+ * Login writes the shared file. This mirrors `seqapi._save_tokens` exactly:
18
17
  * same fields, same shape, same 0o600 permissions, atomic write via
19
- * tmpfile + rename. The M2M token is in-memory only (never persisted).
18
+ * tmpfile + rename. M2M tokens are cached in-process and also under the
19
+ * token file's `m2m` key so short-lived CLI processes reuse a grant.
20
20
  */
21
21
  export declare const AUTH0_DOMAIN = "dev-n1t8ts403fp8oyxp.us.auth0.com";
22
22
  export declare const AUTH0_CLIENT_ID = "GD9riCDWocfc66odpWBjwBiX43qqAX8r";
23
23
  export declare const AUTH0_AUDIENCE = "https://api.studio.com";
24
+ /** The realm name the built-in Sequence environments' tokens live under —
25
+ * also the implicit realm of the legacy flat fields in tokens.json. */
26
+ export declare const SEQUENCE_REALM = "sequence";
27
+ export declare function isSequenceAuthEnvName(envName: string): boolean;
28
+ /**
29
+ * One Auth0 login context. Mirrors seqapi's `AuthRealm`
30
+ * (`shared/seqapi/seqapi/config.py`): the Sequence realm is hard-coded;
31
+ * OpCo-environment realms are read from seqapi's config.json registry,
32
+ * written by `seq-studio envs add` or `seqapi env add` — both CLIs share one
33
+ * registry and one token file, so either can log in and the other picks the
34
+ * session up.
35
+ */
36
+ export interface AuthRealm {
37
+ name: string;
38
+ domain: string;
39
+ clientId: string;
40
+ audience: string;
41
+ organization?: string;
42
+ m2mClientId?: string;
43
+ }
44
+ /**
45
+ * A discovery response is not a trust anchor for the host that receives an
46
+ * M2M client secret. Even another valid *.auth0.com tenant is untrusted;
47
+ * additional Auth0 tenants/custom domains require an explicit code-reviewed
48
+ * allowlist entry.
49
+ */
50
+ export declare function validateAuth0Domain(domain: string): string;
51
+ export declare const SEQUENCE_AUTH_REALM: AuthRealm;
24
52
  export interface SeqapiTokens {
25
- refresh_token?: string;
26
53
  access_token?: string;
27
54
  expires_at?: number;
28
55
  }
56
+ /**
57
+ * Resolve the auth realm for an environment name. Undefined, built-ins, and
58
+ * per-PR preview targets map to the shared Sequence realm. Preview URLs are
59
+ * constrained to Sequence's preview domain by the environment resolver. Every
60
+ * other explicit name must have a valid seqapi registry entry; otherwise fail
61
+ * closed so a shared Sequence bearer token can never be sent to a tenant URL.
62
+ */
63
+ export declare function realmForEnv(envName?: string): Promise<AuthRealm>;
64
+ /** Env var(s) carrying a realm's M2M client secret — the Sequence realm keeps
65
+ * the legacy bare name; OpCo realms use a suffixed name so one shell can hold
66
+ * several credentials unambiguously. Mirrors seqapi's `_m2m_secret_env_names`. */
67
+ export declare function m2mSecretEnvName(realm: AuthRealm): string;
29
68
  /**
30
69
  * A configured M2M credential failed to mint a token. Typed so callers that
31
70
  * normally swallow discovery errors (lazy catalog refresh) can still surface
@@ -38,38 +77,79 @@ export declare function seqapiTokenDir(): string;
38
77
  export declare function seqapiTokenPath(): string;
39
78
  export declare class NotLoggedInError extends Error {
40
79
  readonly name = "NotLoggedInError";
41
- constructor();
80
+ constructor(realmName?: string, reason?: string);
42
81
  }
43
82
  /**
44
- * Return a valid access token. Tries the M2M service account first when
45
- * `AUTH0_M2M_CLIENT_SECRET` is set, then falls back to the cached user
46
- * token (refreshed via the Auth0 refresh-token grant when within 60s of
47
- * expiry). Same precedence as seqapi's `get_access_token`, so both CLIs
48
- * resolve the same identity for the same environment.
83
+ * Return a valid access token for an environment's auth realm.
84
+ *
85
+ * Precedence (default `SEQAPI_AUTH_MODE=auto`), matching seqapi:
86
+ * 1. Valid cached user access token
87
+ * 2. M2M client-credentials when the realm's secret env var is set
88
+ * 3. Bounded PKCE login when browser auto-login is enabled
89
+ *
90
+ * Set `SEQAPI_AUTH_MODE=m2m` to skip the user token. No `env` (or a built-in
91
+ * Sequence env) means the shared Sequence realm.
49
92
  */
50
- export declare function getAccessToken(): Promise<string>;
93
+ export declare class UnsafeAuthTargetError extends Error {
94
+ }
95
+ export type AuthMode = 'm2m' | 'user';
96
+ export interface ResolvedAccessToken {
97
+ authMode: AuthMode;
98
+ token: string;
99
+ }
100
+ export declare function getAccessTokenWithMode(options?: {
101
+ /** Disable browser PKCE fallback for probe-only and other non-interactive callers. */
102
+ allowInteractiveLogin?: boolean;
103
+ env?: string;
104
+ targetUrl?: string;
105
+ }): Promise<ResolvedAccessToken>;
106
+ export declare function getAccessToken(options?: {
107
+ /** Disable browser PKCE fallback for probe-only and other non-interactive callers. */
108
+ allowInteractiveLogin?: boolean;
109
+ env?: string;
110
+ targetUrl?: string;
111
+ }): Promise<string>;
51
112
  /**
52
113
  * Try to load a token without throwing. Returns `null` for any error
53
114
  * condition (missing file, parse error, no token fields). Used by
54
115
  * `doctor` for non-fatal "are you logged in?" checks.
55
116
  */
56
- export declare function tryGetAccessToken(options?: {
117
+ export declare function tryGetAccessTokenWithMode(options?: {
57
118
  /**
58
119
  * When the M2M secret is configured, failing to mint an M2M token should fail
59
120
  * closed (avoid silently falling back to some other cached identity).
60
121
  */
61
122
  failClosedForM2m?: boolean;
123
+ /** Environment name — selects the auth realm (default: Sequence). */
124
+ env?: string;
125
+ /** Resolved request origin — checked against the realm before returning credentials. */
126
+ targetUrl?: string;
127
+ }): Promise<ResolvedAccessToken | null>;
128
+ export declare function tryGetAccessToken(options?: {
129
+ failClosedForM2m?: boolean;
130
+ env?: string;
131
+ targetUrl?: string;
62
132
  }): Promise<string | null>;
63
133
  /**
64
- * Decode the `sub` claim from a JWT without verification. Verification is the
65
- * server's job this is only used to compare identities locally (e.g. to
66
- * bind the cached environment catalog to the identity that fetched it).
134
+ * Refuse to persist a token minted for another audience or Auth0
135
+ * organization. Auth0/server-side JWT verification remains authoritative;
136
+ * this local decode is only a cross-realm confusion check on a token received
137
+ * directly from the configured Auth0 tenant over TLS.
67
138
  */
139
+ export declare function verifyTokenMatchesRealm({ accessToken, realm, requireOrganization, }: {
140
+ accessToken: string;
141
+ realm: AuthRealm;
142
+ requireOrganization?: boolean;
143
+ }): void;
68
144
  export declare function decodeJwtSub(token: string): string | null;
69
145
  /**
70
146
  * The Auth0 subject the CLI would authenticate as right now, without any
71
- * network call: the fixed M2M client subject when the secret is configured,
72
- * else the `sub` of the cached user token, else null (anonymous).
147
+ * network call. Matches token resolution precedence: a valid user session
148
+ * wins over an ambient M2M secret unless `SEQAPI_AUTH_MODE=m2m`.
73
149
  */
74
- export declare function currentIdentitySubject(): Promise<string | null>;
75
- export declare function saveTokens(tokens: SeqapiTokens): Promise<void>;
150
+ export declare function currentIdentitySubject(options?: {
151
+ env?: string;
152
+ }): Promise<string | null>;
153
+ export declare function loadCachedUserTokens(realmName?: string): Promise<SeqapiTokens | null>;
154
+ export declare function saveTokens(tokens: SeqapiTokens, realmName?: string): Promise<void>;
155
+ export declare function deleteRealmTokens(realmName: string): Promise<void>;