shopify-cli 0.9.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.
Files changed (273) hide show
  1. checksums.yaml +7 -0
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/CODE_OF_CONDUCT.md +73 -0
  4. data/.github/CONTRIBUTING.md +51 -0
  5. data/.github/DESIGN.md +153 -0
  6. data/.github/ISSUE_TEMPLATE.md +38 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  8. data/.github/probots.yml +3 -0
  9. data/.gitignore +19 -0
  10. data/.rubocop.yml +47 -0
  11. data/.ruby-version +1 -0
  12. data/.travis.yml +12 -0
  13. data/Gemfile +22 -0
  14. data/Gemfile.lock +77 -0
  15. data/LICENSE.md +7 -0
  16. data/README.md +13 -0
  17. data/Rakefile +101 -0
  18. data/SECURITY.md +59 -0
  19. data/Vagrantfile +17 -0
  20. data/bin/load_shopify.rb +20 -0
  21. data/bin/shopify +32 -0
  22. data/dev.yml +17 -0
  23. data/docs/Gemfile +5 -0
  24. data/docs/Gemfile.lock +248 -0
  25. data/docs/_config.yml +16 -0
  26. data/docs/_data/nav.yml +26 -0
  27. data/docs/_includes/footer.html +15 -0
  28. data/docs/_includes/head.html +19 -0
  29. data/docs/_includes/sidebar_nav.html +22 -0
  30. data/docs/_includes/toc.html +112 -0
  31. data/docs/_layouts/default.html +79 -0
  32. data/docs/app/node/commands/index.md +82 -0
  33. data/docs/app/node/index.md +35 -0
  34. data/docs/app/rails/commands/index.md +80 -0
  35. data/docs/app/rails/index.md +36 -0
  36. data/docs/core/index.md +70 -0
  37. data/docs/css/docs.css +157 -0
  38. data/docs/getting-started/index.md +61 -0
  39. data/docs/help/start-app/index.md +6 -0
  40. data/docs/images/header.png +0 -0
  41. data/docs/index.md +27 -0
  42. data/docs/installing-ruby.md +28 -0
  43. data/ext/shopify-cli/extconf.rb +27 -0
  44. data/install.sh +7 -0
  45. data/lib/docgen/class_template.md.erb +81 -0
  46. data/lib/docgen/index_template.md.erb +5 -0
  47. data/lib/docgen/markdown.rb +101 -0
  48. data/lib/graphql/admin_introspection.graphql +87 -0
  49. data/lib/graphql/all_organizations.graphql +19 -0
  50. data/lib/graphql/all_orgs_with_apps.graphql +30 -0
  51. data/lib/graphql/api_versions.graphql +6 -0
  52. data/lib/graphql/convert_dev_to_test_store.graphql +10 -0
  53. data/lib/graphql/create_app.graphql +20 -0
  54. data/lib/graphql/create_customer.graphql +9 -0
  55. data/lib/graphql/create_draft_order.graphql +8 -0
  56. data/lib/graphql/create_product.graphql +9 -0
  57. data/lib/graphql/extension_create.graphql +21 -0
  58. data/lib/graphql/extension_update_draft.graphql +18 -0
  59. data/lib/graphql/find_organization.graphql +17 -0
  60. data/lib/graphql/get_app_urls.graphql +6 -0
  61. data/lib/graphql/update_dashboard_urls.graphql +8 -0
  62. data/lib/project_types/extension/cli.rb +71 -0
  63. data/lib/project_types/extension/commands/build.rb +29 -0
  64. data/lib/project_types/extension/commands/create.rb +49 -0
  65. data/lib/project_types/extension/commands/extension_command.rb +22 -0
  66. data/lib/project_types/extension/commands/push.rb +69 -0
  67. data/lib/project_types/extension/commands/register.rb +78 -0
  68. data/lib/project_types/extension/commands/serve.rb +24 -0
  69. data/lib/project_types/extension/commands/tunnel.rb +69 -0
  70. data/lib/project_types/extension/extension_project.rb +85 -0
  71. data/lib/project_types/extension/extension_project_keys.rb +10 -0
  72. data/lib/project_types/extension/features/argo.rb +48 -0
  73. data/lib/project_types/extension/features/argo_dependencies.rb +28 -0
  74. data/lib/project_types/extension/features/argo_setup.rb +54 -0
  75. data/lib/project_types/extension/features/argo_setup_step.rb +31 -0
  76. data/lib/project_types/extension/features/argo_setup_steps.rb +53 -0
  77. data/lib/project_types/extension/features/tunnel_url.rb +20 -0
  78. data/lib/project_types/extension/forms/create.rb +52 -0
  79. data/lib/project_types/extension/forms/register.rb +48 -0
  80. data/lib/project_types/extension/messages/message_loading.rb +37 -0
  81. data/lib/project_types/extension/messages/messages.rb +126 -0
  82. data/lib/project_types/extension/models/app.rb +14 -0
  83. data/lib/project_types/extension/models/registration.rb +19 -0
  84. data/lib/project_types/extension/models/type.rb +76 -0
  85. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +20 -0
  86. data/lib/project_types/extension/models/types/subscription_management.rb +20 -0
  87. data/lib/project_types/extension/models/validation_error.rb +17 -0
  88. data/lib/project_types/extension/models/version.rb +15 -0
  89. data/lib/project_types/extension/tasks/converters/registration_converter.rb +26 -0
  90. data/lib/project_types/extension/tasks/converters/validation_error_converter.rb +25 -0
  91. data/lib/project_types/extension/tasks/converters/version_converter.rb +28 -0
  92. data/lib/project_types/extension/tasks/create_extension.rb +31 -0
  93. data/lib/project_types/extension/tasks/get_apps.rb +34 -0
  94. data/lib/project_types/extension/tasks/update_draft.rb +29 -0
  95. data/lib/project_types/extension/tasks/user_errors.rb +45 -0
  96. data/lib/project_types/node/cli.rb +37 -0
  97. data/lib/project_types/node/commands/create.rb +117 -0
  98. data/lib/project_types/node/commands/deploy.rb +22 -0
  99. data/lib/project_types/node/commands/deploy/heroku.rb +91 -0
  100. data/lib/project_types/node/commands/generate.rb +51 -0
  101. data/lib/project_types/node/commands/generate/billing.rb +37 -0
  102. data/lib/project_types/node/commands/generate/page.rb +55 -0
  103. data/lib/project_types/node/commands/generate/webhook.rb +33 -0
  104. data/lib/project_types/node/commands/open.rb +16 -0
  105. data/lib/project_types/node/commands/populate.rb +23 -0
  106. data/lib/project_types/node/commands/populate/customer.rb +31 -0
  107. data/lib/project_types/node/commands/populate/draft_order.rb +28 -0
  108. data/lib/project_types/node/commands/populate/product.rb +30 -0
  109. data/lib/project_types/node/commands/serve.rb +45 -0
  110. data/lib/project_types/node/commands/tunnel.rb +39 -0
  111. data/lib/project_types/node/forms/create.rb +87 -0
  112. data/lib/project_types/node/messages/messages.rb +260 -0
  113. data/lib/project_types/rails/cli.rb +41 -0
  114. data/lib/project_types/rails/commands/create.rb +126 -0
  115. data/lib/project_types/rails/commands/deploy.rb +22 -0
  116. data/lib/project_types/rails/commands/deploy/heroku.rb +113 -0
  117. data/lib/project_types/rails/commands/generate.rb +49 -0
  118. data/lib/project_types/rails/commands/generate/webhook.rb +39 -0
  119. data/lib/project_types/rails/commands/open.rb +16 -0
  120. data/lib/project_types/rails/commands/populate.rb +23 -0
  121. data/lib/project_types/rails/commands/populate/customer.rb +31 -0
  122. data/lib/project_types/rails/commands/populate/draft_order.rb +28 -0
  123. data/lib/project_types/rails/commands/populate/product.rb +30 -0
  124. data/lib/project_types/rails/commands/serve.rb +47 -0
  125. data/lib/project_types/rails/commands/tunnel.rb +39 -0
  126. data/lib/project_types/rails/forms/create.rb +116 -0
  127. data/lib/project_types/rails/gem.rb +56 -0
  128. data/lib/project_types/rails/messages/messages.rb +283 -0
  129. data/lib/project_types/rails/ruby.rb +17 -0
  130. data/lib/project_types/script/cli.rb +76 -0
  131. data/lib/project_types/script/commands/create.rb +45 -0
  132. data/lib/project_types/script/commands/disable.rb +36 -0
  133. data/lib/project_types/script/commands/enable.rb +46 -0
  134. data/lib/project_types/script/commands/push.rb +39 -0
  135. data/lib/project_types/script/config/extension_points.yml +18 -0
  136. data/lib/project_types/script/errors.rb +16 -0
  137. data/lib/project_types/script/forms/create.rb +29 -0
  138. data/lib/project_types/script/forms/enable.rb +24 -0
  139. data/lib/project_types/script/forms/push.rb +19 -0
  140. data/lib/project_types/script/forms/script_form.rb +66 -0
  141. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +27 -0
  142. data/lib/project_types/script/graphql/script_service_proxy.graphql +8 -0
  143. data/lib/project_types/script/graphql/shop_script_delete.graphql +14 -0
  144. data/lib/project_types/script/graphql/shop_script_update_or_create.graphql +28 -0
  145. data/lib/project_types/script/layers/application/build_script.rb +43 -0
  146. data/lib/project_types/script/layers/application/create_script.rb +47 -0
  147. data/lib/project_types/script/layers/application/disable_script.rb +19 -0
  148. data/lib/project_types/script/layers/application/enable_script.rb +21 -0
  149. data/lib/project_types/script/layers/application/extension_points.rb +17 -0
  150. data/lib/project_types/script/layers/application/project_dependencies.rb +34 -0
  151. data/lib/project_types/script/layers/application/push_script.rb +30 -0
  152. data/lib/project_types/script/layers/domain/errors.rb +25 -0
  153. data/lib/project_types/script/layers/domain/extension_point.rb +29 -0
  154. data/lib/project_types/script/layers/domain/push_package.rb +29 -0
  155. data/lib/project_types/script/layers/domain/script.rb +18 -0
  156. data/lib/project_types/script/layers/infrastructure/assemblyscript_dependency_manager.rb +73 -0
  157. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +38 -0
  158. data/lib/project_types/script/layers/infrastructure/assemblyscript_wasm_builder.rb +39 -0
  159. data/lib/project_types/script/layers/infrastructure/dependency_manager.rb +36 -0
  160. data/lib/project_types/script/layers/infrastructure/errors.rb +38 -0
  161. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +31 -0
  162. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +47 -0
  163. data/lib/project_types/script/layers/infrastructure/script_builder.rb +34 -0
  164. data/lib/project_types/script/layers/infrastructure/script_repository.rb +89 -0
  165. data/lib/project_types/script/layers/infrastructure/script_service.rb +165 -0
  166. data/lib/project_types/script/layers/infrastructure/test_suite_repository.rb +59 -0
  167. data/lib/project_types/script/messages/messages.rb +204 -0
  168. data/lib/project_types/script/script_project.rb +37 -0
  169. data/lib/project_types/script/templates/ts/as-pect.config.js +21 -0
  170. data/lib/project_types/script/ui/error_handler.rb +136 -0
  171. data/lib/project_types/script/ui/strict_spinner.rb +22 -0
  172. data/lib/rubygems_plugin.rb +18 -0
  173. data/lib/shopify-cli/admin_api.rb +99 -0
  174. data/lib/shopify-cli/admin_api/populate_resource_command.rb +165 -0
  175. data/lib/shopify-cli/admin_api/schema.rb +32 -0
  176. data/lib/shopify-cli/api.rb +104 -0
  177. data/lib/shopify-cli/command.rb +67 -0
  178. data/lib/shopify-cli/commands.rb +28 -0
  179. data/lib/shopify-cli/commands/connect.rb +108 -0
  180. data/lib/shopify-cli/commands/create.rb +50 -0
  181. data/lib/shopify-cli/commands/help.rb +79 -0
  182. data/lib/shopify-cli/commands/logout.rb +23 -0
  183. data/lib/shopify-cli/commands/system.rb +135 -0
  184. data/lib/shopify-cli/commands/version.rb +15 -0
  185. data/lib/shopify-cli/context.rb +372 -0
  186. data/lib/shopify-cli/core.rb +9 -0
  187. data/lib/shopify-cli/core/entry_point.rb +40 -0
  188. data/lib/shopify-cli/core/executor.rb +21 -0
  189. data/lib/shopify-cli/core/help_resolver.rb +20 -0
  190. data/lib/shopify-cli/core/monorail.rb +118 -0
  191. data/lib/shopify-cli/db.rb +114 -0
  192. data/lib/shopify-cli/form.rb +40 -0
  193. data/lib/shopify-cli/git.rb +141 -0
  194. data/lib/shopify-cli/helpers.rb +5 -0
  195. data/lib/shopify-cli/helpers/haikunator.rb +92 -0
  196. data/lib/shopify-cli/heroku.rb +97 -0
  197. data/lib/shopify-cli/js_deps.rb +110 -0
  198. data/lib/shopify-cli/js_system.rb +98 -0
  199. data/lib/shopify-cli/messages/messages.rb +287 -0
  200. data/lib/shopify-cli/oauth.rb +192 -0
  201. data/lib/shopify-cli/oauth/servlet.rb +61 -0
  202. data/lib/shopify-cli/options.rb +40 -0
  203. data/lib/shopify-cli/packager.rb +116 -0
  204. data/lib/shopify-cli/partners_api.rb +114 -0
  205. data/lib/shopify-cli/partners_api/organizations.rb +32 -0
  206. data/lib/shopify-cli/process_supervision.rb +187 -0
  207. data/lib/shopify-cli/project.rb +191 -0
  208. data/lib/shopify-cli/project_type.rb +83 -0
  209. data/lib/shopify-cli/resources.rb +5 -0
  210. data/lib/shopify-cli/resources/env_file.rb +96 -0
  211. data/lib/shopify-cli/sub_command.rb +15 -0
  212. data/lib/shopify-cli/task.rb +10 -0
  213. data/lib/shopify-cli/tasks.rb +32 -0
  214. data/lib/shopify-cli/tasks/create_api_client.rb +29 -0
  215. data/lib/shopify-cli/tasks/ensure_dev_store.rb +41 -0
  216. data/lib/shopify-cli/tasks/ensure_env.rb +31 -0
  217. data/lib/shopify-cli/tasks/ensure_loopback_url.rb +20 -0
  218. data/lib/shopify-cli/tasks/update_dashboard_urls.rb +44 -0
  219. data/lib/shopify-cli/tunnel.rb +154 -0
  220. data/lib/shopify-cli/version.rb +3 -0
  221. data/lib/shopify_cli.rb +132 -0
  222. data/shopify-cli.gemspec +40 -0
  223. data/shopify.fish +12 -0
  224. data/shopify.sh +11 -0
  225. data/vendor/deps/cli-kit/REVISION +1 -0
  226. data/vendor/deps/cli-kit/lib/cli/kit.rb +60 -0
  227. data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +21 -0
  228. data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +49 -0
  229. data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +94 -0
  230. data/vendor/deps/cli-kit/lib/cli/kit/config.rb +133 -0
  231. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +115 -0
  232. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +81 -0
  233. data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +102 -0
  234. data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +82 -0
  235. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +76 -0
  236. data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +60 -0
  237. data/vendor/deps/cli-kit/lib/cli/kit/ruby_backports/enumerable.rb +6 -0
  238. data/vendor/deps/cli-kit/lib/cli/kit/support.rb +9 -0
  239. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +244 -0
  240. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +207 -0
  241. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +189 -0
  242. data/vendor/deps/cli-kit/lib/cli/kit/version.rb +5 -0
  243. data/vendor/deps/cli-ui/REVISION +1 -0
  244. data/vendor/deps/cli-ui/lib/cli/ui.rb +187 -0
  245. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +153 -0
  246. data/vendor/deps/cli-ui/lib/cli/ui/box.rb +15 -0
  247. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +79 -0
  248. data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +179 -0
  249. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +310 -0
  250. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +78 -0
  251. data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +88 -0
  252. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +248 -0
  253. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +472 -0
  254. data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +24 -0
  255. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +48 -0
  256. data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +40 -0
  257. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +241 -0
  258. data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +227 -0
  259. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +36 -0
  260. data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +102 -0
  261. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +5 -0
  262. data/vendor/deps/smart_properties/REVISION +1 -0
  263. data/vendor/deps/smart_properties/lib/smart_properties.rb +174 -0
  264. data/vendor/deps/smart_properties/lib/smart_properties/errors.rb +114 -0
  265. data/vendor/deps/smart_properties/lib/smart_properties/property.rb +162 -0
  266. data/vendor/deps/smart_properties/lib/smart_properties/property_collection.rb +83 -0
  267. data/vendor/deps/smart_properties/lib/smart_properties/validations.rb +8 -0
  268. data/vendor/deps/smart_properties/lib/smart_properties/validations/ancestor.rb +27 -0
  269. data/vendor/deps/smart_properties/lib/smart_properties/version.rb +3 -0
  270. data/vendor/lib/semantic/LICENSE +20 -0
  271. data/vendor/lib/semantic/semantic.rb +4 -0
  272. data/vendor/lib/semantic/version.rb +180 -0
  273. metadata +374 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module Script
