@sanity/cli 6.5.2 → 6.6.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 +6 -1
- package/bin/run.js +3 -1
- package/dist/actions/auth/login/login.js +35 -12
- package/dist/actions/auth/login/login.js.map +1 -1
- package/dist/actions/auth/login/validateToken.js +39 -0
- package/dist/actions/auth/login/validateToken.js.map +1 -0
- package/dist/commands/login.js +28 -5
- package/dist/commands/login.js.map +1 -1
- package/oclif.manifest.json +19 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2489,13 +2489,14 @@ Log in to your Sanity account
|
|
|
2489
2489
|
|
|
2490
2490
|
```
|
|
2491
2491
|
USAGE
|
|
2492
|
-
$ sanity login [--open] [--provider <providerId> | --sso <slug>] [--sso-provider <name> ]
|
|
2492
|
+
$ sanity login [--open] [--provider <providerId> | --sso <slug> | --with-token] [--sso-provider <name> ]
|
|
2493
2493
|
|
|
2494
2494
|
FLAGS
|
|
2495
2495
|
--[no-]open Open a browser window to log in (`--no-open` only prints URL)
|
|
2496
2496
|
--provider=<providerId> Log in using the given provider
|
|
2497
2497
|
--sso=<slug> Log in using Single Sign-On, using the given organization slug
|
|
2498
2498
|
--sso-provider=<name> Select a specific SSO provider by name (use with --sso)
|
|
2499
|
+
--with-token Read token from standard input
|
|
2499
2500
|
|
|
2500
2501
|
DESCRIPTION
|
|
2501
2502
|
Log in to your Sanity account
|
|
@@ -2516,6 +2517,10 @@ EXAMPLES
|
|
|
2516
2517
|
Log in using a specific SSO provider within an organization
|
|
2517
2518
|
|
|
2518
2519
|
$ sanity login --sso my-organization --sso-provider "Okta SSO"
|
|
2520
|
+
|
|
2521
|
+
Log in using a token from standard input
|
|
2522
|
+
|
|
2523
|
+
$ sanity login --with-token < token.txt
|
|
2519
2524
|
```
|
|
2520
2525
|
|
|
2521
2526
|
## `sanity logout`
|
package/bin/run.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {execute} from '@oclif/core'
|
|
2
|
+
import {execute, settings} from '@oclif/core'
|
|
3
3
|
|
|
4
4
|
var err = '\u001B[31m\u001B[1mERROR:\u001B[22m\u001B[39m '
|
|
5
5
|
var nodeVersionParts = process.version.replace(/^v/i, '').split('.').map(Number)
|
|
@@ -30,4 +30,6 @@ if (!isSupportedNodeVersion(majorVersion, minorVersion, patchVersion)) {
|
|
|
30
30
|
process.exit(1)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
settings.enableAutoTranspile = false
|
|
34
|
+
|
|
33
35
|
await execute({dir: import.meta.url})
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { getCliToken, getUserConfig, setCliUserConfig, subdebug } from '@sanity/cli-core';
|
|
2
2
|
import { spinner } from '@sanity/cli-core/ux';
|
|
3
|
+
import { isHttpError } from '@sanity/client';
|
|
3
4
|
import open from 'open';
|
|
4
5
|
import { logout } from '../../../services/auth.js';
|
|
5
6
|
import { LoginTrace } from '../../../telemetry/login.telemetry.js';
|
|
6
7
|
import { canLaunchBrowser } from '../../../util/canLaunchBrowser.js';
|
|
7
8
|
import { startServerForTokenCallback } from '../authServer.js';
|
|
8
9
|
import { getProvider } from './getProvider.js';
|
|
10
|
+
import { isSanityApiToken, validateToken } from './validateToken.js';
|
|
9
11
|
const debug = subdebug('login');
|
|
10
12
|
/**
|
|
11
13
|
* Trigger the authentication flow for the CLI.
|
|
12
14
|
*
|
|
13
|
-
* NOTE:
|
|
15
|
+
* NOTE: Without a token option, this uses terminal prompts and will not work for
|
|
16
|
+
* non-interactive/programmatic uses.
|
|
14
17
|
*
|
|
15
18
|
* @param options - Options for the login operation
|
|
16
19
|
* @returns Promise that resolves when the login operation is complete
|
|
@@ -19,9 +22,19 @@ const debug = subdebug('login');
|
|
|
19
22
|
*/ export async function login(options) {
|
|
20
23
|
const { output, telemetry } = options;
|
|
21
24
|
const previousToken = await getCliToken();
|
|
22
|
-
const hasExistingToken = Boolean(previousToken);
|
|
23
25
|
const trace = telemetry.trace(LoginTrace);
|
|
24
26
|
trace.start();
|
|
27
|
+
if (typeof options.token === 'string') {
|
|
28
|
+
try {
|
|
29
|
+
const authToken = await validateToken(options.token);
|
|
30
|
+
await storeAuthToken(authToken, previousToken, output);
|
|
31
|
+
trace.complete();
|
|
32
|
+
} catch (err) {
|
|
33
|
+
trace.error(err);
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
25
38
|
const provider = await getProvider({
|
|
26
39
|
experimental: options.experimental,
|
|
27
40
|
orgSlug: options.sso,
|
|
@@ -62,20 +75,30 @@ const debug = subdebug('login');
|
|
|
62
75
|
server.close(()=>resolve());
|
|
63
76
|
});
|
|
64
77
|
}
|
|
65
|
-
|
|
78
|
+
await storeAuthToken(authToken, previousToken, output);
|
|
79
|
+
trace.complete();
|
|
80
|
+
}
|
|
81
|
+
async function storeAuthToken(authToken, previousToken, output) {
|
|
66
82
|
setCliUserConfig('authToken', authToken);
|
|
67
|
-
// Clear cached telemetry consent
|
|
68
83
|
getUserConfig().delete('telemetryConsent');
|
|
69
84
|
// If we had a session previously, attempt to clear it
|
|
70
|
-
if (
|
|
71
|
-
await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
if (previousToken && previousToken !== authToken) {
|
|
86
|
+
await invalidateAuthToken(previousToken, output);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function invalidateAuthToken(token, output) {
|
|
90
|
+
try {
|
|
91
|
+
if (await isSanityApiToken(token)) return;
|
|
92
|
+
} catch (err) {
|
|
93
|
+
if (isHttpError(err) && err.statusCode === 401) return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
await logout(token);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
if (!isHttpError(err) || err.statusCode !== 401) {
|
|
99
|
+
output.warn('Failed to invalidate previous session');
|
|
100
|
+
}
|
|
77
101
|
}
|
|
78
|
-
trace.complete();
|
|
79
102
|
}
|
|
80
103
|
|
|
81
104
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/auth/login/login.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n getUserConfig,\n type Output,\n setCliUserConfig,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport open from 'open'\n\nimport {logout} from '../../../services/auth.js'\nimport {LoginTrace} from '../../../telemetry/login.telemetry.js'\nimport {canLaunchBrowser} from '../../../util/canLaunchBrowser.js'\nimport {startServerForTokenCallback} from '../authServer.js'\nimport {getProvider} from './getProvider.js'\n\nconst debug = subdebug('login')\n\ninterface LoginOptions {\n output: Output\n\n telemetry: CLITelemetryStore\n\n experimental?: boolean\n open?: boolean\n provider?: string\n sso?: string\n ssoProvider?: string\n}\n\n/**\n * Trigger the authentication flow for the CLI.\n *\n * NOTE:
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/auth/login/login.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n getUserConfig,\n type Output,\n setCliUserConfig,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\nimport open from 'open'\n\nimport {logout} from '../../../services/auth.js'\nimport {LoginTrace} from '../../../telemetry/login.telemetry.js'\nimport {canLaunchBrowser} from '../../../util/canLaunchBrowser.js'\nimport {startServerForTokenCallback} from '../authServer.js'\nimport {getProvider} from './getProvider.js'\nimport {isSanityApiToken, validateToken} from './validateToken.js'\n\nconst debug = subdebug('login')\n\ninterface LoginOptions {\n output: Output\n\n telemetry: CLITelemetryStore\n\n experimental?: boolean\n open?: boolean\n provider?: string\n sso?: string\n ssoProvider?: string\n token?: string\n}\n\n/**\n * Trigger the authentication flow for the CLI.\n *\n * NOTE: Without a token option, this uses terminal prompts and will not work for\n * non-interactive/programmatic uses.\n *\n * @param options - Options for the login operation\n * @returns Promise that resolves when the login operation is complete\n * @throws Will throw if login fails or is cancelled\n * @internal\n */\nexport async function login(options: LoginOptions) {\n const {output, telemetry} = options\n const previousToken = await getCliToken()\n\n const trace = telemetry.trace(LoginTrace)\n trace.start()\n\n if (typeof options.token === 'string') {\n try {\n const authToken = await validateToken(options.token)\n await storeAuthToken(authToken, previousToken, output)\n trace.complete()\n } catch (err: unknown) {\n trace.error(err as Error)\n throw err\n }\n return\n }\n\n const provider = await getProvider({\n experimental: options.experimental,\n orgSlug: options.sso,\n specifiedProvider: options.provider,\n ssoProvider: options.ssoProvider,\n })\n\n trace.log({provider: provider?.name, step: 'selectProvider'})\n\n if (provider === undefined) {\n throw new Error('No authentication providers found')\n }\n\n const {loginUrl, server, token: tokenPromise} = await startServerForTokenCallback(provider.url)\n\n trace.log({step: 'waitForToken'})\n\n // Open a browser on the login page (or tell the user to)\n const shouldLaunchBrowser = canLaunchBrowser() && options.open !== false\n const actionText = shouldLaunchBrowser ? 'Opening browser at' : 'Please open a browser at'\n\n output.log(`\\n${actionText} ${loginUrl.href}\\n`)\n\n const spin = spinner('Waiting for browser login to complete... Press Ctrl + C to cancel').start()\n\n if (shouldLaunchBrowser) {\n open(loginUrl.href)\n }\n\n // Wait for a success/error on the HTTP callback server\n let authToken: string\n try {\n authToken = (await tokenPromise).token\n spin.stop()\n } catch (err: unknown) {\n spin.stop()\n trace.error(err as Error)\n debug('Error retrieving token: %O', err)\n throw err\n } finally {\n await new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n }\n\n await storeAuthToken(authToken, previousToken, output)\n\n trace.complete()\n}\n\nasync function storeAuthToken(\n authToken: string,\n previousToken: string | undefined,\n output: Output,\n) {\n setCliUserConfig('authToken', authToken)\n getUserConfig().delete('telemetryConsent')\n\n // If we had a session previously, attempt to clear it\n if (previousToken && previousToken !== authToken) {\n await invalidateAuthToken(previousToken, output)\n }\n}\n\nasync function invalidateAuthToken(token: string, output: Output) {\n try {\n if (await isSanityApiToken(token)) return\n } catch (err) {\n if (isHttpError(err) && err.statusCode === 401) return\n }\n\n try {\n await logout(token)\n } catch (err) {\n if (!isHttpError(err) || err.statusCode !== 401) {\n output.warn('Failed to invalidate previous session')\n }\n }\n}\n"],"names":["getCliToken","getUserConfig","setCliUserConfig","subdebug","spinner","isHttpError","open","logout","LoginTrace","canLaunchBrowser","startServerForTokenCallback","getProvider","isSanityApiToken","validateToken","debug","login","options","output","telemetry","previousToken","trace","start","token","authToken","storeAuthToken","complete","err","error","provider","experimental","orgSlug","sso","specifiedProvider","ssoProvider","log","name","step","undefined","Error","loginUrl","server","tokenPromise","url","shouldLaunchBrowser","actionText","href","spin","stop","Promise","resolve","close","delete","invalidateAuthToken","statusCode","warn"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getGlobalCliClient } from '@sanity/cli-core';
|
|
2
|
+
import { isHttpError } from '@sanity/client';
|
|
3
|
+
import { USERS_API_VERSION } from '../../../services/user.js';
|
|
4
|
+
import { getErrorMessage } from '../../../util/getErrorMessage.js';
|
|
5
|
+
export async function validateToken(token) {
|
|
6
|
+
const trimmedToken = token.trim();
|
|
7
|
+
if (!trimmedToken) {
|
|
8
|
+
throw new Error('Token is required on standard input. Run `sanity login --with-token < token.txt`.');
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
await getTokenUser(trimmedToken);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {
|
|
14
|
+
throw new Error('Token is invalid or expired. Check the token and try again.', {
|
|
15
|
+
cause: error
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`Could not verify token: ${getErrorMessage(error)}`, {
|
|
19
|
+
cause: error
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return trimmedToken;
|
|
23
|
+
}
|
|
24
|
+
export async function isSanityApiToken(token) {
|
|
25
|
+
return isSanityApiTokenUser(await getTokenUser(token));
|
|
26
|
+
}
|
|
27
|
+
async function getTokenUser(token) {
|
|
28
|
+
const client = await getGlobalCliClient({
|
|
29
|
+
apiVersion: USERS_API_VERSION,
|
|
30
|
+
requireUser: true,
|
|
31
|
+
token
|
|
32
|
+
});
|
|
33
|
+
return client.users.getById('me');
|
|
34
|
+
}
|
|
35
|
+
function isSanityApiTokenUser(user) {
|
|
36
|
+
return typeof user === 'object' && user !== null && 'provider' in user && user.provider === 'sanity-token';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=validateToken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/auth/login/validateToken.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {USERS_API_VERSION} from '../../../services/user.js'\nimport {getErrorMessage} from '../../../util/getErrorMessage.js'\n\nexport async function validateToken(token: string): Promise<string> {\n const trimmedToken = token.trim()\n\n if (!trimmedToken) {\n throw new Error(\n 'Token is required on standard input. Run `sanity login --with-token < token.txt`.',\n )\n }\n\n try {\n await getTokenUser(trimmedToken)\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n throw new Error('Token is invalid or expired. Check the token and try again.', {cause: error})\n }\n\n throw new Error(`Could not verify token: ${getErrorMessage(error)}`, {cause: error})\n }\n\n return trimmedToken\n}\n\nexport async function isSanityApiToken(token: string): Promise<boolean> {\n return isSanityApiTokenUser(await getTokenUser(token))\n}\n\nasync function getTokenUser(token: string): Promise<unknown> {\n const client = await getGlobalCliClient({\n apiVersion: USERS_API_VERSION,\n requireUser: true,\n token,\n })\n\n return client.users.getById('me')\n}\n\nfunction isSanityApiTokenUser(user: unknown): boolean {\n return (\n typeof user === 'object' &&\n user !== null &&\n 'provider' in user &&\n (user as {provider?: unknown}).provider === 'sanity-token'\n )\n}\n"],"names":["getGlobalCliClient","isHttpError","USERS_API_VERSION","getErrorMessage","validateToken","token","trimmedToken","trim","Error","getTokenUser","error","statusCode","cause","isSanityApiToken","isSanityApiTokenUser","client","apiVersion","requireUser","users","getById","user","provider"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AACnD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,iBAAiB,QAAO,4BAA2B;AAC3D,SAAQC,eAAe,QAAO,mCAAkC;AAEhE,OAAO,eAAeC,cAAcC,KAAa;IAC/C,MAAMC,eAAeD,MAAME,IAAI;IAE/B,IAAI,CAACD,cAAc;QACjB,MAAM,IAAIE,MACR;IAEJ;IAEA,IAAI;QACF,MAAMC,aAAaH;IACrB,EAAE,OAAOI,OAAO;QACd,IAAIT,YAAYS,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIH,MAAM,+DAA+D;gBAACI,OAAOF;YAAK;QAC9F;QAEA,MAAM,IAAIF,MAAM,CAAC,wBAAwB,EAAEL,gBAAgBO,QAAQ,EAAE;YAACE,OAAOF;QAAK;IACpF;IAEA,OAAOJ;AACT;AAEA,OAAO,eAAeO,iBAAiBR,KAAa;IAClD,OAAOS,qBAAqB,MAAML,aAAaJ;AACjD;AAEA,eAAeI,aAAaJ,KAAa;IACvC,MAAMU,SAAS,MAAMf,mBAAmB;QACtCgB,YAAYd;QACZe,aAAa;QACbZ;IACF;IAEA,OAAOU,OAAOG,KAAK,CAACC,OAAO,CAAC;AAC9B;AAEA,SAASL,qBAAqBM,IAAa;IACzC,OACE,OAAOA,SAAS,YAChBA,SAAS,QACT,cAAcA,QACd,AAACA,KAA8BC,QAAQ,KAAK;AAEhD"}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { text } from 'node:stream/consumers';
|
|
1
2
|
import { Flags } from '@oclif/core';
|
|
2
3
|
import { SanityCommand } from '@sanity/cli-core';
|
|
3
4
|
import { login } from '../actions/auth/login/login.js';
|
|
@@ -19,6 +20,10 @@ export class LoginCommand extends SanityCommand {
|
|
|
19
20
|
{
|
|
20
21
|
command: '<%= config.bin %> <%= command.id %> --sso my-organization --sso-provider "Okta SSO"',
|
|
21
22
|
description: 'Log in using a specific SSO provider within an organization'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
command: '<%= config.bin %> <%= command.id %> --with-token < token.txt',
|
|
26
|
+
description: 'Log in using a token from standard input'
|
|
22
27
|
}
|
|
23
28
|
];
|
|
24
29
|
static flags = {
|
|
@@ -34,14 +39,16 @@ export class LoginCommand extends SanityCommand {
|
|
|
34
39
|
provider: Flags.string({
|
|
35
40
|
description: 'Log in using the given provider',
|
|
36
41
|
exclusive: [
|
|
37
|
-
'sso'
|
|
42
|
+
'sso',
|
|
43
|
+
'with-token'
|
|
38
44
|
],
|
|
39
45
|
helpValue: '<providerId>'
|
|
40
46
|
}),
|
|
41
47
|
sso: Flags.string({
|
|
42
48
|
description: 'Log in using Single Sign-On, using the given organization slug',
|
|
43
49
|
exclusive: [
|
|
44
|
-
'provider'
|
|
50
|
+
'provider',
|
|
51
|
+
'with-token'
|
|
45
52
|
],
|
|
46
53
|
helpValue: '<slug>'
|
|
47
54
|
}),
|
|
@@ -51,16 +58,26 @@ export class LoginCommand extends SanityCommand {
|
|
|
51
58
|
],
|
|
52
59
|
description: 'Select a specific SSO provider by name (use with --sso)',
|
|
53
60
|
helpValue: '<name>'
|
|
61
|
+
}),
|
|
62
|
+
'with-token': Flags.boolean({
|
|
63
|
+
description: 'Read token from standard input',
|
|
64
|
+
exclusive: [
|
|
65
|
+
'provider',
|
|
66
|
+
'sso'
|
|
67
|
+
]
|
|
54
68
|
})
|
|
55
69
|
};
|
|
56
70
|
async run() {
|
|
57
71
|
const { flags } = await this.parse(LoginCommand);
|
|
72
|
+
const { 'sso-provider': ssoProvider, 'with-token': withToken, ...loginFlags } = flags;
|
|
58
73
|
try {
|
|
74
|
+
const token = withToken ? await readTokenFromStdin() : undefined;
|
|
59
75
|
await login({
|
|
60
|
-
...
|
|
76
|
+
...loginFlags,
|
|
61
77
|
output: this.output,
|
|
62
|
-
ssoProvider
|
|
63
|
-
telemetry: this.telemetry
|
|
78
|
+
ssoProvider,
|
|
79
|
+
telemetry: this.telemetry,
|
|
80
|
+
token
|
|
64
81
|
});
|
|
65
82
|
this.log('Login successful');
|
|
66
83
|
} catch (error) {
|
|
@@ -71,5 +88,11 @@ export class LoginCommand extends SanityCommand {
|
|
|
71
88
|
}
|
|
72
89
|
}
|
|
73
90
|
}
|
|
91
|
+
async function readTokenFromStdin() {
|
|
92
|
+
if (process.stdin.isTTY) {
|
|
93
|
+
throw new Error('Token is required on standard input. Run `sanity login --with-token < token.txt`.');
|
|
94
|
+
}
|
|
95
|
+
return text(process.stdin);
|
|
96
|
+
}
|
|
74
97
|
|
|
75
98
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import {Command, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {SanityCommand} from '@sanity/cli-core'\n\nimport {login} from '../actions/auth/login/login.js'\n\nexport class LoginCommand extends SanityCommand<typeof LoginCommand> {\n static override description = 'Log in to your Sanity account'\n static override examples: Array<Command.Example> = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Log in using default settings',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --provider github --no-open',\n description: 'Login with GitHub provider, but do not open a browser window automatically',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sso my-organization',\n description: 'Log in using Single Sign-On with the \"my-organization\" slug',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> --sso my-organization --sso-provider \"Okta SSO\"',\n description: 'Log in using a specific SSO provider within an organization',\n },\n ]\n static override flags = {\n experimental: Flags.boolean({\n default: false,\n hidden: true,\n }),\n open: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Open a browser window to log in (`--no-open` only prints URL)',\n }),\n provider: Flags.string({\n description: 'Log in using the given provider',\n exclusive: ['sso'],\n helpValue: '<providerId>',\n }),\n sso: Flags.string({\n description: 'Log in using Single Sign-On, using the given organization slug',\n exclusive: ['provider'],\n helpValue: '<slug>',\n }),\n 'sso-provider': Flags.string({\n dependsOn: ['sso'],\n description: 'Select a specific SSO provider by name (use with --sso)',\n helpValue: '<name>',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(LoginCommand)\n\n try {\n await login({\n ...
|
|
1
|
+
{"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import {text} from 'node:stream/consumers'\n\nimport {Command, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {SanityCommand} from '@sanity/cli-core'\n\nimport {login} from '../actions/auth/login/login.js'\n\nexport class LoginCommand extends SanityCommand<typeof LoginCommand> {\n static override description = 'Log in to your Sanity account'\n static override examples: Array<Command.Example> = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Log in using default settings',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --provider github --no-open',\n description: 'Login with GitHub provider, but do not open a browser window automatically',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sso my-organization',\n description: 'Log in using Single Sign-On with the \"my-organization\" slug',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> --sso my-organization --sso-provider \"Okta SSO\"',\n description: 'Log in using a specific SSO provider within an organization',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --with-token < token.txt',\n description: 'Log in using a token from standard input',\n },\n ]\n static override flags = {\n experimental: Flags.boolean({\n default: false,\n hidden: true,\n }),\n open: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Open a browser window to log in (`--no-open` only prints URL)',\n }),\n provider: Flags.string({\n description: 'Log in using the given provider',\n exclusive: ['sso', 'with-token'],\n helpValue: '<providerId>',\n }),\n sso: Flags.string({\n description: 'Log in using Single Sign-On, using the given organization slug',\n exclusive: ['provider', 'with-token'],\n helpValue: '<slug>',\n }),\n 'sso-provider': Flags.string({\n dependsOn: ['sso'],\n description: 'Select a specific SSO provider by name (use with --sso)',\n helpValue: '<name>',\n }),\n 'with-token': Flags.boolean({\n description: 'Read token from standard input',\n exclusive: ['provider', 'sso'],\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(LoginCommand)\n const {'sso-provider': ssoProvider, 'with-token': withToken, ...loginFlags} = flags\n\n try {\n const token = withToken ? await readTokenFromStdin() : undefined\n\n await login({\n ...loginFlags,\n output: this.output,\n ssoProvider,\n telemetry: this.telemetry,\n token,\n })\n this.log('Login successful')\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Login failed: ${message}`, {exit: 1})\n }\n }\n}\n\nasync function readTokenFromStdin(): Promise<string> {\n if (process.stdin.isTTY) {\n throw new Error(\n 'Token is required on standard input. Run `sanity login --with-token < token.txt`.',\n )\n }\n\n return text(process.stdin)\n}\n"],"names":["text","Flags","SanityCommand","login","LoginCommand","description","examples","command","flags","experimental","boolean","default","hidden","open","allowNo","provider","string","exclusive","helpValue","sso","dependsOn","run","parse","ssoProvider","withToken","loginFlags","token","readTokenFromStdin","undefined","output","telemetry","log","error","message","Error","String","exit","process","stdin","isTTY"],"mappings":"AAAA,SAAQA,IAAI,QAAO,wBAAuB;AAE1C,SAAiBC,KAAK,QAAO,cAAa;AAE1C,SAAQC,aAAa,QAAO,mBAAkB;AAE9C,SAAQC,KAAK,QAAO,iCAAgC;AAEpD,OAAO,MAAMC,qBAAqBF;IAChC,OAAgBG,cAAc,gCAA+B;IAC7D,OAAgBC,WAAmC;QACjD;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SACE;YACFF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtBC,cAAcR,MAAMS,OAAO,CAAC;YAC1BC,SAAS;YACTC,QAAQ;QACV;QACAC,MAAMZ,MAAMS,OAAO,CAAC;YAClBI,SAAS;YACTH,SAAS;YACTN,aAAa;QACf;QACAU,UAAUd,MAAMe,MAAM,CAAC;YACrBX,aAAa;YACbY,WAAW;gBAAC;gBAAO;aAAa;YAChCC,WAAW;QACb;QACAC,KAAKlB,MAAMe,MAAM,CAAC;YAChBX,aAAa;YACbY,WAAW;gBAAC;gBAAY;aAAa;YACrCC,WAAW;QACb;QACA,gBAAgBjB,MAAMe,MAAM,CAAC;YAC3BI,WAAW;gBAAC;aAAM;YAClBf,aAAa;YACba,WAAW;QACb;QACA,cAAcjB,MAAMS,OAAO,CAAC;YAC1BL,aAAa;YACbY,WAAW;gBAAC;gBAAY;aAAM;QAChC;IACF,EAAqB;IAErB,MAAaI,MAAqB;QAChC,MAAM,EAACb,KAAK,EAAC,GAAG,MAAM,IAAI,CAACc,KAAK,CAAClB;QACjC,MAAM,EAAC,gBAAgBmB,WAAW,EAAE,cAAcC,SAAS,EAAE,GAAGC,YAAW,GAAGjB;QAE9E,IAAI;YACF,MAAMkB,QAAQF,YAAY,MAAMG,uBAAuBC;YAEvD,MAAMzB,MAAM;gBACV,GAAGsB,UAAU;gBACbI,QAAQ,IAAI,CAACA,MAAM;gBACnBN;gBACAO,WAAW,IAAI,CAACA,SAAS;gBACzBJ;YACF;YACA,IAAI,CAACK,GAAG,CAAC;QACX,EAAE,OAAOC,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;YAChE,IAAI,CAACA,KAAK,CAAC,CAAC,cAAc,EAAEC,SAAS,EAAE;gBAACG,MAAM;YAAC;QACjD;IACF;AACF;AAEA,eAAeT;IACb,IAAIU,QAAQC,KAAK,CAACC,KAAK,EAAE;QACvB,MAAM,IAAIL,MACR;IAEJ;IAEA,OAAOlC,KAAKqC,QAAQC,KAAK;AAC3B"}
|
package/oclif.manifest.json
CHANGED
|
@@ -808,6 +808,10 @@
|
|
|
808
808
|
{
|
|
809
809
|
"command": "<%= config.bin %> <%= command.id %> --sso my-organization --sso-provider \"Okta SSO\"",
|
|
810
810
|
"description": "Log in using a specific SSO provider within an organization"
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
"command": "<%= config.bin %> <%= command.id %> --with-token < token.txt",
|
|
814
|
+
"description": "Log in using a token from standard input"
|
|
811
815
|
}
|
|
812
816
|
],
|
|
813
817
|
"flags": {
|
|
@@ -826,7 +830,8 @@
|
|
|
826
830
|
"provider": {
|
|
827
831
|
"description": "Log in using the given provider",
|
|
828
832
|
"exclusive": [
|
|
829
|
-
"sso"
|
|
833
|
+
"sso",
|
|
834
|
+
"with-token"
|
|
830
835
|
],
|
|
831
836
|
"name": "provider",
|
|
832
837
|
"hasDynamicHelp": false,
|
|
@@ -837,7 +842,8 @@
|
|
|
837
842
|
"sso": {
|
|
838
843
|
"description": "Log in using Single Sign-On, using the given organization slug",
|
|
839
844
|
"exclusive": [
|
|
840
|
-
"provider"
|
|
845
|
+
"provider",
|
|
846
|
+
"with-token"
|
|
841
847
|
],
|
|
842
848
|
"name": "sso",
|
|
843
849
|
"hasDynamicHelp": false,
|
|
@@ -855,6 +861,16 @@
|
|
|
855
861
|
"helpValue": "<name>",
|
|
856
862
|
"multiple": false,
|
|
857
863
|
"type": "option"
|
|
864
|
+
},
|
|
865
|
+
"with-token": {
|
|
866
|
+
"description": "Read token from standard input",
|
|
867
|
+
"exclusive": [
|
|
868
|
+
"provider",
|
|
869
|
+
"sso"
|
|
870
|
+
],
|
|
871
|
+
"name": "with-token",
|
|
872
|
+
"allowNo": false,
|
|
873
|
+
"type": "boolean"
|
|
858
874
|
}
|
|
859
875
|
},
|
|
860
876
|
"hasDynamicHelp": false,
|
|
@@ -5082,5 +5098,5 @@
|
|
|
5082
5098
|
]
|
|
5083
5099
|
}
|
|
5084
5100
|
},
|
|
5085
|
-
"version": "6.
|
|
5101
|
+
"version": "6.6.0"
|
|
5086
5102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0",
|
|
4
4
|
"description": "Sanity CLI tool for managing Sanity projects and organizations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"which": "^6.0.1",
|
|
117
117
|
"yaml": "^2.8.4",
|
|
118
118
|
"zod": "^4.3.6",
|
|
119
|
-
"@sanity/cli-build": "^0.1.
|
|
119
|
+
"@sanity/cli-build": "^0.1.1",
|
|
120
120
|
"@sanity/cli-core": "^1.3.2"
|
|
121
121
|
},
|
|
122
122
|
"devDependencies": {
|