@seamapi/cli 0.21.0 → 0.23.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 +39 -4
- package/bin/cli.js +29 -9
- package/bin/cli.js.map +1 -1
- package/lib/args/parse.d.ts +9 -0
- package/lib/args/parse.js +42 -2
- package/lib/args/parse.js.map +1 -1
- package/lib/args/validate.d.ts +10 -0
- package/lib/args/validate.js +23 -0
- package/lib/args/validate.js.map +1 -1
- package/lib/auth/operations.d.ts +13 -15
- package/lib/auth/operations.js +25 -48
- package/lib/auth/operations.js.map +1 -1
- package/lib/blueprint/source-npm.js +2 -2
- package/lib/blueprint/source-npm.js.map +1 -1
- package/lib/commands/local/login.js +4 -12
- package/lib/commands/local/login.js.map +1 -1
- package/lib/commands/local/select-endpoint.js +10 -7
- package/lib/commands/local/select-endpoint.js.map +1 -1
- package/lib/commands/local/select-workspace.js +12 -4
- package/lib/commands/local/select-workspace.js.map +1 -1
- package/lib/commands/local/wizard.d.ts +7 -0
- package/lib/commands/local/wizard.js +31 -0
- package/lib/commands/local/wizard.js.map +1 -1
- package/lib/commands/registry.d.ts +11 -0
- package/lib/commands/registry.js +11 -0
- package/lib/commands/registry.js.map +1 -1
- package/lib/commands/spec.d.ts +12 -0
- package/lib/commands/spec.js +16 -0
- package/lib/commands/spec.js.map +1 -1
- package/lib/config/cli-config.d.ts +19 -0
- package/lib/config/cli-config.js +51 -0
- package/lib/config/cli-config.js.map +1 -0
- package/lib/config/config-store.d.ts +8 -5
- package/lib/config/config-store.js +15 -13
- package/lib/config/config-store.js.map +1 -1
- package/lib/config/index.d.ts +3 -2
- package/lib/config/index.js +3 -2
- package/lib/config/index.js.map +1 -1
- package/lib/config/memory-config-store.d.ts +6 -0
- package/lib/config/memory-config-store.js +6 -0
- package/lib/config/memory-config-store.js.map +1 -1
- package/lib/context.d.ts +8 -7
- package/lib/context.js +26 -21
- package/lib/context.js.map +1 -1
- package/lib/interactions/endpoint-selection.js +2 -2
- package/lib/interactions/endpoint-selection.js.map +1 -1
- package/lib/interactions/login.js +2 -2
- package/lib/interactions/login.js.map +1 -1
- package/lib/interactions/workspace-id.js +2 -2
- package/lib/interactions/workspace-id.js.map +1 -1
- package/lib/overrides.d.ts +20 -0
- package/lib/overrides.js +23 -0
- package/lib/overrides.js.map +1 -0
- package/lib/render/help.js +20 -1
- package/lib/render/help.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -2
- package/src/bin/cli.ts +34 -9
- package/src/lib/args/parse.ts +47 -2
- package/src/lib/args/validate.ts +37 -0
- package/src/lib/auth/operations.ts +26 -56
- package/src/lib/blueprint/source-npm.ts +2 -3
- package/src/lib/commands/local/login.ts +4 -15
- package/src/lib/commands/local/select-endpoint.ts +11 -7
- package/src/lib/commands/local/select-workspace.ts +13 -4
- package/src/lib/commands/local/wizard.ts +48 -0
- package/src/lib/commands/registry.ts +20 -0
- package/src/lib/commands/spec.ts +31 -0
- package/src/lib/config/cli-config.ts +83 -0
- package/src/lib/config/config-store.ts +16 -13
- package/src/lib/config/index.ts +9 -4
- package/src/lib/config/memory-config-store.ts +9 -0
- package/src/lib/context.ts +34 -33
- package/src/lib/interactions/endpoint-selection.ts +2 -2
- package/src/lib/interactions/login.ts +2 -2
- package/src/lib/interactions/workspace-id.ts +2 -2
- package/src/lib/overrides.ts +32 -0
- package/src/lib/render/help.ts +21 -1
- package/src/lib/version.ts +1 -1
package/src/lib/context.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Interactivity } from './args/parse.js'
|
|
2
2
|
import type { ApiBlueprint } from './blueprint/index.js'
|
|
3
|
-
import { type
|
|
3
|
+
import { type CliConfig, getConfig } from './config/index.js'
|
|
4
4
|
import {
|
|
5
5
|
getEndpointFromEnv,
|
|
6
6
|
getTokenFromEnv,
|
|
@@ -8,18 +8,20 @@ import {
|
|
|
8
8
|
} from './env.js'
|
|
9
9
|
import type { SeamApi } from './http/api.js'
|
|
10
10
|
import type { Output } from './output/output.js'
|
|
11
|
+
import { getAuthOverrides } from './overrides.js'
|
|
11
12
|
|
|
12
13
|
export const defaultEndpoint = 'https://connect.getseam.com'
|
|
13
14
|
|
|
14
15
|
/** Where a resolved value came from, e.g., to refuse writes the env shadows. */
|
|
15
|
-
export type ValueSource = 'env' | 'config' | 'default'
|
|
16
|
+
export type ValueSource = 'flag' | 'env' | 'config' | 'default'
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* The endpoint, token, and workspace requests are made with.
|
|
19
20
|
*
|
|
20
|
-
* Resolved in one place so the precedence rule exists once:
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Resolved in one place so the precedence rule exists once: a flag given for
|
|
22
|
+
* the one command wins over an environment variable, which wins over the
|
|
23
|
+
* stored value, and the endpoint falls back to Seam. The source tags say
|
|
24
|
+
* where each value came from.
|
|
23
25
|
*/
|
|
24
26
|
export interface AuthContext {
|
|
25
27
|
endpoint: string
|
|
@@ -30,38 +32,45 @@ export interface AuthContext {
|
|
|
30
32
|
workspaceIdSource: Exclude<ValueSource, 'default'> | null
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
export const resolveAuth = (
|
|
34
|
-
|
|
35
|
-
)
|
|
35
|
+
export const resolveAuth = (config: CliConfig = getConfig()): AuthContext => {
|
|
36
|
+
const { endpoint: flagEndpoint, workspaceId: flagWorkspaceId } =
|
|
37
|
+
getAuthOverrides()
|
|
38
|
+
|
|
36
39
|
const envEndpoint = getEndpointFromEnv()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const storedEndpoint = config.get('endpoint') ?? config.get('server')
|
|
40
|
-
const endpoint =
|
|
41
|
-
envEndpoint ?? (typeof storedEndpoint === 'string' ? storedEndpoint : null)
|
|
40
|
+
const storedEndpoint = config.getEndpoint()
|
|
41
|
+
const endpoint = flagEndpoint ?? envEndpoint ?? storedEndpoint
|
|
42
42
|
|
|
43
43
|
const envToken = getTokenFromEnv()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
44
|
+
// The token is stored per endpoint, so an overridden endpoint is read with
|
|
45
|
+
// the token belonging to it rather than the one it replaced.
|
|
46
|
+
const storedToken = config.getToken(endpoint ?? defaultEndpoint)
|
|
47
47
|
|
|
48
48
|
const envWorkspaceId = getWorkspaceIdFromEnv()
|
|
49
|
-
const storedWorkspaceId =
|
|
49
|
+
const storedWorkspaceId = config.getWorkspace()
|
|
50
|
+
const workspaceId = flagWorkspaceId ?? envWorkspaceId ?? storedWorkspaceId
|
|
50
51
|
|
|
51
52
|
return {
|
|
52
53
|
endpoint: endpoint ?? defaultEndpoint,
|
|
53
54
|
endpointSource:
|
|
54
|
-
|
|
55
|
+
flagEndpoint != null
|
|
56
|
+
? 'flag'
|
|
57
|
+
: envEndpoint != null
|
|
58
|
+
? 'env'
|
|
59
|
+
: endpoint != null
|
|
60
|
+
? 'config'
|
|
61
|
+
: 'default',
|
|
55
62
|
token: envToken ?? storedToken,
|
|
56
63
|
tokenSource:
|
|
57
64
|
envToken != null ? 'env' : storedToken != null ? 'config' : null,
|
|
58
|
-
workspaceId
|
|
65
|
+
workspaceId,
|
|
59
66
|
workspaceIdSource:
|
|
60
|
-
|
|
61
|
-
? '
|
|
62
|
-
:
|
|
63
|
-
? '
|
|
64
|
-
: null
|
|
67
|
+
flagWorkspaceId != null
|
|
68
|
+
? 'flag'
|
|
69
|
+
: envWorkspaceId != null
|
|
70
|
+
? 'env'
|
|
71
|
+
: storedWorkspaceId != null
|
|
72
|
+
? 'config'
|
|
73
|
+
: null,
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -70,7 +79,7 @@ export const resolveAuth = (
|
|
|
70
79
|
* shape it acts on, and how it may interact with the user.
|
|
71
80
|
*/
|
|
72
81
|
export interface CliContext {
|
|
73
|
-
config:
|
|
82
|
+
config: CliConfig
|
|
74
83
|
auth: AuthContext
|
|
75
84
|
output: Output
|
|
76
85
|
blueprint: ApiBlueprint
|
|
@@ -78,11 +87,3 @@ export interface CliContext {
|
|
|
78
87
|
/** The Seam API, constructed on first use and shared for the run. */
|
|
79
88
|
api: () => Promise<SeamApi>
|
|
80
89
|
}
|
|
81
|
-
|
|
82
|
-
const readString = (value: unknown): string | null => {
|
|
83
|
-
if (typeof value !== 'string') return null
|
|
84
|
-
|
|
85
|
-
const trimmedValue = value.trim()
|
|
86
|
-
|
|
87
|
-
return trimmedValue === '' ? null : trimmedValue
|
|
88
|
-
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { assertMutable, selectEndpoint } from 'lib/auth/operations.js'
|
|
2
|
-
import {
|
|
2
|
+
import { getConfig } from 'lib/config/index.js'
|
|
3
3
|
import { resolveAuth } from 'lib/context.js'
|
|
4
4
|
import { getOutput } from 'lib/output/get-output.js'
|
|
5
5
|
import { promptAutocomplete } from 'lib/prompt.js'
|
|
6
6
|
|
|
7
7
|
export async function interactForEndpointSelection() {
|
|
8
|
-
const config =
|
|
8
|
+
const config = getConfig()
|
|
9
9
|
assertMutable(resolveAuth(config), 'endpoint', 'select an endpoint')
|
|
10
10
|
|
|
11
11
|
const endpoints = ['http://localhost:3020', 'https://connect.getseam.com']
|
|
@@ -3,7 +3,7 @@ import chalk from 'chalk'
|
|
|
3
3
|
|
|
4
4
|
import { assertMutable, storeToken } from 'lib/auth/operations.js'
|
|
5
5
|
import { validateToken } from 'lib/auth/validate-token.js'
|
|
6
|
-
import {
|
|
6
|
+
import { getConfig } from 'lib/config/index.js'
|
|
7
7
|
import { resolveAuth } from 'lib/context.js'
|
|
8
8
|
import { getOutput } from 'lib/output/get-output.js'
|
|
9
9
|
import { withLoading } from 'lib/output/with-loading.js'
|
|
@@ -12,7 +12,7 @@ import { promptText } from 'lib/prompt.js'
|
|
|
12
12
|
import { interactForWorkspaceId } from './workspace-id.js'
|
|
13
13
|
|
|
14
14
|
export const interactForLogin = async () => {
|
|
15
|
-
const config =
|
|
15
|
+
const config = getConfig()
|
|
16
16
|
const output = getOutput()
|
|
17
17
|
const auth = resolveAuth(config)
|
|
18
18
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SeamHttpWithoutWorkspace } from '@seamapi/http/connect'
|
|
2
2
|
|
|
3
3
|
import { assertMutable, selectWorkspace } from 'lib/auth/operations.js'
|
|
4
|
-
import {
|
|
4
|
+
import { getConfig } from 'lib/config/index.js'
|
|
5
5
|
import { resolveAuth } from 'lib/context.js'
|
|
6
6
|
import { getSeamMultiWorkspace } from 'lib/http/client.js'
|
|
7
7
|
import { withLoading } from 'lib/output/with-loading.js'
|
|
8
8
|
import { promptAutocomplete } from 'lib/prompt.js'
|
|
9
9
|
|
|
10
10
|
export const interactForWorkspaceId = async (personalAccessToken?: string) => {
|
|
11
|
-
const config =
|
|
11
|
+
const config = getConfig()
|
|
12
12
|
|
|
13
13
|
// Refuse before prompting: nothing selected here could be stored.
|
|
14
14
|
assertMutable(resolveAuth(config), 'workspaceId', 'select a workspace')
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The endpoint and workspace may be overridden for a single command.
|
|
3
|
+
*
|
|
4
|
+
* `--endpoint` and `--workspace-id` change what one invocation resolves to
|
|
5
|
+
* and are never stored: only `seam select endpoint` and `seam select
|
|
6
|
+
* workspace` write those settings. They are held here rather than threaded
|
|
7
|
+
* through every call because auth resolves ambiently, exactly as the
|
|
8
|
+
* environment variables they shadow do (see `env.ts`).
|
|
9
|
+
*
|
|
10
|
+
* Set once from the parsed arguments before anything resolves auth, and
|
|
11
|
+
* reset between tests.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface AuthOverrides {
|
|
15
|
+
endpoint: string | null
|
|
16
|
+
workspaceId: string | null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const noOverrides: AuthOverrides = { endpoint: null, workspaceId: null }
|
|
20
|
+
|
|
21
|
+
let overrides: AuthOverrides = noOverrides
|
|
22
|
+
|
|
23
|
+
export const getAuthOverrides = (): AuthOverrides => overrides
|
|
24
|
+
|
|
25
|
+
export const setAuthOverrides = (next: AuthOverrides): void => {
|
|
26
|
+
overrides = next
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Drop the overrides, e.g., between tests sharing a process. */
|
|
30
|
+
export const resetAuthOverrides = (): void => {
|
|
31
|
+
overrides = noOverrides
|
|
32
|
+
}
|
package/src/lib/render/help.ts
CHANGED
|
@@ -131,6 +131,7 @@ const commandSections = (
|
|
|
131
131
|
): Section[] => {
|
|
132
132
|
const name = ['seam', ...command.path].join(' ')
|
|
133
133
|
const hasFlags = command.flags.length > 0
|
|
134
|
+
const { positional } = command
|
|
134
135
|
|
|
135
136
|
return [
|
|
136
137
|
{
|
|
@@ -139,7 +140,26 @@ const commandSections = (
|
|
|
139
140
|
(line) => line !== '',
|
|
140
141
|
),
|
|
141
142
|
},
|
|
142
|
-
{
|
|
143
|
+
{
|
|
144
|
+
header: 'Usage',
|
|
145
|
+
content:
|
|
146
|
+
positional == null
|
|
147
|
+
? `${name} [options]`
|
|
148
|
+
: `${name} <${positional.name}> [options]`,
|
|
149
|
+
},
|
|
150
|
+
...(positional == null
|
|
151
|
+
? []
|
|
152
|
+
: [
|
|
153
|
+
{
|
|
154
|
+
header: 'Arguments',
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
name: `{underline <${positional.name}>}`,
|
|
158
|
+
summary: positional.description,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
]),
|
|
143
163
|
// The command's own parameters are what the request is made of, so keep
|
|
144
164
|
// them apart from the options every seam command takes.
|
|
145
165
|
...(hasFlags ? [optionSection(command.flags, 'Parameters')] : []),
|
package/src/lib/version.ts
CHANGED