6
+ module Layers
7
+ module Infrastructure
8
+ class AssemblyScriptTsConfig
9
+ TSCONFIG_FILE = "tsconfig.json"
10
+
11
+ attr_reader :config
12
+
13
+ def initialize(dir_to_write_in:)
14
+ @dir_to_write_in = dir_to_write_in
15
+ @config = {}
16
+ end
17
+
18
+ def with_extends_assemblyscript_config(relative_path_to_node_modules:)
19
+ relative_path = Pathname.new(relative_path_to_node_modules).relative_path_from(@dir_to_write_in)
20
+ @config[:extends] = "#{relative_path}/node_modules/assemblyscript/std/assembly.json"
21
+ self
22
+ end
23
+
24
+ def with_module_resolution_paths(paths:)
25
+ @config[:compilerOptions] = {
26
+ baseUrl: ".",
27
+ paths: paths,
28
+ }
29
+ self
30
+ end
31
+
32
+ def write
33
+ File.write("#{@dir_to_write_in}/#{TSCONFIG_FILE}", JSON.pretty_generate(@config))
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class AssemblyScriptWasmBuilder
7
+ BYTECODE_FILE = "%{name}.wasm"
8
+ SCRIPT_SDK_BUILD = "npx --no-install shopify-scripts-build --src=../%{source} --binary=#{BYTECODE_FILE} "\
9
+ "-- --lib=../node_modules --validate --optimize"
10
+
11
+ attr_reader :script
12
+
13
+ def initialize(script)
14
+ @script = script
15
+ end
16
+
17
+ def build
18
+ compile
19
+ bytecode
20
+ end
21
+
22
+ def compiled_type
23
+ "wasm"
24
+ end
25
+
26
+ private
27
+
28
+ def compile
29
+ out, status = CLI::Kit::System.capture2e(format(SCRIPT_SDK_BUILD, source: script.id, name: script.name))
30
+ raise Domain::Errors::ServiceFailureError, out unless status.success?
31
+ end
32
+
33
+ def bytecode
34
+ File.read(format(BYTECODE_FILE, name: script.name))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class NoopDependencyManager
7
+ def initialize(_ctx, language, _extension_point, script_name)
8
+ @language = language
9
+ @script_name = script_name
10
+ end
11
+
12
+ def bootstrap
13
+ end
14
+
15
+ def installed?
16
+ end
17
+
18
+ def install
19
+ end
20
+ end
21
+
22
+ class DependencyManager
23
+ DEP_MANAGER = {
24
+ "ts" => AssemblyScriptDependencyManager,
25
+ "js" => NoopDependencyManager,
26
+ "json" => NoopDependencyManager,
27
+ }
28
+
29
+ def self.for(ctx, language, extension_point, script_name)
30
+ raise Errors::DependencyError, language unless DEP_MANAGER[language]
31
+ DEP_MANAGER[language].new(ctx, language, extension_point, script_name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Errors
7
+ class AppNotInstalledError < ScriptProjectError; end
8
+ class AppScriptUndefinedError < ScriptProjectError; end
9
+ class BuilderNotFoundError < ScriptProjectError; end
10
+ class BuildError < ScriptProjectError; end
11
+ class DependencyError < ScriptProjectError; end
12
+ class DependencyInstallError < ScriptProjectError; end
13
+ class ForbiddenError < ScriptProjectError; end
14
+ class GraphqlError < ScriptProjectError
15
+ attr_reader :errors
16
+ def initialize(errors)
17
+ @errors = errors
18
+ super("GraphQL failed with errors: #{errors}")
19
+ end
20
+ end
21
+ class ScriptRepushError < ScriptProjectError
22
+ attr_reader :api_key
23
+ def initialize(api_key)
24
+ @api_key = api_key
25
+ end
26
+ end
27
+ class ScriptServiceUserError < ScriptProjectError
28
+ def initialize(query_name, errors)
29
+ super("Failed performing #{query_name}. Errors: #{errors}.")
30
+ end
31
+ end
32
+ class ShopAuthenticationError < ScriptProjectError; end
33
+ class ShopScriptConflictError < ScriptProjectError; end
34
+ class ShopScriptUndefinedError < ScriptProjectError; end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class ExtensionPointRepository
7
+ def get_extension_point(type)
8
+ Domain::ExtensionPoint.new(type, fetch_extension_point(type))
9
+ end
10
+
11
+ def extension_point_types
12
+ extension_points.keys
13
+ end
14
+
15
+ private
16
+
17
+ def fetch_extension_point(type)
18
+ raise Domain::Errors::InvalidExtensionPointError, type unless extension_points[type]
19
+ extension_points[type]
20
+ end
21
+
22
+ def extension_points
23
+ @extension_points ||= begin
24
+ require 'yaml'
25
+ YAML.load_file(Project.project_filepath('config/extension_points.yml'))
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class PushPackageRepository
7
+ def create_push_package(script, script_content, compiled_type)
8
+ build_file_path = file_path(script.name, compiled_type)
9
+ write_to_path(build_file_path, script_content)
10
+
11
+ Domain::PushPackage.new(
12
+ build_file_path,
13
+ script,
14
+ script_content,
15
+ compiled_type,
16
+ )
17
+ end
18
+
19
+ def get_push_package(script, compiled_type)
20
+ build_file_path = file_path(script.name, compiled_type)
21
+
22
+ raise Domain::PushPackageNotFoundError unless File.exist?(build_file_path)
23
+
24
+ script_content = File.read(build_file_path)
25
+
26
+ Domain::PushPackage.new(
27
+ build_file_path,
28
+ script,
29
+ script_content,
30
+ compiled_type,
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def write_to_path(path, content)
37
+ FileUtils.mkdir_p(File.dirname(path))
38
+ File.write(path, content)
39
+ end
40
+
41
+ def file_path(script_name, compiled_type)
42
+ "#{ScriptProject.current.directory}/build/#{script_name}.#{compiled_type}"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class NoopBuilder
7
+ def initialize(script)
8
+ @script = script
9
+ end
10
+
11
+ def build
12
+ File.read(@script.filename)
13
+ end
14
+
15
+ def compiled_type
16
+ @script.language
17
+ end
18
+ end
19
+
20
+ class ScriptBuilder
21
+ COMPILERS = {
22
+ "ts" => Infrastructure::AssemblyScriptWasmBuilder,
23
+ "js" => Infrastructure::NoopBuilder,
24
+ "json" => Infrastructure::NoopBuilder,
25
+ }
26
+
27
+ def self.for(script)
28
+ raise Errors::BuilderNotFoundError unless COMPILERS[script.language]
29
+ COMPILERS[script.language].new(script)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class ScriptRepository
7
+ BOOTSTRAP_SRC = "npx --no-install shopify-scripts-bootstrap src %{src_base}"
8
+
9
+ def create_script(language, extension_point, script_name)
10
+ FileUtils.mkdir_p(src_base)
11
+ out, status = CLI::Kit::System.capture2e(format(BOOTSTRAP_SRC, src_base: src_base))
12
+ raise Domain::Errors::ServiceFailureError, out unless status.success?
13
+
14
+ write_tsconfig if language == "ts"
15
+
16
+ Domain::Script.new(
17
+ script_id(language),
18
+ script_name,
19
+ extension_point.type,
20
+ language
21
+ )
22
+ end
23
+
24
+ def get_script(language, extension_point_type, script_name)
25
+ source_file_path = src_code_file(language)
26
+ unless File.exist?(source_file_path)
27
+ raise Domain::Errors::ScriptNotFoundError.new(extension_point_type, source_file_path)
28
+ end
29
+
30
+ Domain::Script.new(script_id(language), script_name, extension_point_type, language)
31
+ end
32
+
33
+ def with_temp_build_context
34
+ prev_dir = Dir.pwd
35
+ temp_dir = "#{project_base}/temp"
36
+ FileUtils.mkdir_p(temp_dir)
37
+ Dir.chdir(temp_dir)
38
+ FileUtils.cp_r("#{src_base}/.", ".")
39
+ yield
40
+ ensure
41
+ Dir.chdir(prev_dir)
42
+ FileUtils.rm_rf(temp_dir)
43
+ end
44
+
45
+ def relative_path_to_src
46
+ "src"
47
+ end
48
+
49
+ private
50
+
51
+ def write_sdk(extension_point_type, language, sdk_types)
52
+ return unless language == "ts"
53
+ File.write(sdk_types_file(extension_point_type, language), sdk_types)
54
+ end
55
+
56
+ def write_tsconfig
57
+ AssemblyScriptTsConfig
58
+ .new(dir_to_write_in: relative_path_to_src)
59
+ .with_extends_assemblyscript_config(relative_path_to_node_modules: ".")
60
+ .write
61
+ end
62
+
63
+ def project_base
64
+ ScriptProject.current.directory
65
+ end
66
+
67
+ def src_base
68
+ "#{project_base}/#{relative_path_to_src}"
69
+ end
70
+
71
+ def script_id(language)
72
+ "#{relative_path_to_src}/#{file_name(language)}"
73
+ end
74
+
75
+ def src_code_file(language)
76
+ "#{src_base}/#{file_name(language)}"
77
+ end
78
+
79
+ def file_name(language)
80
+ "script.#{language}"
81
+ end
82
+
83
+ def sdk_types_file(extension_point_type, language)
84
+ "#{src_base}/#{extension_point_type}.#{language}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "json"
5
+
6
+ module Script
7
+ module Layers
8
+ module Infrastructure
9
+ class ScriptService
10
+ include SmartProperties
11
+ property! :ctx, accepts: ShopifyCli::Context
12
+
13
+ def push(
14
+ extension_point_type:,
15
+ script_name:,
16
+ script_content:,
17
+ compiled_type:,
18
+ api_key: nil,
19
+ force: false
20
+ )
21
+ query_name = "app_script_update_or_create"
22
+ variables = {
23
+ extensionPointName: extension_point_type.upcase,
24
+ title: script_name,
25
+ sourceCode: Base64.encode64(script_content),
26
+ language: compiled_type,
27
+ force: force,
28
+ }
29
+ resp_hash = script_service_request(query_name: query_name, api_key: api_key, variables: variables)
30
+ user_errors = resp_hash["data"]["appScriptUpdateOrCreate"]["userErrors"]
31
+
32
+ return resp_hash if user_errors.empty?
33
+
34
+ if user_errors.any? { |e| e['tag'] == 'already_exists_error' }
35
+ raise Errors::ScriptRepushError, api_key
36
+ else
37
+ raise Errors::ScriptServiceUserError.new(query_name, user_errors.to_s)
38
+ end
39
+ end
40
+
41
+ def enable(api_key:, shop_domain:, configuration:, extension_point_type:, title:)
42
+ query_name = "shop_script_update_or_create"
43
+ variables = {
44
+ extensionPointName: extension_point_type.upcase,
45
+ configuration: configuration,
46
+ title: title,
47
+ }
48
+
49
+ resp_hash = script_service_request(
50
+ query_name: query_name,
51
+ api_key: api_key,
52
+ shop_domain: shop_domain,
53
+ variables: variables,
54
+ )
55
+ user_errors = resp_hash["data"]["shopScriptUpdateOrCreate"]["userErrors"]
56
+
57
+ return resp_hash if user_errors.empty?
58
+
59
+ if user_errors.any? { |e| e['tag'] == 'app_script_not_found' }
60
+ raise Errors::AppScriptUndefinedError, api_key
61
+ elsif user_errors.any? { |e| e['tag'] == 'shop_script_conflict' }
62
+ raise Errors::ShopScriptConflictError
63
+ else
64
+ raise Errors::ScriptServiceUserError.new(query_name, user_errors.to_s)
65
+ end
66
+ end
67
+
68
+ def disable(api_key:, shop_domain:, extension_point_type:)
69
+ query_name = "shop_script_delete"
70
+ variables = {
71
+ extensionPointName: extension_point_type.upcase,
72
+ }
73
+
74
+ resp_hash = script_service_request(
75
+ query_name: query_name,
76
+ api_key: api_key,
77
+ shop_domain: shop_domain,
78
+ variables: variables,
79
+ )
80
+ user_errors = resp_hash["data"]["shopScriptDelete"]["userErrors"]
81
+ return resp_hash if user_errors.empty?
82
+
83
+ if user_errors.any? { |e| e['tag'] == 'shop_script_not_found' }
84
+ raise Errors::ShopScriptUndefinedError, api_key
85
+ else
86
+ raise Errors::ScriptServiceUserError.new(query_name, user_errors.to_s)
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ class ScriptServiceAPI < ShopifyCli::API
93
+ property(:api_key, accepts: String)
94
+ property(:shop_id, accepts: Integer)
95
+
96
+ def self.query(ctx, query_name, api_key: nil, shop_domain: nil, variables: {})
97
+ api_client(ctx, api_key, shop_domain).query(query_name, variables: variables)
98
+ end
99
+
100
+ def self.api_client(ctx, api_key, shop_domain)
101
+ new(
102
+ ctx: ctx,
103
+ url: 'https://script-service.myshopify.io/graphql',
104
+ token: '',
105
+ api_key: api_key,
106
+ shop_id: shop_domain&.to_i
107
+ )
108
+ end
109
+
110
+ def auth_headers(*)
111
+ tokens = { "APP_KEY" => api_key, "SHOP_ID" => shop_id }.compact.to_json
112
+ { "X-Shopify-Authenticated-Tokens" => tokens }
113
+ end
114
+ end
115
+ private_constant(:ScriptServiceAPI)
116
+
117
+ class PartnersProxyAPI < ShopifyCli::PartnersAPI
118
+ def query(query_name, variables: {})
119
+ variables[:query] = load_query(query_name)
120
+ super("script_service_proxy", variables: variables)
121
+ end
122
+ end
123
+ private_constant(:PartnersProxyAPI)
124
+
125
+ def script_service_request(query_name:, variables: nil, **options)
126
+ resp = if ENV["BYPASS_PARTNERS_PROXY"]
127
+ ScriptServiceAPI.query(ctx, query_name, variables: variables, **options)
128
+ else
129
+ proxy_through_partners(query_name: query_name, variables: variables, **options)
130
+ end
131
+ raise_if_graphql_failed(resp)
132
+ resp
133
+ end
134
+
135
+ def proxy_through_partners(query_name:, variables: nil, **options)
136
+ options[:variables] = variables.to_json if variables
137
+ resp = PartnersProxyAPI.query(ctx, query_name, **options)
138
+ raise_if_graphql_failed(resp)
139
+ JSON.parse(resp['data']['scriptServiceProxy'])
140
+ end
141
+
142
+ def raise_if_graphql_failed(response)
143
+ return unless response.key?('errors')
144
+ case error_code(response['errors'])
145
+ when 'forbidden'
146
+ raise Errors::ForbiddenError
147
+ when 'forbidden_on_shop'
148
+ raise Errors::ShopAuthenticationError
149
+ when 'app_not_installed_on_shop'
150
+ raise Errors::AppNotInstalledError
151
+ else
152
+ raise Errors::GraphqlError, response['errors'].map { |e| e['message'] }
153
+ end
154
+ end
155
+
156
+ def error_code(errors)
157
+ errors.map do |e|
158
+ code = e.dig('extensions', 'code')
159
+ return code if code
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end