@shopify/cli-kit 3.45.0-pre.4 → 3.45.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/assets/cli-ruby/Gemfile +1 -0
- package/assets/cli-ruby/docs/contributors/testing.md +2 -2
- package/assets/cli-ruby/lib/project_types/theme/commands/serve.rb +0 -2
- package/assets/cli-ruby/lib/shopify_cli/api.rb +2 -3
- package/assets/cli-ruby/lib/shopify_cli/context.rb +4 -2
- package/assets/cli-ruby/lib/shopify_cli/messages/messages.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/proxy.rb +6 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server.rb +8 -14
- package/assets/cli-ruby/lib/shopify_cli/theme/syncer/operation.rb +4 -12
- package/assets/cli-ruby/lib/shopify_cli/theme/syncer.rb +1 -1
- package/assets/cli-ruby/vendor/deps/cli-ui/lib/cli/ui/color.rb +1 -1
- package/assets/cli-ruby/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +1 -0
- package/assets/cli-ruby/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -1
- package/dist/private/node/api/graphql.d.ts +4 -4
- package/dist/private/node/api/graphql.js +4 -13
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/conf-store.d.ts +2 -1
- package/dist/private/node/conf-store.js +3 -2
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/context/deprecations-store.d.ts +12 -0
- package/dist/private/node/context/deprecations-store.js +35 -0
- package/dist/private/node/context/deprecations-store.js.map +1 -0
- package/dist/private/node/session.d.ts +2 -2
- package/dist/private/node/session.js +4 -4
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +5 -5
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/FullScreen.js +9 -10
- package/dist/private/node/ui/components/FullScreen.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +16 -0
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Table/Row.d.ts +1 -1
- package/dist/private/node/ui/components/Table/Table.d.ts +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +14 -22
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/analytics.js +10 -2
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/api/admin.d.ts +1 -1
- package/dist/public/node/api/admin.js +10 -3
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/graphql.d.ts +27 -0
- package/dist/public/node/api/graphql.js +26 -0
- package/dist/public/node/api/graphql.js.map +1 -0
- package/dist/public/node/api/partners.d.ts +8 -1
- package/dist/public/node/api/partners.js +28 -2
- package/dist/public/node/api/partners.js.map +1 -1
- package/dist/public/node/cli.d.ts +0 -1
- package/dist/public/node/cli.js +0 -5
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/crypto.d.ts +7 -0
- package/dist/public/node/crypto.js +9 -0
- package/dist/public/node/crypto.js.map +1 -1
- package/dist/public/node/environment.d.ts +12 -0
- package/dist/public/node/environment.js +17 -0
- package/dist/public/node/environment.js.map +1 -1
- package/dist/public/node/environments.js +12 -4
- package/dist/public/node/environments.js.map +1 -1
- package/dist/public/node/git.d.ts +15 -0
- package/dist/public/node/git.js +23 -0
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/hooks/deprecations.d.ts +7 -0
- package/dist/public/node/hooks/deprecations.js +46 -0
- package/dist/public/node/hooks/deprecations.js.map +1 -0
- package/dist/public/node/hooks/postrun.js +2 -0
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/liquid.js +4 -0
- package/dist/public/node/liquid.js.map +1 -1
- package/dist/public/node/metadata.d.ts +10 -1
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/monorail.d.ts +2 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/plugins.d.ts +2 -1
- package/dist/public/node/plugins.js +2 -1
- package/dist/public/node/plugins.js.map +1 -1
- package/dist/public/node/ruby.d.ts +7 -0
- package/dist/public/node/ruby.js +29 -8
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/session.d.ts +2 -2
- package/dist/public/node/session.js +4 -4
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/ui.d.ts +2 -1
- package/dist/public/node/ui.js +2 -1
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/public/node/api/oxygen.d.ts +0 -22
- package/dist/public/node/api/oxygen.js +0 -40
- package/dist/public/node/api/oxygen.js.map +0 -1
package/assets/cli-ruby/Gemfile
CHANGED
|
@@ -7,7 +7,7 @@ Most of the internal components the project uses have unit tests to thoroughly t
|
|
|
7
7
|
|
|
8
8
|
### Acceptance Tests
|
|
9
9
|
|
|
10
|
-
Acceptance tests run the built `shopify` command line
|
|
10
|
+
Acceptance tests run the built `shopify` command line and verify its output and results. They are the slowest to run however provide the most coverage. The idea is to test a few complete scenarios for each major feature.
|
|
11
11
|
|
|
12
12
|
Those are written in [Cucumber](https://cucumber.io/) and Ruby and can be found in the [`features/`](/features) directory. They can be executed by running:
|
|
13
13
|
|
|
@@ -24,4 +24,4 @@ To see outputs, append `--verbose` when running an acceptance test. Example:
|
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
bundle exec cucumber features/theme.feature --verbose
|
|
27
|
-
```
|
|
27
|
+
```
|
|
@@ -55,7 +55,6 @@ module ShopifyCLI
|
|
|
55
55
|
# we delay this require so as to avoid a performance hit on starting the CLI
|
|
56
56
|
require "shopify_cli/http_request"
|
|
57
57
|
headers = default_headers.merge(headers)
|
|
58
|
-
ctx.debug("#{method} #{uri} with X-Request-Id: #{headers["X-Request-Id"]}")
|
|
59
58
|
response = if method == "POST"
|
|
60
59
|
HttpRequest.post(uri, body, headers)
|
|
61
60
|
elsif method == "PUT"
|
|
@@ -65,6 +64,7 @@ module ShopifyCLI
|
|
|
65
64
|
elsif method == "DELETE"
|
|
66
65
|
HttpRequest.delete(uri, body, headers)
|
|
67
66
|
end
|
|
67
|
+
ctx.debug("#{method} #{uri} with request_id: #{response["x-request-id"]}")
|
|
68
68
|
case response.code.to_i
|
|
69
69
|
when 200..399
|
|
70
70
|
[response.code.to_i, JSON.parse(response.body), response]
|
|
@@ -84,7 +84,7 @@ module ShopifyCLI
|
|
|
84
84
|
raise APIRequestUnexpectedError.new("#{response.code}\n#{response.body}", response: response)
|
|
85
85
|
end
|
|
86
86
|
rescue Errno::ETIMEDOUT, Timeout::Error
|
|
87
|
-
ctx.debug("timeout in #{method} #{uri}
|
|
87
|
+
ctx.debug("timeout in #{method} #{uri}")
|
|
88
88
|
raise APIRequestTimeoutError, "Timeout"
|
|
89
89
|
end.retry_after(APIRequestRetriableError, retries: 3) do |e|
|
|
90
90
|
sleep(1) if e.is_a?(APIRequestThrottledError)
|
|
@@ -117,7 +117,6 @@ module ShopifyCLI
|
|
|
117
117
|
"User-Agent" => user_agent,
|
|
118
118
|
"Sec-CH-UA" => sec_ch_ua,
|
|
119
119
|
"Sec-CH-UA-PLATFORM" => ctx.os.to_s,
|
|
120
|
-
"X-Request-Id" => SecureRandom.uuid,
|
|
121
120
|
}.tap do |headers|
|
|
122
121
|
headers["X-Shopify-Cli-Employee"] = "1" if Shopifolk.acting_as_shopify_organization?
|
|
123
122
|
end.merge(auth_headers(token))
|
|
@@ -47,12 +47,14 @@ module ShopifyCLI
|
|
|
47
47
|
str ? str % params : key
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# a wrapper around
|
|
50
|
+
# a wrapper around $stdout.puts to allow for easy formatting
|
|
51
51
|
#
|
|
52
52
|
# #### Parameters
|
|
53
53
|
# * `text` - a string message to output
|
|
54
54
|
def puts(*args)
|
|
55
|
-
|
|
55
|
+
$stdout.puts(CLI::UI.fmt(*args)).tap do
|
|
56
|
+
$stdout.flush
|
|
57
|
+
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
# aborts the current running command and outputs an error message:
|
|
@@ -485,7 +485,7 @@ module ShopifyCLI
|
|
|
485
485
|
error: {
|
|
486
486
|
timeout: "Timed out while waiting for response from Shopify",
|
|
487
487
|
local_identity_not_running: "Identity needs to be running locally in order to proceed.",
|
|
488
|
-
reauthenticate: "Please login again
|
|
488
|
+
reauthenticate: "Please login again",
|
|
489
489
|
invalid_destination: "The store %s doesn't exist. Please log out and try again.",
|
|
490
490
|
},
|
|
491
491
|
|
|
@@ -28,7 +28,12 @@ module ShopifyCLI
|
|
|
28
28
|
SESSION_COOKIE_NAME = "_secure_session_id"
|
|
29
29
|
SESSION_COOKIE_REGEXP = /#{SESSION_COOKIE_NAME}=(\h+)/
|
|
30
30
|
SESSION_COOKIE_MAX_AGE = 60 * 60 * 23 # 1 day - leeway of 1h
|
|
31
|
-
IGNORED_ENDPOINTS = [
|
|
31
|
+
IGNORED_ENDPOINTS = %w[
|
|
32
|
+
shopify/monorail
|
|
33
|
+
mini-profiler-resources
|
|
34
|
+
web-pixels-manager
|
|
35
|
+
wpm
|
|
36
|
+
]
|
|
32
37
|
|
|
33
38
|
def initialize(ctx, theme, param_builder)
|
|
34
39
|
@ctx = ctx
|
|
@@ -170,22 +170,16 @@ module ShopifyCLI
|
|
|
170
170
|
end
|
|
171
171
|
|
|
172
172
|
def sync_theme
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
syncer.start_threads
|
|
173
|
+
ctx.print_task(syncing_theme_message)
|
|
174
|
+
syncer.start_threads
|
|
176
175
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
return if stopped
|
|
184
|
-
|
|
185
|
-
ctx.puts(serving_theme_message)
|
|
186
|
-
ctx.open_url!(address)
|
|
187
|
-
ctx.puts(preview_message)
|
|
176
|
+
if block
|
|
177
|
+
block.call(syncer)
|
|
178
|
+
else
|
|
179
|
+
syncer.upload_theme!(delay_low_priority_files: true)
|
|
188
180
|
end
|
|
181
|
+
|
|
182
|
+
ctx.open_browser_url!(address)
|
|
189
183
|
end
|
|
190
184
|
|
|
191
185
|
def theme
|
|
@@ -6,13 +6,6 @@ module ShopifyCLI
|
|
|
6
6
|
class Operation
|
|
7
7
|
attr_accessor :method, :file
|
|
8
8
|
|
|
9
|
-
COLOR_BY_STATUS = {
|
|
10
|
-
error: :red,
|
|
11
|
-
synced: :green,
|
|
12
|
-
warning: :yellow,
|
|
13
|
-
fixed: :cyan,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
9
|
def initialize(ctx, method, file)
|
|
17
10
|
@ctx = ctx
|
|
18
11
|
@method = method
|
|
@@ -27,8 +20,8 @@ module ShopifyCLI
|
|
|
27
20
|
as_message_with(status: :error)
|
|
28
21
|
end
|
|
29
22
|
|
|
30
|
-
def as_synced_message
|
|
31
|
-
as_message_with(status: :synced
|
|
23
|
+
def as_synced_message
|
|
24
|
+
as_message_with(status: :synced)
|
|
32
25
|
end
|
|
33
26
|
|
|
34
27
|
def as_fix_message
|
|
@@ -41,11 +34,10 @@ module ShopifyCLI
|
|
|
41
34
|
|
|
42
35
|
private
|
|
43
36
|
|
|
44
|
-
def as_message_with(status
|
|
45
|
-
color ||= COLOR_BY_STATUS[status]
|
|
37
|
+
def as_message_with(status:)
|
|
46
38
|
text = @ctx.message("theme.serve.operation.status.#{status}").ljust(6)
|
|
47
39
|
|
|
48
|
-
"#{timestamp}
|
|
40
|
+
"{{gray: • #{timestamp}}} #{text} {{>}} {{gray:#{self}}}"
|
|
49
41
|
end
|
|
50
42
|
|
|
51
43
|
def timestamp
|
|
@@ -275,7 +275,7 @@ module ShopifyCLI
|
|
|
275
275
|
|
|
276
276
|
if file.warnings.any?
|
|
277
277
|
warning_message =
|
|
278
|
-
operation.as_synced_message
|
|
278
|
+
operation.as_synced_message +
|
|
279
279
|
UnsupportedScriptWarning.new(@ctx, file).to_s
|
|
280
280
|
|
|
281
281
|
return @error_reporter.report(warning_message)
|
|
@@ -55,7 +55,7 @@ module CLI
|
|
|
55
55
|
CHECK = new('v', 0x2713, '√', Color::GREEN) # GREEN CHECK MARK (✓)
|
|
56
56
|
X = new('x', 0x2717, 'X', Color::RED) # RED BALLOT X (✗)
|
|
57
57
|
BUG = new('b', 0x1f41b, '!', Color::WHITE) # Bug emoji (🐛)
|
|
58
|
-
CHEVRON = new('>', 0xbb, '»', Color::
|
|
58
|
+
CHEVRON = new('>', 0xbb, '»', Color::GRAY) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (»)
|
|
59
59
|
HOURGLASS = new('H', [0x231b, 0xfe0e], 'H', Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (⌛︎)
|
|
60
60
|
WARNING = new('!', [0x26a0, 0xfe0f], '!', Color::YELLOW) # WARNING SIGN + VARIATION SELECTOR 16 (⚠️ )
|
|
61
61
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestDocument, Variables } from 'graphql-request';
|
|
2
|
-
export
|
|
3
|
-
[key: string]:
|
|
4
|
-
}
|
|
5
|
-
export declare function
|
|
2
|
+
export declare function debugLogRequestInfo<T>(api: string, query: RequestDocument, variables?: Variables, headers?: {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
}): void;
|
|
5
|
+
export declare function errorHandler<T>(api: string): (error: unknown) => Error | unknown;
|
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RequestClientError, sanitizedHeadersOutput } from './headers.js';
|
|
2
2
|
import { stringifyMessage, outputContent, outputToken, outputDebug } from '../../../public/node/output.js';
|
|
3
3
|
import { AbortError } from '../../../public/node/error.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export async function graphqlRequest(query, api, url, token, variables, handleErrors = true) {
|
|
7
|
-
const headers = buildHeaders(token);
|
|
8
|
-
debugLogRequestInfo(api, query, variables, headers);
|
|
9
|
-
const clientOptions = { agent: await httpsAgent(), headers };
|
|
10
|
-
const client = new GraphQLClient(url, clientOptions);
|
|
11
|
-
const response = await debugLogResponseInfo({ request: client.rawRequest(query, variables), url }, handleErrors ? errorHandler(api) : undefined);
|
|
12
|
-
return response.data;
|
|
13
|
-
}
|
|
14
|
-
function debugLogRequestInfo(api, query, variables, headers = {}) {
|
|
4
|
+
import { ClientError } from 'graphql-request';
|
|
5
|
+
export function debugLogRequestInfo(api, query, variables, headers = {}) {
|
|
15
6
|
outputDebug(outputContent `Sending ${outputToken.json(api)} GraphQL request:
|
|
16
7
|
${outputToken.raw(query.toString().trim())}
|
|
17
8
|
${variables ? `\nWith variables:\n${JSON.stringify(variables, null, 2)}\n` : ''}
|
|
@@ -19,7 +10,7 @@ With request headers:
|
|
|
19
10
|
${sanitizedHeadersOutput(headers)}
|
|
20
11
|
`);
|
|
21
12
|
}
|
|
22
|
-
function errorHandler(api) {
|
|
13
|
+
export function errorHandler(api) {
|
|
23
14
|
return (error) => {
|
|
24
15
|
if (error instanceof ClientError) {
|
|
25
16
|
const errorMessage = stringifyMessage(outputContent `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACvE,OAAO,EAAC,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AACxG,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,EAAC,WAAW,EAA6B,MAAM,iBAAiB,CAAA;AAEvE,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,KAAsB,EACtB,SAAqB,EACrB,UAAmC,EAAE;IAErC,WAAW,CAAC,aAAa,CAAA,WAAW,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;IACvD,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;EAC1C,SAAS,CAAC,CAAC,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;;EAE7E,sBAAsB,CAAC,OAAO,CAAC;CAChC,CAAC,CAAA;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAI,GAAW;IACzC,OAAO,CAAC,KAAc,EAAE,EAAE;QACxB,IAAI,KAAK,YAAY,WAAW,EAAE;YAChC,MAAM,YAAY,GAAG,gBAAgB,CAAC,aAAa,CAAA;QACjD,WAAW,CAAC,GAAG,CACnB,GAAG,CACJ,8DAA8D,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE;;IAEvF,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;OACpC,CAAC,CAAA;YACF,IAAI,WAAkB,CAAA;YACtB,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE;gBAC/B,WAAW,GAAG,IAAI,kBAAkB,CAAC,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;aAC1E;iBAAM;gBACL,WAAW,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAA;aAC3C;YACD,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;YAC/B,OAAO,WAAW,CAAA;SACnB;aAAM;YACL,OAAO,KAAK,CAAA;SACb;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {RequestClientError, sanitizedHeadersOutput} from './headers.js'\nimport {stringifyMessage, outputContent, outputToken, outputDebug} from '../../../public/node/output.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {ClientError, RequestDocument, Variables} from 'graphql-request'\n\nexport function debugLogRequestInfo<T>(\n api: string,\n query: RequestDocument,\n variables?: Variables,\n headers: {[key: string]: string} = {},\n) {\n outputDebug(outputContent`Sending ${outputToken.json(api)} GraphQL request:\n ${outputToken.raw(query.toString().trim())}\n${variables ? `\\nWith variables:\\n${JSON.stringify(variables, null, 2)}\\n` : ''}\nWith request headers:\n${sanitizedHeadersOutput(headers)}\n`)\n}\n\nexport function errorHandler<T>(api: string): (error: unknown) => Error | unknown {\n return (error: unknown) => {\n if (error instanceof ClientError) {\n const errorMessage = stringifyMessage(outputContent`\n The ${outputToken.raw(\n api,\n )} GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:\n\n ${outputToken.json(error.response.errors)}\n `)\n let mappedError: Error\n if (error.response.status < 500) {\n mappedError = new RequestClientError(errorMessage, error.response.status)\n } else {\n mappedError = new AbortError(errorMessage)\n }\n mappedError.stack = error.stack\n return mappedError\n } else {\n return error\n }\n }\n}\n"]}
|
|
@@ -33,7 +33,8 @@ type CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['valu
|
|
|
33
33
|
* before returning it.
|
|
34
34
|
* @param key - The key to use for the cache.
|
|
35
35
|
* @param fn - The function to run to get the value to cache, if a cache miss occurs.
|
|
36
|
-
* @param timeout - The maximum valid age of a cached value, in milliseconds.
|
|
36
|
+
* @param timeout - The maximum valid age of a cached value, in milliseconds.
|
|
37
|
+
* If the cached value is older than this, it will be refreshed.
|
|
37
38
|
* @returns The value from the cache or the result of the function.
|
|
38
39
|
*/
|
|
39
40
|
export declare function cacheRetrieveOrRepopulate(key: keyof Cache, fn: () => Promise<CacheValueForKey<typeof key>>, timeout?: number, config?: LocalStorage<ConfSchema>): Promise<CacheValueForKey<typeof key>>;
|
|
@@ -42,13 +42,14 @@ export function removeSession(config = cliKitStore()) {
|
|
|
42
42
|
* before returning it.
|
|
43
43
|
* @param key - The key to use for the cache.
|
|
44
44
|
* @param fn - The function to run to get the value to cache, if a cache miss occurs.
|
|
45
|
-
* @param timeout - The maximum valid age of a cached value, in milliseconds.
|
|
45
|
+
* @param timeout - The maximum valid age of a cached value, in milliseconds.
|
|
46
|
+
* If the cached value is older than this, it will be refreshed.
|
|
46
47
|
* @returns The value from the cache or the result of the function.
|
|
47
48
|
*/
|
|
48
49
|
export async function cacheRetrieveOrRepopulate(key, fn, timeout, config = cliKitStore()) {
|
|
49
50
|
const cache = config.get('cache') || {};
|
|
50
51
|
const cached = cache[key];
|
|
51
|
-
if (cached && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {
|
|
52
|
+
if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {
|
|
52
53
|
return cached.value;
|
|
53
54
|
}
|
|
54
55
|
const value = await fn();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,oCAAoC,CAAA;AAC/D,OAAO,EAAC,aAAa,EAAE,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAkBvE,IAAI,SAA+C,CAAA;AAEnD;;;;GAIG;AACH,SAAS,WAAW;IAClB,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,IAAI,YAAY,CAAa,EAAC,WAAW,EAAE,iBAAiB,EAAC,CAAC,CAAA;KAC3E;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,SAAmC,WAAW,EAAE;IACzE,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,SAAmC,WAAW,EAAE;IAC1F,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAmC,WAAW,EAAE;IAC5E,WAAW,CAAC,aAAa,CAAA,2BAA2B,CAAC,CAAA;IACrD,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;AAC/B,CAAC;AAGD
|
|
1
|
+
{"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,oCAAoC,CAAA;AAC/D,OAAO,EAAC,aAAa,EAAE,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAkBvE,IAAI,SAA+C,CAAA;AAEnD;;;;GAIG;AACH,SAAS,WAAW;IAClB,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,IAAI,YAAY,CAAa,EAAC,WAAW,EAAE,iBAAiB,EAAC,CAAC,CAAA;KAC3E;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,SAAmC,WAAW,EAAE;IACzE,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,SAAmC,WAAW,EAAE;IAC1F,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAmC,WAAW,EAAE;IAC5E,WAAW,CAAC,aAAa,CAAA,2BAA2B,CAAC,CAAA;IACrD,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;AAC/B,CAAC;AAGD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,GAAgB,EAChB,EAA+C,EAC/C,OAAgB,EAChB,MAAM,GAAG,WAAW,EAAE;IAEtB,MAAM,KAAK,GAAU,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;IAEzB,IAAI,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE;QACrG,OAAO,MAAM,CAAC,KAAK,CAAA;KACpB;IAED,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,CAAA;IACxB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC,CAAA;IAC3C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC1B,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '@shopify/cli-kit/node/output'\n\ninterface CacheValue<T> {\n value: T\n timestamp: number\n}\n\nexport type IntrospectionUrlKey = `identity-introspection-url-${string}`\n\ninterface Cache {\n [introspectionUrlKey: IntrospectionUrlKey]: CacheValue<string>\n}\n\nexport interface ConfSchema {\n sessionStore: string\n cache?: Cache\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n if (!_instance) {\n _instance = new LocalStorage<ConfSchema>({projectName: 'shopify-cli-kit'})\n }\n return _instance\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSession(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get('sessionStore')\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSession(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set('sessionStore', session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSession(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete('sessionStore')\n}\n\ntype CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value']\n/**\n * Fetch from cache, or run the provided function to get the value, and cache it\n * before returning it.\n * @param key - The key to use for the cache.\n * @param fn - The function to run to get the value to cache, if a cache miss occurs.\n * @param timeout - The maximum valid age of a cached value, in milliseconds.\n * If the cached value is older than this, it will be refreshed.\n * @returns The value from the cache or the result of the function.\n */\nexport async function cacheRetrieveOrRepopulate(\n key: keyof Cache,\n fn: () => Promise<CacheValueForKey<typeof key>>,\n timeout?: number,\n config = cliKitStore(),\n): Promise<CacheValueForKey<typeof key>> {\n const cache: Cache = config.get('cache') || {}\n const cached = cache[key]\n\n if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {\n return cached.value\n }\n\n const value = await fn()\n cache[key] = {value, timestamp: Date.now()}\n config.set('cache', cache)\n return value\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the earliest date in the future when deprecations will no longer be supported, if any.
|
|
3
|
+
*
|
|
4
|
+
* @returns The next deprecation date.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getNextDeprecationDate(): Date | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Set the next deprecation date to the earliest date in the future.
|
|
9
|
+
*
|
|
10
|
+
* @param dates - Dates when deprecations will no longer be supported.
|
|
11
|
+
*/
|
|
12
|
+
export declare function setNextDeprecationDate(dates: Date[]): Date | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const globalWithDeprecationsStore = {
|
|
2
|
+
...globalThis,
|
|
3
|
+
deprecationsStore: {
|
|
4
|
+
nextDeprecationDate: undefined,
|
|
5
|
+
},
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Get the earliest date in the future when deprecations will no longer be supported, if any.
|
|
9
|
+
*
|
|
10
|
+
* @returns The next deprecation date.
|
|
11
|
+
*/
|
|
12
|
+
export function getNextDeprecationDate() {
|
|
13
|
+
return globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Set the next deprecation date to the earliest date in the future.
|
|
17
|
+
*
|
|
18
|
+
* @param dates - Dates when deprecations will no longer be supported.
|
|
19
|
+
*/
|
|
20
|
+
export function setNextDeprecationDate(dates) {
|
|
21
|
+
if (dates.length < 1)
|
|
22
|
+
return;
|
|
23
|
+
const earliestFutureDateTime = earliestDateTimeAfter(Date.now(), dates);
|
|
24
|
+
if (!earliestFutureDateTime)
|
|
25
|
+
return;
|
|
26
|
+
const nextDeprecationDate = getNextDeprecationDate();
|
|
27
|
+
if (!nextDeprecationDate || earliestFutureDateTime < nextDeprecationDate.getTime()) {
|
|
28
|
+
globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function earliestDateTimeAfter(afterTime, dates) {
|
|
32
|
+
const times = dates.map((date) => date.getTime());
|
|
33
|
+
return times.sort().find((time) => time > afterTime);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=deprecations-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecations-store.js","sourceRoot":"","sources":["../../../../src/private/node/context/deprecations-store.ts"],"names":[],"mappings":"AAQA,MAAM,2BAA2B,GAAgC;IAC/D,GAAG,UAAU;IACb,iBAAiB,EAAE;QACjB,mBAAmB,EAAE,SAAS;KAC/B;CACF,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,2BAA2B,CAAC,iBAAiB,CAAC,mBAAmB,CAAA;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAM;IAE5B,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IACvE,IAAI,CAAC,sBAAsB;QAAE,OAAM;IAEnC,MAAM,mBAAmB,GAAG,sBAAsB,EAAE,CAAA;IACpD,IAAI,CAAC,mBAAmB,IAAI,sBAAsB,GAAG,mBAAmB,CAAC,OAAO,EAAE,EAAE;QAClF,2BAA2B,CAAC,iBAAiB,CAAC,mBAAmB,GAAG,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAA;KACrG;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,KAAa;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;IACjD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,CAAC,CAAA;AACtD,CAAC","sourcesContent":["interface DeprecationsStore {\n nextDeprecationDate: Date | undefined\n}\n\ninterface GlobalWithDeprecationsStore {\n deprecationsStore: DeprecationsStore\n}\n\nconst globalWithDeprecationsStore: GlobalWithDeprecationsStore = {\n ...globalThis,\n deprecationsStore: {\n nextDeprecationDate: undefined,\n },\n}\n\n/**\n * Get the earliest date in the future when deprecations will no longer be supported, if any.\n *\n * @returns The next deprecation date.\n */\nexport function getNextDeprecationDate(): Date | undefined {\n return globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate\n}\n\n/**\n * Set the next deprecation date to the earliest date in the future.\n *\n * @param dates - Dates when deprecations will no longer be supported.\n */\nexport function setNextDeprecationDate(dates: Date[]): Date | undefined {\n if (dates.length < 1) return\n\n const earliestFutureDateTime = earliestDateTimeAfter(Date.now(), dates)\n if (!earliestFutureDateTime) return\n\n const nextDeprecationDate = getNextDeprecationDate()\n if (!nextDeprecationDate || earliestFutureDateTime < nextDeprecationDate.getTime()) {\n globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime)\n }\n}\n\nfunction earliestDateTimeAfter(afterTime: number, dates: Date[]): number | undefined {\n const times = dates.map((date) => date.getTime())\n return times.sort().find((time) => time > afterTime)\n}\n"]}
|
|
@@ -48,9 +48,9 @@ export interface OAuthSession {
|
|
|
48
48
|
* This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
|
|
49
49
|
*
|
|
50
50
|
* @param applications - An object containing the applications we need to be authenticated with.
|
|
51
|
-
* @param
|
|
51
|
+
* @param _env - Optional environment variables to use.
|
|
52
52
|
* @param forceRefresh - Optional flag to force a refresh of the token.
|
|
53
53
|
* @returns An instance with the access tokens organized by application.
|
|
54
54
|
*/
|
|
55
|
-
export declare function ensureAuthenticated(applications: OAuthApplications,
|
|
55
|
+
export declare function ensureAuthenticated(applications: OAuthApplications, _env?: NodeJS.ProcessEnv, forceRefresh?: boolean): Promise<OAuthSession>;
|
|
56
56
|
export {};
|
|
@@ -6,7 +6,6 @@ import { authorize } from './session/authorize.js';
|
|
|
6
6
|
import * as secureStore from './session/store.js';
|
|
7
7
|
import { pollForDeviceAuthorization, requestDeviceAuthorization } from './session/device-authorization.js';
|
|
8
8
|
import { RequestClientError } from './api/headers.js';
|
|
9
|
-
import { environmentVariables } from './constants.js';
|
|
10
9
|
import { outputContent, outputToken, outputDebug } from '../../public/node/output.js';
|
|
11
10
|
import { firstPartyDev, useDeviceAuth } from '../../public/node/context/local.js';
|
|
12
11
|
import { AbortError, BugError } from '../../public/node/error.js';
|
|
@@ -14,17 +13,18 @@ import { partnersRequest } from '../../public/node/api/partners.js';
|
|
|
14
13
|
import { normalizeStoreFqdn, partnersFqdn, identityFqdn } from '../../public/node/context/fqdn.js';
|
|
15
14
|
import { openURL } from '../../public/node/system.js';
|
|
16
15
|
import { keypress } from '../../public/node/ui.js';
|
|
16
|
+
import { getPartnersToken } from '../../public/node/environment.js';
|
|
17
17
|
import { gql } from 'graphql-request';
|
|
18
18
|
import { outputCompleted, outputInfo, outputWarn } from '@shopify/cli-kit/node/output';
|
|
19
19
|
/**
|
|
20
20
|
* This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
|
|
21
21
|
*
|
|
22
22
|
* @param applications - An object containing the applications we need to be authenticated with.
|
|
23
|
-
* @param
|
|
23
|
+
* @param _env - Optional environment variables to use.
|
|
24
24
|
* @param forceRefresh - Optional flag to force a refresh of the token.
|
|
25
25
|
* @returns An instance with the access tokens organized by application.
|
|
26
26
|
*/
|
|
27
|
-
export async function ensureAuthenticated(applications,
|
|
27
|
+
export async function ensureAuthenticated(applications, _env, forceRefresh = false) {
|
|
28
28
|
const fqdn = await identityFqdn();
|
|
29
29
|
const previousStoreFqdn = applications.adminApi?.storeFqdn;
|
|
30
30
|
if (previousStoreFqdn) {
|
|
@@ -71,7 +71,7 @@ ${outputToken.json(applications)}
|
|
|
71
71
|
await secureStore.store(completeSession);
|
|
72
72
|
const tokens = await tokensFor(applications, completeSession, fqdn);
|
|
73
73
|
// Overwrite partners token if using a custom CLI Token
|
|
74
|
-
const envToken =
|
|
74
|
+
const envToken = getPartnersToken();
|
|
75
75
|
if (envToken && applications.partnersApi) {
|
|
76
76
|
tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken;
|
|
77
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/private/node/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAC,gBAAgB,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kCAAkC,EAClC,0BAA0B,EAC1B,0BAA0B,EAE1B,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAEhD,OAAO,KAAK,WAAW,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAC,0BAA0B,EAAE,0BAA0B,EAAC,MAAM,mCAAmC,CAAA;AACxG,OAAO,EAAC,kBAAkB,EAAC,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAC,oBAAoB,EAAC,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAC,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,6BAA6B,CAAA;AACnF,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAC,eAAe,EAAC,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAC,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAC,MAAM,mCAAmC,CAAA;AAChG,OAAO,EAAC,OAAO,EAAC,MAAM,6BAA6B,CAAA;AACnD,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAA;AAEnC,OAAO,EAAC,eAAe,EAAE,UAAU,EAAE,UAAU,EAAC,MAAM,8BAA8B,CAAA;AAqDpF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAA+B,EAC/B,GAAG,GAAG,OAAO,CAAC,GAAG,EACjB,YAAY,GAAG,KAAK;IAEpB,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAA;IAEjC,MAAM,iBAAiB,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC1D,IAAI,iBAAiB,EAAE;QACrB,MAAM,mBAAmB,GAAG,MAAM,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;QACvE,IAAI,iBAAiB,KAAK,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE;YAC1D,YAAY,CAAC,QAAQ,CAAC,SAAS,GAAG,mBAAmB,CAAA;SACtD;KACF;IAED,MAAM,cAAc,GAAG,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;IACxD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAE,CAAA;IACzC,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAE7C,WAAW,CAAC,aAAa,CAAA;EACzB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;;EAExB,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC;CAC/B,CAAC,CAAA;IACA,MAAM,gBAAgB,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,CAAA;IAEjF,IAAI,UAAU,GAAG,EAAE,CAAA;IAEnB,IAAI,gBAAgB,KAAK,iBAAiB,EAAE;QAC1C,WAAW,CAAC,aAAa,CAAA,4CAA4C,CAAC,CAAA;QACtE,UAAU,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;KAC3D;SAAM,IAAI,gBAAgB,KAAK,eAAe,IAAI,YAAY,EAAE;QAC/D,WAAW,CAAC,aAAa,CAAA,+DAA+D,CAAC,CAAA;QACzF,IAAI;YACF,UAAU,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;SAC3E;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,YAAY,iBAAiB,EAAE;gBACtC,UAAU,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;aAC3D;iBAAM,IAAI,KAAK,YAAY,mBAAmB,EAAE;gBAC/C,MAAM,WAAW,CAAC,MAAM,EAAE,CAAA;gBAC1B,MAAM,IAAI,UAAU,CAAC,iCAAiC,EAAE,qDAAqD,CAAC,CAAA;aAC/G;iBAAM;gBACL,MAAM,KAAK,CAAA;aACZ;SACF;KACF;IAED,MAAM,eAAe,GAAY,EAAC,GAAG,cAAc,EAAE,GAAG,UAAU,EAAC,CAAA;IACnE,8CAA8C;IAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;IAChF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,CAAA;IAEnE,uDAAuD;IACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;IACxD,IAAI,QAAQ,IAAI,YAAY,CAAC,WAAW,EAAE;QACxC,MAAM,CAAC,QAAQ,GAAG,CAAC,MAAM,0BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;KAC3E;IACD,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;QAChC,MAAM,2BAA2B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;KACnD;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,mBAAmB,CAAC,YAA+B,EAAE,YAAoB;IACtF,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAC7C,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAA;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC9C,IAAI,aAAa,EAAE,EAAE;QACnB,WAAW,CAAC,aAAa,CAAA,uCAAuC,CAAC,CAAA;QACjE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;KACxB;IAED,IAAI,aAA4B,CAAA;IAChC,IAAI,aAAa,EAAE,EAAE;QACnB,iEAAiE;QACjE,WAAW,CAAC,aAAa,CAAA,yCAAyC,CAAC,CAAA;QACnE,MAAM,UAAU,GAAG,MAAM,0BAA0B,CAAC,MAAM,CAAC,CAAA;QAE3D,8BAA8B;QAC9B,WAAW,CAAC,aAAa,CAAA,4CAA4C,CAAC,CAAA;QACtE,aAAa,GAAG,MAAM,0BAA0B,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;KAC7F;SAAM;QACL,6BAA6B;QAC7B,WAAW,CAAC,aAAa,CAAA,2CAA2C,CAAC,CAAA;QACrE,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;QAEpC,mCAAmC;QACnC,WAAW,CAAC,aAAa,CAAA,+DAA+D,CAAC,CAAA;QACzF,aAAa,GAAG,MAAM,0BAA0B,CAAC,IAAI,CAAC,CAAA;KACvD;IAED,iDAAiD;IACjD,WAAW,CAAC,aAAa,CAAA,6DAA6D,CAAC,CAAA;IACvF,MAAM,MAAM,GAAG,MAAM,kCAAkC,CAAC,aAAa,EAAE,cAAc,EAAE,KAAK,CAAC,CAAA;IAE7F,MAAM,OAAO,GAAY;QACvB,CAAC,YAAY,CAAC,EAAE;YACd,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,MAAM;SACrB;KACF,CAAA;IAED,eAAe,CAAC,YAAY,CAAC,CAAA;IAE7B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,2BAA2B,CAAC,aAAqB;IAC9D,WAAW,CAAC,aAAa,CAAA,oDAAoD,CAAC,CAAA;IAC9E,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE;QAC7C,UAAU,CAAC,yDAAyD,CAAC,CAAA;QACrE,UAAU,CAAC,gCAAgC,CAAC,CAAA;QAC5C,MAAM,QAAQ,EAAE,CAAA;QAChB,MAAM,OAAO,CAAC,WAAW,MAAM,YAAY,EAAE,SAAS,CAAC,CAAA;QACvD,UAAU,CAAC,aAAa,CAAA,kCAAkC,WAAW,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAA;QACzG,UAAU,CAAC,aAAa,CAAA,qFAAqF,CAAC,CAAA;QAC9G,MAAM,QAAQ,EAAE,CAAA;QAChB,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE;YAC7C,MAAM,IAAI,UAAU,CAClB,kDAAkD,EAClD,gEAAgE,CACjE,CAAA;SACF;KACF;AACH,CAAC;AAED,MAAM,oBAAoB,GAAG,GAAG,CAAA;;;;;;;;CAQ/B,CAAA;AAED;;;;;GAKG;AACH,KAAK,UAAU,iBAAiB,CAAC,aAAqB;IACpD,IAAI;QACF,MAAM,eAAe,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAA;QAC1D,OAAO,IAAI,CAAA;QACX,qDAAqD;KACtD;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,KAAK,YAAY,kBAAkB,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG,EAAE;YACnE,OAAO,KAAK,CAAA;SACb;aAAM;YACL,OAAO,IAAI,CAAA;SACZ;KACF;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,KAAoB,EAAE,YAA+B,EAAE,IAAY;IAC9F,yBAAyB;IACzB,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACrD,qDAAqD;IACrD,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAA;IACtD,MAAM,iBAAiB,GAAG,MAAM,kCAAkC,CAChE,aAAa,EACb,cAAc,EACd,YAAY,CAAC,QAAQ,EAAE,SAAS,CACjC,CAAA;IAED,OAAO;QACL,CAAC,IAAI,CAAC,EAAE;YACN,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,iBAAiB;SAChC;KACF,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,SAAS,CAAC,YAA+B,EAAE,OAAgB,EAAE,IAAY;IACtF,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,IAAI,QAAQ,CAAC,+CAA+C,CAAC,CAAA;KACpE;IACD,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,YAAY,CAAC,QAAQ,EAAE;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,CAAA;QAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,WAAW,CAAA;QAC9D,IAAI,KAAK,EAAE;YACT,MAAM,CAAC,KAAK,GAAG,EAAC,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAC,CAAA;SACnE;KACF;IAED,IAAI,YAAY,CAAC,WAAW,EAAE;QAC5B,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;QACvC,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAC/D;IAED,IAAI,YAAY,CAAC,qBAAqB,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAA;QAClD,MAAM,CAAC,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KACjE;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,gBAAgB;AAChB;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,IAAuB;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAA;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,IAAI,EAAE,CAAA;IAC3D,MAAM,eAAe,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC7D,OAAO,gBAAgB,CAAC,eAAe,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,IAAuB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAA;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAA;IACnD,MAAM,gBAAgB,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,IAAI,EAAE,CAAA;IACjE,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC;QACrC,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC;QAC7C,UAAU,EAAE,SAAS,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;KAC/D,CAAA;AACH,CAAC","sourcesContent":["import {applicationId} from './session/identity.js'\nimport {validateSession} from './session/validate.js'\nimport {allDefaultScopes, apiScopes} from './session/scopes.js'\nimport {\n exchangeAccessForApplicationTokens,\n exchangeCodeForAccessToken,\n exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\nimport {authorize} from './session/authorize.js'\nimport {IdentityToken, Session} from './session/schema.js'\nimport * as secureStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {RequestClientError} from './api/headers.js'\nimport {environmentVariables} from './constants.js'\nimport {outputContent, outputToken, outputDebug} from '../../public/node/output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/context/local.js'\nimport {AbortError, BugError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {keypress} from '../../public/node/ui.js'\nimport {gql} from 'graphql-request'\nimport {AdminSession} from '@shopify/cli-kit/node/session'\nimport {outputCompleted, outputInfo, outputWarn} from '@shopify/cli-kit/node/output'\n\n/**\n * A scope supported by the Shopify Admin API.\n */\ntype AdminAPIScope = 'graphql' | 'themes' | 'collaborator' | string\n\n/**\n * It represents the options to authenticate against the Shopify Admin API.\n */\n\ninterface AdminAPIOAuthOptions {\n /** Store to request permissions for. */\n storeFqdn: string\n /** List of scopes to request permissions for. */\n scopes: AdminAPIScope[]\n}\n\n/**\n * A scope supported by the Partners API.\n */\ntype PartnersAPIScope = 'cli' | string\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\ntype StorefrontRendererScope = 'devtools' | string\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\n/**\n * It represents the authentication requirements and\n * is the input necessary to trigger the authentication\n * flow.\n */\nexport interface OAuthApplications {\n adminApi?: AdminAPIOAuthOptions\n storefrontRendererApi?: StorefrontRendererAPIOAuthOptions\n partnersApi?: PartnersAPIOAuthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n}\n\n/**\n * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param env - Optional environment variables to use.\n * @param forceRefresh - Optional flag to force a refresh of the token.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n env = process.env,\n forceRefresh = false,\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const currentSession = (await secureStore.fetch()) || {}\n const fqdnSession = currentSession[fqdn]!\n const scopes = getFlattenScopes(applications)\n\n outputDebug(outputContent`Validating existing session against the scopes:\n${outputToken.json(scopes)}\nFor applications:\n${outputToken.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n outputDebug(outputContent`The current session is valid but needs refresh. Refreshing...`)\n try {\n newSession = await refreshTokens(fqdnSession.identity, applications, fqdn)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (error instanceof InvalidRequestError) {\n await secureStore.remove()\n throw new AbortError('\\nError validating auth session', \"We've cleared the current session, please try again\")\n } else {\n throw error\n }\n }\n }\n\n const completeSession: Session = {...currentSession, ...newSession}\n // Save the new session info if it has changed\n if (Object.keys(newSession).length > 0) await secureStore.store(completeSession)\n const tokens = await tokensFor(applications, completeSession, fqdn)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = env[environmentVariables.partnersToken]\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n if (!envToken && tokens.partners) {\n await ensureUserHasPartnerAccount(tokens.partners)\n }\n\n return tokens\n}\n\n/**\n * Execute the full authentication flow.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param identityFqdn - The identity FQDN.\n */\nasync function executeCompleteFlow(applications: OAuthApplications, identityFqdn: string): Promise<Session> {\n const scopes = getFlattenScopes(applications)\n const exchangeScopes = getExchangeScopes(applications)\n const store = applications.adminApi?.storeFqdn\n if (firstPartyDev()) {\n outputDebug(outputContent`Authenticating as Shopify Employee...`)\n scopes.push('employee')\n }\n\n let identityToken: IdentityToken\n if (useDeviceAuth()) {\n // Request a device code to authorize without a browser redirect.\n outputDebug(outputContent`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n outputDebug(outputContent`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n outputDebug(outputContent`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n outputDebug(outputContent`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n outputDebug(outputContent`CLI token received. Exchanging it for application tokens...`)\n const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store)\n\n const session: Session = {\n [identityFqdn]: {\n identity: identityToken,\n applications: result,\n },\n }\n\n outputCompleted('Logged in.')\n\n return session\n}\n\n/**\n * If the user creates an account from the Identity website, the created\n * account won't get a Partner organization created. We need to detect that\n * and take the user to create a partner organization.\n *\n * @param partnersToken - Partners token.\n */\nasync function ensureUserHasPartnerAccount(partnersToken: string) {\n outputDebug(outputContent`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n outputInfo(`\\nA Shopify Partners organization is needed to proceed.`)\n outputInfo(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n outputInfo(outputContent`👉 Press any key when you have ${outputToken.cyan('created the organization')}`)\n outputWarn(outputContent`Make sure you've confirmed your Shopify and the Partner organization from the email`)\n await keypress()\n if (!(await hasPartnerAccount(partnersToken))) {\n throw new AbortError(\n `Couldn't find your Shopify Partners organization`,\n `Have you confirmed your accounts from the emails you received?`,\n )\n }\n }\n}\n\nconst getFirstOrganization = gql`\n {\n organizations(first: 1) {\n nodes {\n id\n }\n }\n }\n`\n\n/**\n * Validate if the current token is valid for partners API.\n *\n * @param partnersToken - Partners token.\n * @returns A promise that resolves to true if the token is valid for partners API.\n */\nasync function hasPartnerAccount(partnersToken: string): Promise<boolean> {\n try {\n await partnersRequest(getFirstOrganization, partnersToken)\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n if (error instanceof RequestClientError && error.statusCode === 404) {\n return false\n } else {\n return true\n }\n }\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param token - Identity token.\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param fqdn - The identity FQDN.\n */\nasync function refreshTokens(token: IdentityToken, applications: OAuthApplications, fqdn: string): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(token)\n // Exchange new identity token for application tokens\n const exchangeScopes = getExchangeScopes(applications)\n const applicationTokens = await exchangeAccessForApplicationTokens(\n identityToken,\n exchangeScopes,\n applications.adminApi?.storeFqdn,\n )\n\n return {\n [fqdn]: {\n identity: identityToken,\n applications: applicationTokens,\n },\n }\n}\n\n/**\n * Get the application tokens for a given session.\n *\n * @param applications - An object containing the applications we need the tokens for.\n * @param session - The current session.\n * @param fqdn - The identity FQDN.\n */\nasync function tokensFor(applications: OAuthApplications, session: Session, fqdn: string): Promise<OAuthSession> {\n const fqdnSession = session[fqdn]\n if (!fqdnSession) {\n throw new BugError('No session found after ensuring authenticated')\n }\n const tokens: OAuthSession = {}\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = fqdnSession.applications[realAppId]?.accessToken\n if (token) {\n tokens.admin = {token, storeFqdn: applications.adminApi.storeFqdn}\n }\n }\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n tokens.partners = fqdnSession.applications[appId]?.accessToken\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n tokens.storefront = fqdnSession.applications[appId]?.accessToken\n }\n return tokens\n}\n\n// Scope Helpers\n/**\n * Get a flattened array of scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns A flattened array of scopes.\n */\nfunction getFlattenScopes(apps: OAuthApplications): string[] {\n const admin = apps.adminApi?.scopes || []\n const partner = apps.partnersApi?.scopes || []\n const storefront = apps.storefrontRendererApi?.scopes || []\n const requestedScopes = [...admin, ...partner, ...storefront]\n return allDefaultScopes(requestedScopes)\n}\n\n/**\n * Get the scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns An object containing the scopes for each application.\n */\nfunction getExchangeScopes(apps: OAuthApplications): ExchangeScopes {\n const adminScope = apps.adminApi?.scopes || []\n const partnerScope = apps.partnersApi?.scopes || []\n const storefrontScopes = apps.storefrontRendererApi?.scopes || []\n return {\n admin: apiScopes('admin', adminScope),\n partners: apiScopes('partners', partnerScope),\n storefront: apiScopes('storefront-renderer', storefrontScopes),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/private/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {applicationId} from './session/identity.js'\nimport {validateSession} from './session/validate.js'\nimport {allDefaultScopes, apiScopes} from './session/scopes.js'\nimport {\n exchangeAccessForApplicationTokens,\n exchangeCodeForAccessToken,\n exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\nimport {authorize} from './session/authorize.js'\nimport {IdentityToken, Session} from './session/schema.js'\nimport * as secureStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {RequestClientError} from './api/headers.js'\nimport {outputContent, outputToken, outputDebug} from '../../public/node/output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/context/local.js'\nimport {AbortError, BugError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {keypress} from '../../public/node/ui.js'\nimport {getPartnersToken} from '../../public/node/environment.js'\nimport {gql} from 'graphql-request'\nimport {AdminSession} from '@shopify/cli-kit/node/session'\nimport {outputCompleted, outputInfo, outputWarn} from '@shopify/cli-kit/node/output'\n\n/**\n * A scope supported by the Shopify Admin API.\n */\ntype AdminAPIScope = 'graphql' | 'themes' | 'collaborator' | string\n\n/**\n * It represents the options to authenticate against the Shopify Admin API.\n */\n\ninterface AdminAPIOAuthOptions {\n /** Store to request permissions for. */\n storeFqdn: string\n /** List of scopes to request permissions for. */\n scopes: AdminAPIScope[]\n}\n\n/**\n * A scope supported by the Partners API.\n */\ntype PartnersAPIScope = 'cli' | string\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\ntype StorefrontRendererScope = 'devtools' | string\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\n/**\n * It represents the authentication requirements and\n * is the input necessary to trigger the authentication\n * flow.\n */\nexport interface OAuthApplications {\n adminApi?: AdminAPIOAuthOptions\n storefrontRendererApi?: StorefrontRendererAPIOAuthOptions\n partnersApi?: PartnersAPIOAuthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n}\n\n/**\n * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param _env - Optional environment variables to use.\n * @param forceRefresh - Optional flag to force a refresh of the token.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n _env?: NodeJS.ProcessEnv,\n forceRefresh = false,\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const currentSession = (await secureStore.fetch()) || {}\n const fqdnSession = currentSession[fqdn]!\n const scopes = getFlattenScopes(applications)\n\n outputDebug(outputContent`Validating existing session against the scopes:\n${outputToken.json(scopes)}\nFor applications:\n${outputToken.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n outputDebug(outputContent`The current session is valid but needs refresh. Refreshing...`)\n try {\n newSession = await refreshTokens(fqdnSession.identity, applications, fqdn)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (error instanceof InvalidRequestError) {\n await secureStore.remove()\n throw new AbortError('\\nError validating auth session', \"We've cleared the current session, please try again\")\n } else {\n throw error\n }\n }\n }\n\n const completeSession: Session = {...currentSession, ...newSession}\n // Save the new session info if it has changed\n if (Object.keys(newSession).length > 0) await secureStore.store(completeSession)\n const tokens = await tokensFor(applications, completeSession, fqdn)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = getPartnersToken()\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n if (!envToken && tokens.partners) {\n await ensureUserHasPartnerAccount(tokens.partners)\n }\n\n return tokens\n}\n\n/**\n * Execute the full authentication flow.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param identityFqdn - The identity FQDN.\n */\nasync function executeCompleteFlow(applications: OAuthApplications, identityFqdn: string): Promise<Session> {\n const scopes = getFlattenScopes(applications)\n const exchangeScopes = getExchangeScopes(applications)\n const store = applications.adminApi?.storeFqdn\n if (firstPartyDev()) {\n outputDebug(outputContent`Authenticating as Shopify Employee...`)\n scopes.push('employee')\n }\n\n let identityToken: IdentityToken\n if (useDeviceAuth()) {\n // Request a device code to authorize without a browser redirect.\n outputDebug(outputContent`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n outputDebug(outputContent`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n outputDebug(outputContent`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n outputDebug(outputContent`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n outputDebug(outputContent`CLI token received. Exchanging it for application tokens...`)\n const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store)\n\n const session: Session = {\n [identityFqdn]: {\n identity: identityToken,\n applications: result,\n },\n }\n\n outputCompleted('Logged in.')\n\n return session\n}\n\n/**\n * If the user creates an account from the Identity website, the created\n * account won't get a Partner organization created. We need to detect that\n * and take the user to create a partner organization.\n *\n * @param partnersToken - Partners token.\n */\nasync function ensureUserHasPartnerAccount(partnersToken: string) {\n outputDebug(outputContent`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n outputInfo(`\\nA Shopify Partners organization is needed to proceed.`)\n outputInfo(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n outputInfo(outputContent`👉 Press any key when you have ${outputToken.cyan('created the organization')}`)\n outputWarn(outputContent`Make sure you've confirmed your Shopify and the Partner organization from the email`)\n await keypress()\n if (!(await hasPartnerAccount(partnersToken))) {\n throw new AbortError(\n `Couldn't find your Shopify Partners organization`,\n `Have you confirmed your accounts from the emails you received?`,\n )\n }\n }\n}\n\nconst getFirstOrganization = gql`\n {\n organizations(first: 1) {\n nodes {\n id\n }\n }\n }\n`\n\n/**\n * Validate if the current token is valid for partners API.\n *\n * @param partnersToken - Partners token.\n * @returns A promise that resolves to true if the token is valid for partners API.\n */\nasync function hasPartnerAccount(partnersToken: string): Promise<boolean> {\n try {\n await partnersRequest(getFirstOrganization, partnersToken)\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n if (error instanceof RequestClientError && error.statusCode === 404) {\n return false\n } else {\n return true\n }\n }\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param token - Identity token.\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param fqdn - The identity FQDN.\n */\nasync function refreshTokens(token: IdentityToken, applications: OAuthApplications, fqdn: string): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(token)\n // Exchange new identity token for application tokens\n const exchangeScopes = getExchangeScopes(applications)\n const applicationTokens = await exchangeAccessForApplicationTokens(\n identityToken,\n exchangeScopes,\n applications.adminApi?.storeFqdn,\n )\n\n return {\n [fqdn]: {\n identity: identityToken,\n applications: applicationTokens,\n },\n }\n}\n\n/**\n * Get the application tokens for a given session.\n *\n * @param applications - An object containing the applications we need the tokens for.\n * @param session - The current session.\n * @param fqdn - The identity FQDN.\n */\nasync function tokensFor(applications: OAuthApplications, session: Session, fqdn: string): Promise<OAuthSession> {\n const fqdnSession = session[fqdn]\n if (!fqdnSession) {\n throw new BugError('No session found after ensuring authenticated')\n }\n const tokens: OAuthSession = {}\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = fqdnSession.applications[realAppId]?.accessToken\n if (token) {\n tokens.admin = {token, storeFqdn: applications.adminApi.storeFqdn}\n }\n }\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n tokens.partners = fqdnSession.applications[appId]?.accessToken\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n tokens.storefront = fqdnSession.applications[appId]?.accessToken\n }\n return tokens\n}\n\n// Scope Helpers\n/**\n * Get a flattened array of scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns A flattened array of scopes.\n */\nfunction getFlattenScopes(apps: OAuthApplications): string[] {\n const admin = apps.adminApi?.scopes || []\n const partner = apps.partnersApi?.scopes || []\n const storefront = apps.storefrontRendererApi?.scopes || []\n const requestedScopes = [...admin, ...partner, ...storefront]\n return allDefaultScopes(requestedScopes)\n}\n\n/**\n * Get the scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns An object containing the scopes for each application.\n */\nfunction getExchangeScopes(apps: OAuthApplications): ExchangeScopes {\n const adminScope = apps.adminApi?.scopes || []\n const partnerScope = apps.partnersApi?.scopes || []\n const storefrontScopes = apps.storefrontRendererApi?.scopes || []\n return {\n admin: apiScopes('admin', adminScope),\n partners: apiScopes('partners', partnerScope),\n storefront: apiScopes('storefront-renderer', storefrontScopes),\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {TokenizedText} from './TokenizedText.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {debounce} from '../../../../public/common/function.js'\nimport React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react'\nimport {Box, measureElement, Text, useApp, useInput, useStdout} from 'ink'\nimport figures from 'figures'\nimport ansiEscapes from 'ansi-escapes'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: string\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n}\n\nenum PromptState {\n Idle = 'idle',\n Loading = 'loading',\n Submitted = 'submitted',\n Error = 'error',\n}\n\nconst PAGE_SIZE = 25\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices: initialChoices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const paginatedInitialChoices = initialChoices.slice(0, PAGE_SIZE)\n const [answer, setAnswer] = useState<SelectItem<T> | undefined>(paginatedInitialChoices[0])\n const {exit: unmountInk} = useApp()\n const [promptState, setPromptState] = useState<PromptState>(PromptState.Idle)\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(paginatedInitialChoices.slice(0, PAGE_SIZE))\n const {stdout} = useStdout()\n const canSearch = initialChoices.length >= PAGE_SIZE\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const [wrapperHeight, setWrapperHeight] = useState(0)\n const [selectInputHeight, setSelectInputHeight] = useState(0)\n const [limit, setLimit] = useState(searchResults.length)\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n results.data = results.data.slice(0, PAGE_SIZE)\n return results\n },\n [search],\n )\n\n const wrapperRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setWrapperHeight(height)\n }\n }, [])\n\n const inputRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setSelectInputHeight(height)\n }\n }, [])\n\n useEffect(() => {\n function onResize() {\n const availableSpace = stdout!.rows - (wrapperHeight - selectInputHeight)\n // rough estimate of the limit needed based on the space available\n const newLimit = Math.max(2, availableSpace - 6)\n\n if (newLimit < limit) {\n stdout!.write(ansiEscapes.clearTerminal)\n }\n\n setLimit(Math.min(newLimit, searchResults.length))\n }\n\n onResize()\n\n stdout!.on('resize', onResize)\n return () => {\n stdout!.off('resize', onResize)\n }\n }, [wrapperHeight, selectInputHeight, searchResults.length, stdout, limit])\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.return && promptState === PromptState.Idle && answer) {\n // -1 is for the last row with the terminal cursor\n if (stdout && wrapperHeight >= stdout.rows - 1) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n setPromptState(PromptState.Submitted)\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n })\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // disable exhaustive-deps because we want to memoize the debounce function itself\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debounceSearch = useCallback(\n debounce((term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(paginatedInitialChoices)\n setHasMorePages(initialHasMorePages)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n }, 300),\n [initialHasMorePages, paginatedInitialChoices, paginatedSearch],\n )\n\n return (\n <Box flexDirection=\"column\" marginBottom={1} ref={wrapperRef}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n {promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(paginatedInitialChoices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null}\n </Box>\n\n {infoTable && promptState !== PromptState.Submitted ? (\n <Box marginLeft={7} marginTop={1}>\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{answer!.label}</Text>\n </Box>\n ) : (\n <Box marginTop={1}>\n <SelectInput\n items={searchResults}\n onChange={({item}) => {\n setAnswer(item)\n }}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n ref={inputRef}\n limit={limit}\n />\n </Box>\n )}\n </Box>\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|
|
1
|
+
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {TokenizedText} from './TokenizedText.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {debounce} from '../../../../public/common/function.js'\nimport React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react'\nimport {Box, measureElement, Text, useApp, useInput, useStdout} from 'ink'\nimport figures from 'figures'\nimport ansiEscapes from 'ansi-escapes'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: string\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n}\n\nenum PromptState {\n Idle = 'idle',\n Loading = 'loading',\n Submitted = 'submitted',\n Error = 'error',\n}\n\nconst PAGE_SIZE = 25\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices: initialChoices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const paginatedInitialChoices = initialChoices.slice(0, PAGE_SIZE)\n const [answer, setAnswer] = useState<SelectItem<T> | undefined>(paginatedInitialChoices[0])\n const {exit: unmountInk} = useApp()\n const [promptState, setPromptState] = useState<PromptState>(PromptState.Idle)\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(paginatedInitialChoices.slice(0, PAGE_SIZE))\n const {stdout} = useStdout()\n const canSearch = initialChoices.length >= PAGE_SIZE\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const [wrapperHeight, setWrapperHeight] = useState(0)\n const [selectInputHeight, setSelectInputHeight] = useState(0)\n const [limit, setLimit] = useState(searchResults.length)\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n results.data = results.data.slice(0, PAGE_SIZE)\n return results\n },\n [search],\n )\n\n const wrapperRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setWrapperHeight(height)\n }\n }, [])\n\n const inputRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setSelectInputHeight(height)\n }\n }, [])\n\n useEffect(() => {\n function onResize() {\n const availableSpace = stdout.rows - (wrapperHeight - selectInputHeight)\n // rough estimate of the limit needed based on the space available\n const newLimit = Math.max(2, availableSpace - 6)\n\n if (newLimit < limit) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n\n setLimit(Math.min(newLimit, searchResults.length))\n }\n\n onResize()\n\n stdout.on('resize', onResize)\n return () => {\n stdout.off('resize', onResize)\n }\n }, [wrapperHeight, selectInputHeight, searchResults.length, stdout, limit])\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.return && promptState === PromptState.Idle && answer) {\n // -1 is for the last row with the terminal cursor\n if (stdout && wrapperHeight >= stdout.rows - 1) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n setPromptState(PromptState.Submitted)\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n })\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // disable exhaustive-deps because we want to memoize the debounce function itself\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debounceSearch = useCallback(\n debounce((term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(paginatedInitialChoices)\n setHasMorePages(initialHasMorePages)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n }, 300),\n [initialHasMorePages, paginatedInitialChoices, paginatedSearch],\n )\n\n return (\n <Box flexDirection=\"column\" marginBottom={1} ref={wrapperRef}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n {promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(paginatedInitialChoices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null}\n </Box>\n\n {infoTable && promptState !== PromptState.Submitted ? (\n <Box marginLeft={7} marginTop={1}>\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{answer!.label}</Text>\n </Box>\n ) : (\n <Box marginTop={1}>\n <SelectInput\n items={searchResults}\n onChange={({item}) => {\n setAnswer(item)\n }}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n ref={inputRef}\n limit={limit}\n />\n </Box>\n )}\n </Box>\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|