@shopify/cli-kit 3.44.1 → 3.45.0-pre.2
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 +15 -7
- package/assets/cli-ruby/lib/project_types/extension/messages/messages.rb +0 -2
- package/assets/cli-ruby/lib/project_types/theme/commands/pull.rb +6 -0
- package/assets/cli-ruby/lib/project_types/theme/commands/push.rb +6 -0
- package/assets/cli-ruby/lib/shopify_cli/constants.rb +1 -0
- package/assets/cli-ruby/lib/shopify_cli/environment.rb +4 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/hot_reload.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/proxy.rb +3 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +3 -3
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/host_theme.rb +4 -4
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/syncer/extension_serve_job.rb +4 -6
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/ui/host_theme_raw_progress_bar.rb +40 -0
- package/assets/cli-ruby/vendor/deps/cli-ui/lib/cli/ui/progress_plain.rb +50 -0
- package/assets/cli-ruby/vendor/deps/cli-ui/lib/cli/ui.rb +15 -14
- package/dist/private/node/api/graphql.js +12 -23
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api.d.ts +1 -1
- package/dist/private/node/api.js +28 -9
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/constants.d.ts +0 -1
- package/dist/private/node/constants.js +0 -1
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/session/redirect-listener.js +2 -3
- package/dist/private/node/session/redirect-listener.js.map +1 -1
- package/dist/private/node/session/schema.d.ts +28 -28
- package/dist/private/node/session/schema.js +12 -12
- package/dist/private/node/session/schema.js.map +1 -1
- package/dist/private/node/testing/ui.d.ts +11 -0
- package/dist/private/node/testing/ui.js +15 -1
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/ui/alert.d.ts +5 -1
- package/dist/private/node/ui/alert.js +2 -2
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +38 -12
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +56 -36
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +5 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js +15 -13
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +20 -11
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/FullScreen.js +1 -1
- package/dist/private/node/ui/components/FullScreen.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.d.ts +7 -2
- package/dist/private/node/ui/components/SelectInput.js +73 -60
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js +72 -2
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js +38 -12
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +52 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.js +9 -1
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.js +4 -4
- package/dist/private/node/ui/components/TextAnimation.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.js +4 -4
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/hooks/use-layout.d.ts +6 -0
- package/dist/private/node/ui/hooks/use-layout.js +31 -12
- package/dist/private/node/ui/hooks/use-layout.js.map +1 -1
- package/dist/private/node/ui.d.ts +11 -3
- package/dist/private/node/ui.js +14 -10
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/object.d.ts +1 -1
- package/dist/public/common/object.js +1 -1
- package/dist/public/common/object.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/base-command.d.ts +1 -4
- package/dist/public/node/base-command.js +17 -19
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/context/local.d.ts +0 -7
- package/dist/public/node/context/local.js +0 -9
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/environments.d.ts +7 -8
- package/dist/public/node/environments.js +23 -25
- package/dist/public/node/environments.js.map +1 -1
- package/dist/public/node/http.d.ts +0 -1
- package/dist/public/node/http.js +0 -1
- package/dist/public/node/http.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +1 -1
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -1
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/path.js +1 -1
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/ruby.d.ts +1 -0
- package/dist/public/node/ruby.js +35 -15
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/schema.d.ts +1 -1
- package/dist/public/node/schema.js +1 -1
- package/dist/public/node/schema.js.map +1 -1
- package/dist/public/node/themes/theme-manager.d.ts +1 -1
- package/dist/public/node/themes/theme-manager.js.map +1 -1
- package/dist/public/node/ui.d.ts +182 -121
- package/dist/public/node/ui.js +172 -120
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -19
- package/dist/private/node/ui/components/TextWithBackground.d.ts +0 -12
- package/dist/private/node/ui/components/TextWithBackground.js +0 -39
- package/dist/private/node/ui/components/TextWithBackground.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<a href="https://github.com/Shopify/cli/actions/workflows/shopify-cli.yml"></a>
|
|
7
7
|
|
|
8
8
|
With the Shopify command line interface (Shopify CLI 3.0), you can:
|
|
9
|
+
- initialize, build, dev, and deploy Shopify apps, extensions, functions and themes
|
|
9
10
|
- build custom storefronts and manage their hosting
|
|
10
|
-
- initialize, build, dev, and deploy Shopify apps — and generate app extensions
|
|
11
11
|
|
|
12
12
|
<p> </p>
|
|
13
13
|
|
|
@@ -30,15 +30,23 @@ Learn more in the docs: [Create an app](https://shopify.dev/apps/getting-started
|
|
|
30
30
|
|
|
31
31
|
<p> </p>
|
|
32
32
|
|
|
33
|
+
## Developing themes with Shopify CLI
|
|
34
|
+
|
|
35
|
+
To work with themes, the CLI needs to be installed globally with:
|
|
36
|
+
|
|
37
|
+
- `npm install -g @shopify/cli @shopify/theme`
|
|
38
|
+
|
|
39
|
+
You can also use do it through Homebrew on macOS: `brew install shopify-cli`
|
|
40
|
+
|
|
41
|
+
Learn more in the docs: [Shopify CLI for themes](https://shopify.dev/docs/themes/tools/cli)
|
|
42
|
+
|
|
43
|
+
<p> </p>
|
|
44
|
+
|
|
33
45
|
## Developing Hydrogen custom storefronts with Shopify CLI ##
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
The Hydrogen code lives here: https://github.com/Shopify/hydrogen/tree/main/packages/cli
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
- `npm init @shopify/hydrogen@latest`
|
|
39
|
-
- `npx @shopify/create-hydrogen@latest`
|
|
40
|
-
- `pnpm create @shopify/create-hydrogen@latest`
|
|
41
|
-
- `yarn create @shopify/hydrogen`
|
|
49
|
+
Learn more in the docs: [Shopify CLI for Hydrogen storefronts](https://shopify.dev/docs/custom-storefronts/hydrogen/cli)
|
|
42
50
|
|
|
43
51
|
<p> </p>
|
|
44
52
|
|
|
@@ -35,12 +35,18 @@ module Theme
|
|
|
35
35
|
flags[:ignores] |= pattern
|
|
36
36
|
end
|
|
37
37
|
parser.on("-f", "--force") { flags[:force] = true }
|
|
38
|
+
parser.on("--development-theme-id=DEVELOPMENT_THEME_ID") do |development_theme_id|
|
|
39
|
+
flags[:development_theme_id] = development_theme_id.to_i
|
|
40
|
+
end
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
def call(_args, name)
|
|
41
44
|
root = root_value(options, name)
|
|
42
45
|
return if exist_and_not_empty?(root) && !valid_theme_directory?(root)
|
|
43
46
|
|
|
47
|
+
development_theme_id = options.flags[:development_theme_id]
|
|
48
|
+
ShopifyCLI::DB.set(development_theme_id: development_theme_id) unless development_theme_id.nil?
|
|
49
|
+
|
|
44
50
|
delete = !options.flags[:nodelete]
|
|
45
51
|
theme = find_theme(root, **options.flags)
|
|
46
52
|
return if theme.nil?
|
|
@@ -40,12 +40,18 @@ module Theme
|
|
|
40
40
|
flags[:ignores] |= pattern
|
|
41
41
|
end
|
|
42
42
|
parser.on("-f", "--force") { flags[:force] = true }
|
|
43
|
+
parser.on("--development-theme-id=DEVELOPMENT_THEME_ID") do |development_theme_id|
|
|
44
|
+
flags[:development_theme_id] = development_theme_id.to_i
|
|
45
|
+
end
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
def call(_args, name)
|
|
46
49
|
root = root_value(options, name)
|
|
47
50
|
return unless valid_theme_directory?(root)
|
|
48
51
|
|
|
52
|
+
development_theme_id = options.flags[:development_theme_id]
|
|
53
|
+
ShopifyCLI::DB.set(development_theme_id: development_theme_id) unless development_theme_id.nil?
|
|
54
|
+
|
|
49
55
|
delete = !options.flags[:nodelete]
|
|
50
56
|
theme = find_theme(root, **options.flags)
|
|
51
57
|
return if theme.nil?
|
|
@@ -109,6 +109,10 @@ module ShopifyCLI
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def self.spin_url_override(env_variables: ENV)
|
|
112
|
+
return env_variables[Constants::EnvironmentVariables::SPIN_FQDN] if env_variables.key?(
|
|
113
|
+
Constants::EnvironmentVariables::SPIN_FQDN
|
|
114
|
+
)
|
|
115
|
+
|
|
112
116
|
tokens = SPIN_OVERRIDE_ENV_NAMES.map do |name|
|
|
113
117
|
env_variables[name]
|
|
114
118
|
end
|
|
@@ -28,6 +28,7 @@ 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 = ["shopify/monorail", "mini-profiler-resources", "web-pixels-manager"]
|
|
31
32
|
|
|
32
33
|
def initialize(ctx, theme, param_builder)
|
|
33
34
|
@ctx = ctx
|
|
@@ -40,6 +41,8 @@ module ShopifyCLI
|
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def call(env)
|
|
44
|
+
return [204, {}, []] if IGNORED_ENDPOINTS.any? { |endpoint| env["PATH_INFO"].include?(endpoint) }
|
|
45
|
+
|
|
43
46
|
headers = extract_http_request_headers(env)
|
|
44
47
|
headers["Host"] = shop
|
|
45
48
|
headers["Cookie"] = add_session_cookie(headers["Cookie"])
|
|
@@ -119,9 +119,9 @@ module ShopifyCLI
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def setup_server
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
ctx.puts("\n--------- #{frame_title}")
|
|
123
|
+
ctx.puts(preview_message)
|
|
124
|
+
ctx.puts("------------------\n")
|
|
125
125
|
|
|
126
126
|
watcher.start
|
|
127
127
|
syncer.start
|
|
@@ -4,7 +4,7 @@ require "fileutils"
|
|
|
4
4
|
require_relative "../syncer"
|
|
5
5
|
require_relative "../development_theme"
|
|
6
6
|
require "shopify_cli/git"
|
|
7
|
-
require "shopify_cli/theme/extension/ui/
|
|
7
|
+
require "shopify_cli/theme/extension/ui/host_theme_raw_progress_bar"
|
|
8
8
|
require "tmpdir"
|
|
9
9
|
|
|
10
10
|
require "shopify_cli/git"
|
|
@@ -77,9 +77,9 @@ module ShopifyCLI
|
|
|
77
77
|
|
|
78
78
|
begin
|
|
79
79
|
syncer.start_threads
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
ctx.puts("\n--------- #{ctx.message("theme.push.info.pushing", name, id, shop)}")
|
|
81
|
+
UI::HostThemeRawProgressBar.new(syncer, dir).progress(:upload_theme!, delete: false)
|
|
82
|
+
ctx.puts("------------------\n")
|
|
83
83
|
rescue Errno::ENOENT => e
|
|
84
84
|
ctx.debug(e.message)
|
|
85
85
|
ensure
|
|
@@ -30,6 +30,8 @@ module ShopifyCLI
|
|
|
30
30
|
|
|
31
31
|
@job_in_progress = false
|
|
32
32
|
@job_in_progress_mutex = Mutex.new
|
|
33
|
+
|
|
34
|
+
$stdout.sync = true
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def perform!
|
|
@@ -81,16 +83,12 @@ module ShopifyCLI
|
|
|
81
83
|
Time.now - @syncer.latest_sync < PUSH_INTERVAL
|
|
82
84
|
end
|
|
83
85
|
|
|
84
|
-
def timestamp
|
|
85
|
-
Time.now.strftime("%T")
|
|
86
|
-
end
|
|
87
|
-
|
|
88
86
|
def success_message(project)
|
|
89
|
-
"
|
|
87
|
+
"{{green:Pushed}} {{>}} {{blue:'#{project}'}} to a draft"
|
|
90
88
|
end
|
|
91
89
|
|
|
92
90
|
def error_message(project)
|
|
93
|
-
"
|
|
91
|
+
"{{red:Error}} {{>}} {{blue:'#{project}'}} could not be pushed:"
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
def print_file_success(file)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
module ShopifyCLI
|
|
3
|
+
module Theme
|
|
4
|
+
module Extension
|
|
5
|
+
module UI
|
|
6
|
+
class HostThemeRawProgressBar
|
|
7
|
+
GIT_CLONE_PROGRESS_SHARE = 0.2
|
|
8
|
+
SYNC_PROGRESS_SHARE = 0.8
|
|
9
|
+
|
|
10
|
+
def initialize(syncer, dir)
|
|
11
|
+
@syncer = syncer
|
|
12
|
+
@dir = dir
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def progress(method, **args)
|
|
16
|
+
@syncer.lock_io!
|
|
17
|
+
old_sync = $stdout.sync
|
|
18
|
+
$stdout.sync = true
|
|
19
|
+
CLI::UI::ProgressPlain.progress(prefix: "Pushing theme...") do |bar|
|
|
20
|
+
bar.tick(set_percent: 0)
|
|
21
|
+
|
|
22
|
+
Git.public_send(:raw_clone, "https://github.com/Shopify/dawn.git", @dir) do |percent|
|
|
23
|
+
bar.tick(set_percent: percent * GIT_CLONE_PROGRESS_SHARE)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@syncer.public_send(method, **args) do |left, total|
|
|
27
|
+
next if total == 0
|
|
28
|
+
bar.tick(set_percent: (1 - left.to_f / total) * SYNC_PROGRESS_SHARE + GIT_CLONE_PROGRESS_SHARE)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
bar.tick(set_percent: 1)
|
|
32
|
+
end
|
|
33
|
+
$stdout.sync = old_sync
|
|
34
|
+
@syncer.unlock_io!
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'cli/ui'
|
|
2
|
+
|
|
3
|
+
module CLI
|
|
4
|
+
module UI
|
|
5
|
+
class ProgressPlain
|
|
6
|
+
# Add a plain progress bar to the terminal output
|
|
7
|
+
#
|
|
8
|
+
# ==== Example Usage:
|
|
9
|
+
#
|
|
10
|
+
# Set the percent to X
|
|
11
|
+
# CLI::UI::ProgressPlain.progress do |bar|
|
|
12
|
+
# bar.tick(set_percent: percent)
|
|
13
|
+
# end
|
|
14
|
+
def self.progress(prefix: "")
|
|
15
|
+
bar = ProgressPlain.new(prefix: prefix)
|
|
16
|
+
yield(bar)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Initialize a plain progress bar. Typically used in a +ProgressPlain.progress+ block
|
|
20
|
+
#
|
|
21
|
+
def initialize(prefix: "")
|
|
22
|
+
@percent_done = 0
|
|
23
|
+
@prefix = prefix
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Set the progress of the bar. Typically used in a +ProgressPlain.progress+ block
|
|
27
|
+
#
|
|
28
|
+
# ==== Options
|
|
29
|
+
# * +:set_percent+ - Set progress to a specific percent
|
|
30
|
+
#
|
|
31
|
+
# *Note:* The +:set_percent must be between 0.00 and 1.0
|
|
32
|
+
#
|
|
33
|
+
def tick(set_percent: nil)
|
|
34
|
+
return if @percent_done >= 1.0 # Don't print if we're already done
|
|
35
|
+
# Print only if we've moved up a whole 10% (e.g. 10%, 20%, 30%)q
|
|
36
|
+
return if (@percent_done * 100).floor != 0 && ((@percent_done * 100).floor / 10 == (set_percent * 100).floor / 10)
|
|
37
|
+
@percent_done = set_percent
|
|
38
|
+
@percent_done = [@percent_done, 1.0].min # Make sure we can't go above 1.0
|
|
39
|
+
|
|
40
|
+
print("#{to_s}\n")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Format the progress bar to be printed to terminal
|
|
44
|
+
#
|
|
45
|
+
def to_s
|
|
46
|
+
"#{@prefix} #{(@percent_done * 100).floor.to_s.rjust(5)}%"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
module CLI
|
|
2
2
|
module UI
|
|
3
|
-
autoload :ANSI,
|
|
4
|
-
autoload :Glyph,
|
|
5
|
-
autoload :Color,
|
|
6
|
-
autoload :Frame,
|
|
7
|
-
autoload :OS,
|
|
8
|
-
autoload :Printer,
|
|
9
|
-
autoload :Progress,
|
|
10
|
-
autoload :
|
|
11
|
-
autoload :
|
|
12
|
-
autoload :
|
|
13
|
-
autoload :
|
|
14
|
-
autoload :
|
|
15
|
-
autoload :
|
|
16
|
-
autoload :
|
|
3
|
+
autoload :ANSI, 'cli/ui/ansi'
|
|
4
|
+
autoload :Glyph, 'cli/ui/glyph'
|
|
5
|
+
autoload :Color, 'cli/ui/color'
|
|
6
|
+
autoload :Frame, 'cli/ui/frame'
|
|
7
|
+
autoload :OS, 'cli/ui/os'
|
|
8
|
+
autoload :Printer, 'cli/ui/printer'
|
|
9
|
+
autoload :Progress, 'cli/ui/progress'
|
|
10
|
+
autoload :ProgressPlain, 'cli/ui/progress_plain'
|
|
11
|
+
autoload :Prompt, 'cli/ui/prompt'
|
|
12
|
+
autoload :Terminal, 'cli/ui/terminal'
|
|
13
|
+
autoload :Truncater, 'cli/ui/truncater'
|
|
14
|
+
autoload :Formatter, 'cli/ui/formatter'
|
|
15
|
+
autoload :Spinner, 'cli/ui/spinner'
|
|
16
|
+
autoload :Widgets, 'cli/ui/widgets'
|
|
17
|
+
autoload :Wrap, 'cli/ui/wrap'
|
|
17
18
|
|
|
18
19
|
# Convenience accessor to +CLI::UI::Spinner::SpinGroup+
|
|
19
20
|
SpinGroup = Spinner::SpinGroup
|
|
@@ -3,21 +3,13 @@ import { stringifyMessage, outputContent, outputToken, outputDebug } from '../..
|
|
|
3
3
|
import { AbortError } from '../../../public/node/error.js';
|
|
4
4
|
import { debugLogResponseInfo } from '../api.js';
|
|
5
5
|
import { ClientError, GraphQLClient } from 'graphql-request';
|
|
6
|
-
export function graphqlRequest(query, api, url, token, variables, handleErrors = true) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return response.data;
|
|
14
|
-
};
|
|
15
|
-
if (handleErrors) {
|
|
16
|
-
return handlingErrors(api, action);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
return action();
|
|
20
|
-
}
|
|
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;
|
|
21
13
|
}
|
|
22
14
|
function debugLogRequestInfo(api, query, variables, headers = {}) {
|
|
23
15
|
outputDebug(outputContent `Sending ${outputToken.json(api)} GraphQL request:
|
|
@@ -27,11 +19,8 @@ With request headers:
|
|
|
27
19
|
${sanitizedHeadersOutput(headers)}
|
|
28
20
|
`);
|
|
29
21
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return await action();
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
22
|
+
function errorHandler(api) {
|
|
23
|
+
return (error) => {
|
|
35
24
|
if (error instanceof ClientError) {
|
|
36
25
|
const errorMessage = stringifyMessage(outputContent `
|
|
37
26
|
The ${outputToken.raw(api)} GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:
|
|
@@ -46,11 +35,11 @@ async function handlingErrors(api, action) {
|
|
|
46
35
|
mappedError = new AbortError(errorMessage);
|
|
47
36
|
}
|
|
48
37
|
mappedError.stack = error.stack;
|
|
49
|
-
|
|
38
|
+
return mappedError;
|
|
50
39
|
}
|
|
51
40
|
else {
|
|
52
|
-
|
|
41
|
+
return error;
|
|
53
42
|
}
|
|
54
|
-
}
|
|
43
|
+
};
|
|
55
44
|
}
|
|
56
45
|
//# sourceMappingURL=graphql.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACjG,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,oBAAoB,EAAC,MAAM,WAAW,CAAA;AAC9C,OAAO,EAAC,WAAW,EAAE,aAAa,EAA6B,MAAM,iBAAiB,CAAA;AAOtF,MAAM,UAAU,cAAc,
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACjG,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,oBAAoB,EAAC,MAAM,WAAW,CAAA;AAC9C,OAAO,EAAC,WAAW,EAAE,aAAa,EAA6B,MAAM,iBAAiB,CAAA;AAOtF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAsB,EACtB,GAAW,EACX,GAAW,EACX,KAAa,EACb,SAAqB,EACrB,YAAY,GAAG,IAAI;IAEnB,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACnC,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;IACnD,MAAM,aAAa,GAAG,EAAC,KAAK,EAAE,MAAM,UAAU,EAAE,EAAE,OAAO,EAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CACzC,EAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAI,KAAe,EAAE,SAAS,CAAC,EAAE,GAAG,EAAC,EAChE,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAC7C,CAAA;IACD,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,SAAS,mBAAmB,CAC1B,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,SAAS,YAAY,CAAI,GAAW;IAClC,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 {buildHeaders, httpsAgent, RequestClientError, sanitizedHeadersOutput} from './headers.js'\nimport {stringifyMessage, outputContent, outputToken, outputDebug} from '../../../public/node/output.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {debugLogResponseInfo} from '../api.js'\nimport {ClientError, GraphQLClient, RequestDocument, Variables} from 'graphql-request'\n\nexport interface GraphQLVariables {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\nexport async function graphqlRequest<T>(\n query: RequestDocument,\n api: string,\n url: string,\n token: string,\n variables?: Variables,\n handleErrors = true,\n): Promise<T> {\n const headers = buildHeaders(token)\n debugLogRequestInfo(api, query, variables, headers)\n const clientOptions = {agent: await httpsAgent(), headers}\n const client = new GraphQLClient(url, clientOptions)\n const response = await debugLogResponseInfo(\n {request: client.rawRequest<T>(query as string, variables), url},\n handleErrors ? errorHandler(api) : undefined,\n )\n return response.data\n}\n\nfunction 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\nfunction 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"]}
|
|
@@ -7,5 +7,5 @@ interface RequestOptions<T> {
|
|
|
7
7
|
export declare function debugLogResponseInfo<T extends {
|
|
8
8
|
headers: Headers;
|
|
9
9
|
status: number;
|
|
10
|
-
}>({ request, url
|
|
10
|
+
}>({ request, url }: RequestOptions<T>, errorHandler?: (error: unknown) => Error | unknown): Promise<T>;
|
|
11
11
|
export {};
|
package/dist/private/node/api.js
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
import { sanitizedHeadersOutput } from './api/headers.js';
|
|
2
2
|
import { outputDebug } from '@shopify/cli-kit/node/output';
|
|
3
|
+
import { ClientError } from 'graphql-request';
|
|
3
4
|
import { performance } from 'perf_hooks';
|
|
4
5
|
export const allAPIs = ['admin', 'storefront-renderer', 'partners'];
|
|
5
6
|
const interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id']);
|
|
6
|
-
export async function debugLogResponseInfo({ request, url,
|
|
7
|
+
export async function debugLogResponseInfo({ request, url }, errorHandler) {
|
|
7
8
|
const t0 = performance.now();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
let headers = new Headers();
|
|
10
|
+
let response = {};
|
|
11
|
+
try {
|
|
12
|
+
response = await request;
|
|
13
|
+
headers = response.headers;
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err instanceof ClientError) {
|
|
17
|
+
headers = err.response?.headers;
|
|
18
|
+
}
|
|
19
|
+
if (errorHandler) {
|
|
20
|
+
throw errorHandler(err);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
const t1 = performance.now();
|
|
28
|
+
const responseHeaders = {};
|
|
29
|
+
headers.forEach((value, key) => {
|
|
30
|
+
if (interestingResponseHeaders.has(key))
|
|
31
|
+
responseHeaders[key] = value;
|
|
32
|
+
});
|
|
33
|
+
outputDebug(`Request to ${url} completed in ${Math.round(t1 - t0)} ms
|
|
16
34
|
With response headers:
|
|
17
35
|
${sanitizedHeadersOutput(responseHeaders)}
|
|
18
36
|
`);
|
|
37
|
+
}
|
|
19
38
|
return response;
|
|
20
39
|
}
|
|
21
40
|
//# sourceMappingURL=api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AACxD,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAO1E,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AACxD,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAO1E,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAC,OAAO,EAAE,GAAG,EAAoB,EACjC,YAAkD;IAElD,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IAC5B,IAAI,OAAO,GAAY,IAAI,OAAO,EAAE,CAAA;IACpC,IAAI,QAAQ,GAAM,EAAO,CAAA;IACzB,IAAI;QACF,QAAQ,GAAG,MAAM,OAAO,CAAA;QACxB,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAA;KAC3B;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,GAAG,YAAY,WAAW,EAAE;YAC9B,OAAO,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAkB,CAAA;SAC3C;QACD,IAAI,YAAY,EAAE;YAChB,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;SACxB;aAAM;YACL,MAAM,GAAG,CAAA;SACV;KACF;YAAS;QACR,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC5B,MAAM,eAAe,GAA4B,EAAE,CAAA;QACnD,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7B,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACvE,CAAC,CAAC,CAAA;QACF,WAAW,CAAC,cAAc,GAAG,iBAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;;EAEnE,sBAAsB,CAAC,eAAe,CAAC;KACpC,CAAC,CAAA;KACH;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners']\n\ninterface RequestOptions<T> {\n request: Promise<T>\n url: string\n}\n\nconst interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id'])\n\nexport async function debugLogResponseInfo<T extends {headers: Headers; status: number}>(\n {request, url}: RequestOptions<T>,\n errorHandler?: (error: unknown) => Error | unknown,\n): Promise<T> {\n const t0 = performance.now()\n let headers: Headers = new Headers()\n let response: T = {} as T\n try {\n response = await request\n headers = response.headers\n } catch (err) {\n if (err instanceof ClientError) {\n headers = err.response?.headers as Headers\n }\n if (errorHandler) {\n throw errorHandler(err)\n } else {\n throw err\n }\n } finally {\n const t1 = performance.now()\n const responseHeaders: {[key: string]: string} = {}\n headers.forEach((value, key) => {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n })\n outputDebug(`Request to ${url} completed in ${Math.round(t1 - t0)} ms\nWith response headers:\n${sanitizedHeadersOutput(responseHeaders)}\n `)\n }\n return response\n}\n"]}
|
|
@@ -22,7 +22,6 @@ export const environmentVariables = {
|
|
|
22
22
|
unitTest: 'SHOPIFY_UNIT_TEST',
|
|
23
23
|
verbose: 'SHOPIFY_FLAG_VERBOSE',
|
|
24
24
|
themeBundling: 'SHOPIFY_CLI_THEME_BUNDLING',
|
|
25
|
-
javascriptFunctions: 'SHOPIFY_CLI_FUNCTIONS_JAVASCRIPT',
|
|
26
25
|
// Variables to detect if the CLI is running in a cloud environment
|
|
27
26
|
codespaceName: 'CODESPACE_NAME',
|
|
28
27
|
codespaces: 'CODESPACES',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,aAAa,EAAE,4BAA4B;IAC3C,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,aAAa,EAAE,4BAA4B;IAC3C,mEAAmE;IACnE,aAAa,EAAE,gBAAgB;IAC/B,UAAU,EAAE,YAAY;IACxB,MAAM,EAAE,sBAAsB;IAC9B,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,eAAe;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE;QACX,GAAG,EAAE,kBAAkB;KACxB;IACD,WAAW,EAAE;QACX,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,OAAO,WAAW,EAAE,CAAA;YACtB,CAAC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,GAAG,EAAE;oBACT,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;gBAC1C,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACtD,CAAC;aACF;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,aAAa;CACvB,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6BAA6B,EAAE,CAAC;CACjC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,kCAAkC,CAAA","sourcesContent":["import {joinPath} from '../../public/node/path.js'\nimport envPaths from 'env-paths'\n\nconst identifier = 'shopify-cli'\n\nconst cacheFolder = () => {\n if (process.env.XDG_CACHE_HOME) return process.env.XDG_CACHE_HOME\n return envPaths(identifier).cache\n}\n\nexport const environmentVariables = {\n alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',\n deviceAuth: 'SHOPIFY_CLI_DEVICE_AUTH',\n enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT',\n env: 'SHOPIFY_CLI_ENV',\n firstPartyDev: 'SHOPIFY_CLI_1P_DEV',\n noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS',\n partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',\n runAsUser: 'SHOPIFY_RUN_AS_USER',\n serviceEnv: 'SHOPIFY_SERVICE_ENV',\n skipCliRedirect: 'SHOPIFY_CLI_SKIP_CLI_REDIRECT',\n spinInstance: 'SPIN_INSTANCE',\n themeToken: 'SHOPIFY_CLI_THEME_TOKEN',\n unitTest: 'SHOPIFY_UNIT_TEST',\n verbose: 'SHOPIFY_FLAG_VERBOSE',\n themeBundling: 'SHOPIFY_CLI_THEME_BUNDLING',\n // Variables to detect if the CLI is running in a cloud environment\n codespaceName: 'CODESPACE_NAME',\n codespaces: 'CODESPACES',\n gitpod: 'GITPOD_WORKSPACE_URL',\n spin: 'SPIN',\n spinAppPort: 'SERVER_PORT',\n spinAppHost: 'SPIN_APP_HOST',\n}\n\nexport const pathConstants = {\n executables: {\n dev: '/opt/dev/bin/dev',\n },\n directories: {\n cache: {\n path: () => {\n return cacheFolder()\n },\n vendor: {\n path: () => {\n return joinPath(cacheFolder(), 'vendor')\n },\n binaries: () => {\n return joinPath(cacheFolder(), 'vendor', 'binaries')\n },\n },\n },\n },\n}\n\nexport const keychainConstants = {\n service: 'shopify-cli',\n}\n\nexport const sessionConstants = {\n expirationTimeMarginInMinutes: 4,\n}\n\nexport const bugsnagApiKey = '9e1e6889176fd0c795d5c659225e0fae'\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getFavicon, getStylesheet, getEmptyUrlHTML, getAuthErrorHTML, getMissingCodeHTML, getMissingStateHTML, getSuccessHTML, EmptyUrlString, MissingCodeString, MissingStateString, } from './post-auth.js';
|
|
2
2
|
import { AbortError, BugError } from '../../../public/node/error.js';
|
|
3
3
|
import { outputContent, outputInfo, outputToken } from '../../../public/node/output.js';
|
|
4
|
-
import { createApp } from 'h3';
|
|
5
4
|
import url from 'url';
|
|
6
5
|
import { createServer } from 'http';
|
|
7
6
|
const ResponseTimeoutSeconds = 10;
|
|
@@ -15,7 +14,7 @@ const ServerStopDelaySeconds = 0.5;
|
|
|
15
14
|
*/
|
|
16
15
|
export class RedirectListener {
|
|
17
16
|
static createServer(callback) {
|
|
18
|
-
const app =
|
|
17
|
+
const app = async (request, response) => {
|
|
19
18
|
const requestUrl = request.url;
|
|
20
19
|
if (requestUrl?.includes('favicon')) {
|
|
21
20
|
const faviconFile = await getFavicon();
|
|
@@ -65,7 +64,7 @@ export class RedirectListener {
|
|
|
65
64
|
}
|
|
66
65
|
const file = await getSuccessHTML();
|
|
67
66
|
return respond(file, undefined, `${queryObject.code}`, `${queryObject.state}`);
|
|
68
|
-
}
|
|
67
|
+
};
|
|
69
68
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
70
69
|
return createServer(app);
|
|
71
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect-listener.js","sourceRoot":"","sources":["../../../../src/private/node/session/redirect-listener.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AAClE,OAAO,EAAC,aAAa,EAAE,UAAU,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AACrF,OAAO,
|
|
1
|
+
{"version":3,"file":"redirect-listener.js","sourceRoot":"","sources":["../../../../src/private/node/session/redirect-listener.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getFavicon,\n getStylesheet,\n getEmptyUrlHTML,\n getAuthErrorHTML,\n getMissingCodeHTML,\n getMissingStateHTML,\n getSuccessHTML,\n EmptyUrlString,\n MissingCodeString,\n MissingStateString,\n} from './post-auth.js'\nimport {AbortError, BugError} from '../../../public/node/error.js'\nimport {outputContent, outputInfo, outputToken} from '../../../public/node/output.js'\nimport url from 'url'\nimport {createServer, Server, IncomingMessage, ServerResponse} from 'http'\n\nconst ResponseTimeoutSeconds = 10\nconst ServerStopDelaySeconds = 0.5\n\n/**\n * It represents the result of a redirect.\n */\ntype RedirectCallback = (error: Error | undefined, state: string | undefined, code: string | undefined) => void\n\n/**\n * Defines the interface of the options that\n * are used to instantiate a redirect listener.\n */\ninterface RedirectListenerOptions {\n host: string\n port: number\n callback: RedirectCallback\n}\n/**\n * When the authentication completes, Identity redirects\n * the user to a URL. In the case of the CLI, the redirect\n * is to localhost passing some parameters that are necessary\n * to continue the authentication. Because of that, we need\n * an HTTP server that runs and listens to the request.\n */\nexport class RedirectListener {\n private static createServer(callback: RedirectCallback): Server {\n const app = async (request: IncomingMessage, response: ServerResponse) => {\n const requestUrl = request.url\n if (requestUrl?.includes('favicon')) {\n const faviconFile = await getFavicon()\n response.setHeader('Content-Type', 'image/svg+xml')\n response.write(faviconFile)\n response.end()\n return {}\n } else if (requestUrl === '/style.css') {\n const stylesheetFile = await getStylesheet()\n response.setHeader('Content-Type', 'text/css')\n response.write(stylesheetFile)\n response.end()\n return {}\n }\n\n const respond = async (contents: string, error?: Error, state?: string, code?: string) => {\n response.setHeader('Content-Type', 'text/html')\n response.write(contents)\n response.end()\n callback(error, state, code)\n return {}\n }\n\n // If there was an empty/malformed URL sent back.\n if (!requestUrl) {\n const file = await getEmptyUrlHTML()\n const err = new BugError(EmptyUrlString)\n return respond(file, err, undefined, undefined)\n }\n\n // If an error was returned by the Identity server.\n const queryObject = url.parse(requestUrl, true).query\n if (queryObject.error && queryObject.error_description) {\n const file = await getAuthErrorHTML()\n const err = new AbortError(`${queryObject.error_description}`)\n return respond(file, err, undefined, undefined)\n }\n\n // If the code isn't present in the URL.\n if (!queryObject.code) {\n const file = await getMissingCodeHTML()\n const err = new BugError(MissingCodeString)\n return respond(file, err, undefined, undefined)\n }\n\n // If the state isn't present in the URL.\n if (!queryObject.state) {\n const file = await getMissingStateHTML()\n const err = new BugError(MissingStateString)\n return respond(file, err, undefined, undefined)\n }\n\n const file = await getSuccessHTML()\n return respond(file, undefined, `${queryObject.code}`, `${queryObject.state}`)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return createServer(app)\n }\n\n port: number\n host: string\n server: ReturnType<typeof RedirectListener.createServer>\n\n constructor(options: RedirectListenerOptions) {\n this.port = options.port\n this.host = options.host\n this.server = RedirectListener.createServer(options.callback)\n }\n\n start(): void {\n this.server.listen({port: this.port, host: this.host}, () => {})\n }\n\n async stop(): Promise<void> {\n await this.server.close()\n }\n}\n\nexport async function listenRedirect(host: string, port: number, url: string): Promise<{code: string; state: string}> {\n const result = await new Promise<{code: string; state: string}>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const message = '\\nAuto-open timed out. Open the login page: '\n outputInfo(outputContent`${message}${outputToken.link('Log in to Shopify Partners', url)}\\n`)\n }, ResponseTimeoutSeconds * 1000)\n\n const callback: RedirectCallback = (error, code, state) => {\n clearTimeout(timeout)\n setTimeout(() => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n redirectListener.stop()\n if (error) reject(error)\n else resolve({code: code as string, state: state as string})\n }, ServerStopDelaySeconds * 1000)\n }\n\n const redirectListener = new RedirectListener({host, port, callback})\n redirectListener.start()\n })\n return result\n}\n"]}
|