@shopify/cli-kit 3.0.25 → 3.1.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 (289) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/assets/auth-error.html +2 -4
  3. package/assets/empty-url.html +2 -4
  4. package/assets/missing-code.html +2 -4
  5. package/assets/missing-state.html +2 -4
  6. package/assets/style.css +5 -8
  7. package/assets/success.html +1 -1
  8. package/dist/abort.d.ts +1 -0
  9. package/dist/abort.js +2 -0
  10. package/dist/abort.js.map +1 -0
  11. package/dist/analytics.d.ts +13 -0
  12. package/dist/analytics.js +111 -0
  13. package/dist/analytics.js.map +1 -0
  14. package/dist/api/admin.d.ts +3 -0
  15. package/dist/api/admin.js +80 -0
  16. package/dist/api/admin.js.map +1 -0
  17. package/dist/api/common.d.ts +11 -0
  18. package/dist/api/common.js +40 -0
  19. package/dist/api/common.js.map +1 -0
  20. package/dist/api/graphql/all_app_extension_registrations.d.ts +14 -0
  21. package/dist/api/graphql/all_app_extension_registrations.js +14 -0
  22. package/dist/api/graphql/all_app_extension_registrations.js.map +1 -0
  23. package/dist/api/graphql/all_orgs.d.ts +12 -0
  24. package/dist/api/graphql/all_orgs.js +14 -0
  25. package/dist/api/graphql/all_orgs.js.map +1 -0
  26. package/dist/api/graphql/all_stores_by_org.d.ts +18 -0
  27. package/dist/api/graphql/all_stores_by_org.js +21 -0
  28. package/dist/api/graphql/all_stores_by_org.js.map +1 -0
  29. package/dist/api/graphql/convert_dev_to_test_store.d.ts +16 -0
  30. package/dist/api/graphql/convert_dev_to_test_store.js +13 -0
  31. package/dist/api/graphql/convert_dev_to_test_store.js.map +1 -0
  32. package/dist/api/graphql/create_app.d.ts +28 -0
  33. package/dist/api/graphql/create_app.js +32 -0
  34. package/dist/api/graphql/create_app.js.map +1 -0
  35. package/dist/api/graphql/create_deployment.d.ts +33 -0
  36. package/dist/api/graphql/create_deployment.js +25 -0
  37. package/dist/api/graphql/create_deployment.js.map +1 -0
  38. package/dist/api/graphql/extension_create.d.ts +30 -0
  39. package/dist/api/graphql/extension_create.js +26 -0
  40. package/dist/api/graphql/extension_create.js.map +1 -0
  41. package/dist/api/graphql/extension_specifications.d.ts +18 -0
  42. package/dist/api/graphql/extension_specifications.js +18 -0
  43. package/dist/api/graphql/extension_specifications.js.map +1 -0
  44. package/dist/api/graphql/find_app.d.ts +13 -0
  45. package/dist/api/graphql/find_app.js +16 -0
  46. package/dist/api/graphql/find_app.js.map +1 -0
  47. package/dist/api/graphql/find_org.d.ts +23 -0
  48. package/dist/api/graphql/find_org.js +26 -0
  49. package/dist/api/graphql/find_org.js.map +1 -0
  50. package/dist/api/graphql/find_org_basic.d.ts +11 -0
  51. package/dist/api/graphql/find_org_basic.js +14 -0
  52. package/dist/api/graphql/find_org_basic.js.map +1 -0
  53. package/dist/api/graphql/find_store_by_domain.d.ts +21 -0
  54. package/dist/api/graphql/find_store_by_domain.js +24 -0
  55. package/dist/api/graphql/find_store_by_domain.js.map +1 -0
  56. package/dist/api/graphql/functions/app_function_set.d.ts +43 -0
  57. package/dist/api/graphql/functions/app_function_set.js +52 -0
  58. package/dist/api/graphql/functions/app_function_set.js.map +1 -0
  59. package/dist/api/graphql/functions/compile_module.d.ts +15 -0
  60. package/dist/api/graphql/functions/compile_module.js +13 -0
  61. package/dist/api/graphql/functions/compile_module.js.map +1 -0
  62. package/dist/api/graphql/functions/function_service_proxy.d.ts +4 -0
  63. package/dist/api/graphql/functions/function_service_proxy.js +7 -0
  64. package/dist/api/graphql/functions/function_service_proxy.js.map +1 -0
  65. package/dist/api/graphql/functions/get_app_functions.d.ts +1 -0
  66. package/dist/api/graphql/functions/get_app_functions.js +10 -0
  67. package/dist/api/graphql/functions/get_app_functions.js.map +1 -0
  68. package/dist/api/graphql/functions/module_compilation_status.d.ts +15 -0
  69. package/dist/api/graphql/functions/module_compilation_status.js +13 -0
  70. package/dist/api/graphql/functions/module_compilation_status.js.map +1 -0
  71. package/dist/api/graphql/functions/module_upload_url_generate.d.ts +18 -0
  72. package/dist/api/graphql/functions/module_upload_url_generate.js +17 -0
  73. package/dist/api/graphql/functions/module_upload_url_generate.js.map +1 -0
  74. package/dist/api/graphql/generate_signed_upload_url.d.ts +15 -0
  75. package/dist/api/graphql/generate_signed_upload_url.js +15 -0
  76. package/dist/api/graphql/generate_signed_upload_url.js.map +1 -0
  77. package/dist/api/graphql/get_variant_id.d.ts +17 -0
  78. package/dist/api/graphql/get_variant_id.js +20 -0
  79. package/dist/api/graphql/get_variant_id.js.map +1 -0
  80. package/dist/api/graphql/index.d.ts +22 -0
  81. package/dist/api/graphql/index.js +23 -0
  82. package/dist/api/graphql/index.js.map +1 -0
  83. package/dist/api/graphql/update_draft.d.ts +33 -0
  84. package/dist/api/graphql/update_draft.js +24 -0
  85. package/dist/api/graphql/update_draft.js.map +1 -0
  86. package/dist/api/graphql/update_urls.d.ts +14 -0
  87. package/dist/api/graphql/update_urls.js +12 -0
  88. package/dist/api/graphql/update_urls.js.map +1 -0
  89. package/dist/api/identity.d.ts +1 -0
  90. package/dist/api/identity.js +32 -0
  91. package/dist/api/identity.js.map +1 -0
  92. package/dist/api/partners.d.ts +25 -0
  93. package/dist/api/partners.js +100 -0
  94. package/dist/api/partners.js.map +1 -0
  95. package/dist/api.d.ts +5 -0
  96. package/dist/api.js +6 -0
  97. package/dist/api.js.map +1 -0
  98. package/dist/cli.d.ts +7 -0
  99. package/dist/cli.js +13 -0
  100. package/dist/cli.js.map +1 -0
  101. package/dist/constants.d.ts +43 -0
  102. package/dist/constants.js +63 -0
  103. package/dist/constants.js.map +1 -0
  104. package/dist/environment/fqdn.d.ts +23 -0
  105. package/dist/environment/fqdn.js +61 -0
  106. package/dist/environment/fqdn.js.map +1 -0
  107. package/dist/environment/local.d.ts +48 -0
  108. package/dist/environment/local.js +82 -0
  109. package/dist/environment/local.js.map +1 -0
  110. package/dist/environment/service.d.ts +17 -0
  111. package/dist/environment/service.js +41 -0
  112. package/dist/environment/service.js.map +1 -0
  113. package/dist/environment/spin.d.ts +47 -0
  114. package/dist/environment/spin.js +83 -0
  115. package/dist/environment/spin.js.map +1 -0
  116. package/dist/environment/utilities.d.ts +6 -0
  117. package/dist/environment/utilities.js +12 -0
  118. package/dist/environment/utilities.js.map +1 -0
  119. package/dist/environment.d.ts +5 -0
  120. package/dist/environment.js +6 -0
  121. package/dist/environment.js.map +1 -0
  122. package/dist/error.d.ts +44 -0
  123. package/dist/error.js +91 -0
  124. package/dist/error.js.map +1 -0
  125. package/dist/file.d.ts +67 -0
  126. package/dist/file.js +165 -0
  127. package/dist/file.js.map +1 -0
  128. package/dist/git.d.ts +15 -0
  129. package/dist/git.js +48 -0
  130. package/dist/git.js.map +1 -0
  131. package/dist/github.d.ts +33 -0
  132. package/dist/github.js +56 -0
  133. package/dist/github.js.map +1 -0
  134. package/dist/haiku.d.ts +1 -0
  135. package/dist/haiku.js +8 -0
  136. package/dist/haiku.js.map +1 -0
  137. package/dist/http/fetch.d.ts +16 -0
  138. package/dist/http/fetch.js +18 -0
  139. package/dist/http/fetch.js.map +1 -0
  140. package/dist/http/formdata.d.ts +3 -0
  141. package/dist/http/formdata.js +6 -0
  142. package/dist/http/formdata.js.map +1 -0
  143. package/dist/http.d.ts +2 -0
  144. package/dist/http.js +3 -0
  145. package/dist/http.js.map +1 -0
  146. package/dist/id.d.ts +6 -0
  147. package/dist/id.js +18 -0
  148. package/dist/id.js.map +1 -0
  149. package/dist/index.d.ts +33 -2179
  150. package/dist/index.js +34 -3264
  151. package/dist/index.js.map +1 -1
  152. package/dist/network/api.d.ts +2 -0
  153. package/dist/network/api.js +2 -0
  154. package/dist/network/api.js.map +1 -0
  155. package/dist/network/service.d.ts +16 -0
  156. package/dist/network/service.js +12 -0
  157. package/dist/network/service.js.map +1 -0
  158. package/dist/{archiver.d.ts → node/archiver.d.ts} +1 -4
  159. package/dist/node/archiver.js +22 -42
  160. package/dist/node/archiver.js.map +1 -1
  161. package/dist/node/checksum.d.ts +20 -0
  162. package/dist/node/checksum.js +32 -0
  163. package/dist/node/checksum.js.map +1 -0
  164. package/dist/node/cli.d.ts +18 -0
  165. package/dist/node/cli.js +96 -0
  166. package/dist/node/cli.js.map +1 -0
  167. package/dist/node/colors.d.ts +1 -0
  168. package/dist/node/colors.js +8 -0
  169. package/dist/node/colors.js.map +1 -0
  170. package/dist/node/dot-env.d.ts +33 -0
  171. package/dist/node/dot-env.js +36 -0
  172. package/dist/node/dot-env.js.map +1 -0
  173. package/dist/node/node-package-manager.d.ts +197 -0
  174. package/dist/node/node-package-manager.js +309 -0
  175. package/dist/node/node-package-manager.js.map +1 -0
  176. package/dist/node/ruby.d.ts +30 -0
  177. package/dist/node/ruby.js +197 -0
  178. package/dist/node/ruby.js.map +1 -0
  179. package/dist/npm.d.ts +27 -0
  180. package/dist/npm.js +20 -0
  181. package/dist/npm.js.map +1 -0
  182. package/dist/os.d.ts +10 -0
  183. package/dist/os.js +70 -0
  184. package/dist/os.js.map +1 -0
  185. package/dist/output.d.ts +149 -0
  186. package/dist/output.js +515 -0
  187. package/dist/output.js.map +1 -0
  188. package/dist/path.d.ts +22 -0
  189. package/dist/path.js +43 -0
  190. package/dist/path.js.map +1 -0
  191. package/dist/plugins.d.ts +9 -0
  192. package/dist/plugins.js +12 -0
  193. package/dist/plugins.js.map +1 -0
  194. package/dist/port.d.ts +5 -0
  195. package/dist/port.js +35 -0
  196. package/dist/port.js.map +1 -0
  197. package/dist/schema.d.ts +1 -0
  198. package/dist/schema.js +2 -0
  199. package/dist/schema.js.map +1 -0
  200. package/dist/secure-store.d.ts +19 -0
  201. package/dist/secure-store.js +63 -0
  202. package/dist/secure-store.js.map +1 -0
  203. package/dist/semver.d.ts +3 -0
  204. package/dist/semver.js +6 -0
  205. package/dist/semver.js.map +1 -0
  206. package/dist/session/authorize.d.ts +7 -0
  207. package/dist/session/authorize.js +40 -0
  208. package/dist/session/authorize.js.map +1 -0
  209. package/dist/session/exchange.d.ts +42 -0
  210. package/dist/session/exchange.js +144 -0
  211. package/dist/session/exchange.js.map +1 -0
  212. package/dist/session/identity.d.ts +3 -0
  213. package/dist/session/identity.js +58 -0
  214. package/dist/session/identity.js.map +1 -0
  215. package/dist/session/post-auth.d.ts +13 -0
  216. package/dist/session/post-auth.js +56 -0
  217. package/dist/session/post-auth.js.map +1 -0
  218. package/dist/session/redirect-listener.d.ts +34 -0
  219. package/dist/session/redirect-listener.js +97 -0
  220. package/dist/session/redirect-listener.js.map +1 -0
  221. package/dist/session/schema.d.ts +174 -0
  222. package/dist/session/schema.js +59 -0
  223. package/dist/session/schema.js.map +1 -0
  224. package/dist/session/scopes.d.ts +16 -0
  225. package/dist/session/scopes.js +53 -0
  226. package/dist/session/scopes.js.map +1 -0
  227. package/dist/session/store.d.ts +24 -0
  228. package/dist/session/store.js +88 -0
  229. package/dist/session/store.js.map +1 -0
  230. package/dist/session/token.d.ts +40 -0
  231. package/dist/session/token.js +22 -0
  232. package/dist/session/token.js.map +1 -0
  233. package/dist/session/validate.d.ts +17 -0
  234. package/dist/session/validate.js +75 -0
  235. package/dist/session/validate.js.map +1 -0
  236. package/dist/session.d.ts +88 -0
  237. package/dist/session.js +251 -0
  238. package/dist/session.js.map +1 -0
  239. package/dist/store/schema.d.ts +3 -0
  240. package/dist/store/schema.js +27 -0
  241. package/dist/store/schema.js.map +1 -0
  242. package/dist/store.d.ts +32 -0
  243. package/dist/store.js +102 -0
  244. package/dist/store.js.map +1 -0
  245. package/dist/string.d.ts +22 -0
  246. package/dist/string.js +38 -0
  247. package/dist/string.js.map +1 -0
  248. package/dist/system.d.ts +53 -0
  249. package/dist/system.js +109 -0
  250. package/dist/system.js.map +1 -0
  251. package/dist/template.d.ts +11 -0
  252. package/dist/template.js +50 -0
  253. package/dist/template.js.map +1 -0
  254. package/dist/testing/output.d.ts +9 -0
  255. package/dist/testing/output.js +15 -0
  256. package/dist/testing/output.js.map +1 -0
  257. package/dist/testing/store.d.ts +7 -0
  258. package/dist/testing/store.js +26 -0
  259. package/dist/testing/store.js.map +1 -0
  260. package/dist/toml.d.ts +3 -0
  261. package/dist/toml.js +8 -0
  262. package/dist/toml.js.map +1 -0
  263. package/dist/tsconfig.tsbuildinfo +1 -0
  264. package/dist/ui/autocomplete.d.ts +7 -0
  265. package/dist/ui/autocomplete.js +43 -0
  266. package/dist/ui/autocomplete.js.map +1 -0
  267. package/dist/ui/input.d.ts +7 -0
  268. package/dist/ui/input.js +48 -0
  269. package/dist/ui/input.js.map +1 -0
  270. package/dist/ui/select.d.ts +6 -0
  271. package/dist/ui/select.js +30 -0
  272. package/dist/ui/select.js.map +1 -0
  273. package/dist/ui.d.ts +36 -0
  274. package/dist/ui.js +124 -0
  275. package/dist/ui.js.map +1 -0
  276. package/dist/version.d.ts +19 -0
  277. package/dist/version.js +34 -0
  278. package/dist/version.js.map +1 -0
  279. package/dist/vscode.d.ts +8 -0
  280. package/dist/vscode.js +36 -0
  281. package/dist/vscode.js.map +1 -0
  282. package/dist/yaml.d.ts +2 -0
  283. package/dist/yaml.js +8 -0
  284. package/dist/yaml.js.map +1 -0
  285. package/package.json +19 -8
  286. package/dist/archiver.d.ts.map +0 -1
  287. package/dist/index.d.ts.map +0 -1
  288. package/dist/local-d0094ffe.js +0 -1344
  289. package/dist/local-d0094ffe.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * It represents the result of a redirect.
3
+ */
4
+ declare type RedirectCallback = (error: Error | undefined, state: string | undefined, code: string | undefined) => void;
5
+ /**
6
+ * Defines the interface of the options that
7
+ * are used to instantiate a redirect listener.
8
+ */
9
+ interface RedirectListenerOptions {
10
+ host: string;
11
+ port: number;
12
+ callback: RedirectCallback;
13
+ }
14
+ /**
15
+ * When the authentication completes, Identity redirects
16
+ * the user to a URL. In the case of the CLI, the redirect
17
+ * is to localhost passing some parameters that are necessary
18
+ * to continue the authentication. Because of that, we need
19
+ * an HTTP server that runs and listens to the request.
20
+ */
21
+ export declare class RedirectListener {
22
+ private static createServer;
23
+ port: number;
24
+ host: string;
25
+ server: ReturnType<typeof RedirectListener.createServer>;
26
+ constructor(options: RedirectListenerOptions);
27
+ start(): void;
28
+ stop(): Promise<void>;
29
+ }
30
+ export declare function listenRedirect(host: string, port: number, url: string): Promise<{
31
+ code: string;
32
+ state: string;
33
+ }>;
34
+ export {};
@@ -0,0 +1,97 @@
1
+ import { getFavicon, getStylesheet, getEmptyUrlHTML, getAuthErrorHTML, getMissingCodeHTML, getMissingStateHTML, getSuccessHTML, EmptyUrlString, MissingCodeString, MissingStateString, } from './post-auth.js';
2
+ import { Abort, Bug } from '../error.js';
3
+ import { content, info, token } from '../output.js';
4
+ import Fastify from 'fastify';
5
+ import url from 'url';
6
+ const ResponseTimeoutSeconds = 10;
7
+ const ServerStopDelaySeconds = 0.5;
8
+ /**
9
+ * When the authentication completes, Identity redirects
10
+ * the user to a URL. In the case of the CLI, the redirect
11
+ * is to localhost passing some parameters that are necessary
12
+ * to continue the authentication. Because of that, we need
13
+ * an HTTP server that runs and listens to the request.
14
+ */
15
+ export class RedirectListener {
16
+ constructor(options) {
17
+ this.port = options.port;
18
+ this.host = options.host;
19
+ this.server = RedirectListener.createServer(options.callback);
20
+ }
21
+ static createServer(callback) {
22
+ const server = Fastify().get('*', async (request, reply) => {
23
+ const requestUrl = request.url;
24
+ if (requestUrl === '/favicon.svg') {
25
+ const faviconFile = await getFavicon();
26
+ reply.header('Content-Type', 'image/svg+xml').send(faviconFile);
27
+ return {};
28
+ }
29
+ else if (requestUrl === '/style.css') {
30
+ const stylesheetFile = await getStylesheet();
31
+ reply.header('Content-Type', 'text/css').send(stylesheetFile);
32
+ return {};
33
+ }
34
+ const respond = (contents, error, state, code) => {
35
+ reply.header('Content-Type', 'text/html').send(contents);
36
+ callback(error, state, code);
37
+ return {};
38
+ };
39
+ // If there was an empty/malformed URL sent back.
40
+ if (!requestUrl) {
41
+ const file = await getEmptyUrlHTML();
42
+ const err = new Bug(EmptyUrlString);
43
+ return respond(file, err, undefined, undefined);
44
+ }
45
+ // If an error was returned by the Identity server.
46
+ const queryObject = url.parse(requestUrl, true).query;
47
+ if (queryObject.error && queryObject.error_description) {
48
+ const file = await getAuthErrorHTML();
49
+ const err = new Abort(`${queryObject.error_description}`);
50
+ return respond(file, err, undefined, undefined);
51
+ }
52
+ // If the code isn't present in the URL.
53
+ if (!queryObject.code) {
54
+ const file = await getMissingCodeHTML();
55
+ const err = new Bug(MissingCodeString);
56
+ return respond(file, err, undefined, undefined);
57
+ }
58
+ // If the state isn't present in the URL.
59
+ if (!queryObject.state) {
60
+ const file = await getMissingStateHTML();
61
+ const err = new Bug(MissingStateString);
62
+ return respond(file, err, undefined, undefined);
63
+ }
64
+ const file = await getSuccessHTML();
65
+ return respond(file, undefined, `${queryObject.code}`, `${queryObject.state}`);
66
+ });
67
+ return server;
68
+ }
69
+ start() {
70
+ this.server.listen({ port: this.port, host: this.host }, () => { });
71
+ }
72
+ async stop() {
73
+ await this.server.close();
74
+ }
75
+ }
76
+ export async function listenRedirect(host, port, url) {
77
+ const result = await new Promise((resolve, reject) => {
78
+ const timeout = setTimeout(() => {
79
+ const message = '\nAuto-open timed out. Open the login page: ';
80
+ info(content `${message}${token.link('Log in to Shopify Partners', url)}\n`);
81
+ }, ResponseTimeoutSeconds * 1000);
82
+ const callback = async (error, code, state) => {
83
+ clearTimeout(timeout);
84
+ setTimeout(() => {
85
+ redirectListener.stop();
86
+ if (error)
87
+ reject(error);
88
+ else
89
+ resolve({ code: code, state: state });
90
+ }, ServerStopDelaySeconds * 1000);
91
+ };
92
+ const redirectListener = new RedirectListener({ host, port, callback });
93
+ redirectListener.start();
94
+ });
95
+ return result;
96
+ }
97
+ //# sourceMappingURL=redirect-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect-listener.js","sourceRoot":"","sources":["../../src/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 {Abort, Bug} from '../error.js'\nimport {content, info, token} from '../output.js'\nimport Fastify from 'fastify'\nimport url from 'url'\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) {\n const server = Fastify().get('*', async (request, reply) => {\n const requestUrl = request.url\n if (requestUrl === '/favicon.svg') {\n const faviconFile = await getFavicon()\n reply.header('Content-Type', 'image/svg+xml').send(faviconFile)\n return {}\n } else if (requestUrl === '/style.css') {\n const stylesheetFile = await getStylesheet()\n reply.header('Content-Type', 'text/css').send(stylesheetFile)\n return {}\n }\n\n const respond = (contents: string, error?: Error, state?: string, code?: string) => {\n reply.header('Content-Type', 'text/html').send(contents)\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 Bug(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 Abort(`${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 Bug(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 Bug(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 return server\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 info(content`${message}${token.link('Log in to Shopify Partners', url)}\\n`)\n }, ResponseTimeoutSeconds * 1000)\n\n const callback: RedirectCallback = async (error, code, state) => {\n clearTimeout(timeout)\n setTimeout(() => {\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"]}
@@ -0,0 +1,174 @@
1
+ import { define } from '../schema.js';
2
+ /**
3
+ * The schema represents an Identity token.
4
+ */
5
+ declare const IdentityTokenSchema: define.ZodObject<{
6
+ accessToken: define.ZodString;
7
+ refreshToken: define.ZodString;
8
+ expiresAt: define.ZodEffects<define.ZodDate, Date, Date>;
9
+ scopes: define.ZodArray<define.ZodString, "many">;
10
+ }, "strip", define.ZodTypeAny, {
11
+ accessToken: string;
12
+ refreshToken: string;
13
+ expiresAt: Date;
14
+ scopes: string[];
15
+ }, {
16
+ accessToken: string;
17
+ refreshToken: string;
18
+ expiresAt: Date;
19
+ scopes: string[];
20
+ }>;
21
+ /**
22
+ * The schema represents an application token.
23
+ */
24
+ declare const ApplicationTokenSchema: define.ZodObject<{
25
+ accessToken: define.ZodString;
26
+ expiresAt: define.ZodEffects<define.ZodDate, Date, Date>;
27
+ scopes: define.ZodArray<define.ZodString, "many">;
28
+ }, "strip", define.ZodTypeAny, {
29
+ accessToken: string;
30
+ expiresAt: Date;
31
+ scopes: string[];
32
+ }, {
33
+ accessToken: string;
34
+ expiresAt: Date;
35
+ scopes: string[];
36
+ }>;
37
+ /**
38
+ * This schema represents the format of the session
39
+ * that we cache in the system to avoid unnecessary
40
+ * token exchanges.
41
+ *
42
+ * @example
43
+ * {
44
+ * "accounts.shopify.com": {
45
+ * "identity": {...} // IdentityTokenSchema
46
+ * "applications": {
47
+ * "${domain}-application-id": { // Admin APIs includes domain in the key
48
+ * "accessToken": "...",
49
+ * },
50
+ * "$application-id": { // ApplicationTokenSchema
51
+ * "accessToken": "...",
52
+ * },
53
+ * }
54
+ * },
55
+ * "identity.spin.com": {...}
56
+ *}
57
+ *
58
+ */
59
+ export declare const SessionSchema: define.ZodObject<{}, "strip", define.ZodObject<{
60
+ /**
61
+ * It contains the identity token. Before usint it, we exchange it
62
+ * to get a token that we can use with different applications. The exchanged
63
+ * tokens for the applications are stored under applications.
64
+ */
65
+ identity: define.ZodObject<{
66
+ accessToken: define.ZodString;
67
+ refreshToken: define.ZodString;
68
+ expiresAt: define.ZodEffects<define.ZodDate, Date, Date>;
69
+ scopes: define.ZodArray<define.ZodString, "many">;
70
+ }, "strip", define.ZodTypeAny, {
71
+ accessToken: string;
72
+ refreshToken: string;
73
+ expiresAt: Date;
74
+ scopes: string[];
75
+ }, {
76
+ accessToken: string;
77
+ refreshToken: string;
78
+ expiresAt: Date;
79
+ scopes: string[];
80
+ }>;
81
+ /**
82
+ * It contains exchanged tokens for the applications the CLI
83
+ * authenticates with. Tokens are scoped under the fqdn of the applications.
84
+ */
85
+ applications: define.ZodObject<{}, "strip", define.ZodObject<{
86
+ accessToken: define.ZodString;
87
+ expiresAt: define.ZodEffects<define.ZodDate, Date, Date>;
88
+ scopes: define.ZodArray<define.ZodString, "many">;
89
+ }, "strip", define.ZodTypeAny, {
90
+ accessToken: string;
91
+ expiresAt: Date;
92
+ scopes: string[];
93
+ }, {
94
+ accessToken: string;
95
+ expiresAt: Date;
96
+ scopes: string[];
97
+ }>, {
98
+ [x: string]: {
99
+ accessToken: string;
100
+ expiresAt: Date;
101
+ scopes: string[];
102
+ };
103
+ }, {
104
+ [x: string]: {
105
+ accessToken: string;
106
+ expiresAt: Date;
107
+ scopes: string[];
108
+ };
109
+ }>;
110
+ }, "strip", define.ZodTypeAny, {
111
+ identity: {
112
+ accessToken: string;
113
+ refreshToken: string;
114
+ expiresAt: Date;
115
+ scopes: string[];
116
+ };
117
+ applications: {
118
+ [x: string]: {
119
+ accessToken: string;
120
+ expiresAt: Date;
121
+ scopes: string[];
122
+ };
123
+ };
124
+ }, {
125
+ identity: {
126
+ accessToken: string;
127
+ refreshToken: string;
128
+ expiresAt: Date;
129
+ scopes: string[];
130
+ };
131
+ applications: {
132
+ [x: string]: {
133
+ accessToken: string;
134
+ expiresAt: Date;
135
+ scopes: string[];
136
+ };
137
+ };
138
+ }>, {
139
+ [x: string]: {
140
+ identity: {
141
+ accessToken: string;
142
+ refreshToken: string;
143
+ expiresAt: Date;
144
+ scopes: string[];
145
+ };
146
+ applications: {
147
+ [x: string]: {
148
+ accessToken: string;
149
+ expiresAt: Date;
150
+ scopes: string[];
151
+ };
152
+ };
153
+ };
154
+ }, {
155
+ [x: string]: {
156
+ identity: {
157
+ accessToken: string;
158
+ refreshToken: string;
159
+ expiresAt: Date;
160
+ scopes: string[];
161
+ };
162
+ applications: {
163
+ [x: string]: {
164
+ accessToken: string;
165
+ expiresAt: Date;
166
+ scopes: string[];
167
+ };
168
+ };
169
+ };
170
+ }>;
171
+ export declare type Session = define.infer<typeof SessionSchema>;
172
+ export declare type IdentityToken = define.infer<typeof IdentityTokenSchema>;
173
+ export declare type ApplicationToken = define.infer<typeof ApplicationTokenSchema>;
174
+ export {};
@@ -0,0 +1,59 @@
1
+ import { define } from '../schema.js';
2
+ const DateSchema = define.preprocess((arg) => {
3
+ if (typeof arg === 'string' || arg instanceof Date)
4
+ return new Date(arg);
5
+ return null;
6
+ }, define.date());
7
+ /**
8
+ * The schema represents an Identity token.
9
+ */
10
+ const IdentityTokenSchema = define.object({
11
+ accessToken: define.string(),
12
+ refreshToken: define.string(),
13
+ expiresAt: DateSchema,
14
+ scopes: define.array(define.string()),
15
+ });
16
+ /**
17
+ * The schema represents an application token.
18
+ */
19
+ const ApplicationTokenSchema = define.object({
20
+ accessToken: define.string(),
21
+ expiresAt: DateSchema,
22
+ scopes: define.array(define.string()),
23
+ });
24
+ /**
25
+ * This schema represents the format of the session
26
+ * that we cache in the system to avoid unnecessary
27
+ * token exchanges.
28
+ *
29
+ * @example
30
+ * {
31
+ * "accounts.shopify.com": {
32
+ * "identity": {...} // IdentityTokenSchema
33
+ * "applications": {
34
+ * "${domain}-application-id": { // Admin APIs includes domain in the key
35
+ * "accessToken": "...",
36
+ * },
37
+ * "$application-id": { // ApplicationTokenSchema
38
+ * "accessToken": "...",
39
+ * },
40
+ * }
41
+ * },
42
+ * "identity.spin.com": {...}
43
+ *}
44
+ *
45
+ */
46
+ export const SessionSchema = define.object({}).catchall(define.object({
47
+ /**
48
+ * It contains the identity token. Before usint it, we exchange it
49
+ * to get a token that we can use with different applications. The exchanged
50
+ * tokens for the applications are stored under applications.
51
+ */
52
+ identity: IdentityTokenSchema,
53
+ /**
54
+ * It contains exchanged tokens for the applications the CLI
55
+ * authenticates with. Tokens are scoped under the fqdn of the applications.
56
+ */
57
+ applications: define.object({}).catchall(ApplicationTokenSchema),
58
+ }));
59
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/session/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAA;AAEnC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;IAC3C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,YAAY,IAAI;QAAE,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;IACxE,OAAO,IAAI,CAAA;AACb,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;AAEjB;;GAEG;AACH,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;IAC5B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAC7B,SAAS,EAAE,UAAU;IACrB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;CACtC,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;IAC5B,SAAS,EAAE,UAAU;IACrB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;CACtC,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CACrD,MAAM,CAAC,MAAM,CAAC;IACZ;;;;OAIG;IACH,QAAQ,EAAE,mBAAmB;IAC7B;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;CACjE,CAAC,CACH,CAAA","sourcesContent":["import {define} from '../schema.js'\n\nconst DateSchema = define.preprocess((arg) => {\n if (typeof arg === 'string' || arg instanceof Date) return new Date(arg)\n return null\n}, define.date())\n\n/**\n * The schema represents an Identity token.\n */\nconst IdentityTokenSchema = define.object({\n accessToken: define.string(),\n refreshToken: define.string(),\n expiresAt: DateSchema,\n scopes: define.array(define.string()),\n})\n\n/**\n * The schema represents an application token.\n */\nconst ApplicationTokenSchema = define.object({\n accessToken: define.string(),\n expiresAt: DateSchema,\n scopes: define.array(define.string()),\n})\n\n/**\n * This schema represents the format of the session\n * that we cache in the system to avoid unnecessary\n * token exchanges.\n *\n * @example\n * {\n * \"accounts.shopify.com\": {\n * \"identity\": {...} // IdentityTokenSchema\n * \"applications\": {\n * \"${domain}-application-id\": { // Admin APIs includes domain in the key\n * \"accessToken\": \"...\",\n * },\n * \"$application-id\": { // ApplicationTokenSchema\n * \"accessToken\": \"...\",\n * },\n * }\n * },\n * \"identity.spin.com\": {...}\n *}\n *\n */\nexport const SessionSchema = define.object({}).catchall(\n define.object({\n /**\n * It contains the identity token. Before usint it, we exchange it\n * to get a token that we can use with different applications. The exchanged\n * tokens for the applications are stored under applications.\n */\n identity: IdentityTokenSchema,\n /**\n * It contains exchanged tokens for the applications the CLI\n * authenticates with. Tokens are scoped under the fqdn of the applications.\n */\n applications: define.object({}).catchall(ApplicationTokenSchema),\n }),\n)\n\nexport type Session = define.infer<typeof SessionSchema>\nexport type IdentityToken = define.infer<typeof IdentityTokenSchema>\nexport type ApplicationToken = define.infer<typeof ApplicationTokenSchema>\n"]}
@@ -0,0 +1,16 @@
1
+ import { API } from '../network/api.js';
2
+ /**
3
+ * Generate a flat array with all the default scopes for all the APIs plus
4
+ * any custom scope defined by the user.
5
+ * @param extraScopes custom user-defined scopes
6
+ * @returns Array of scopes
7
+ */
8
+ export declare function allDefaultScopes(extraScopes?: string[]): string[];
9
+ /**
10
+ * Generate a flat array with the default scopes for the given API plus
11
+ * any custom scope defined by the user
12
+ * @param api API to get the scopes for
13
+ * @param extraScopes custom user-defined scopes
14
+ * @returns Array of scopes
15
+ */
16
+ export declare function apiScopes(api: API, extraScopes?: string[]): string[];
@@ -0,0 +1,53 @@
1
+ import { Bug } from '../error.js';
2
+ import { allAPIs } from '../network/api.js';
3
+ /**
4
+ * Generate a flat array with all the default scopes for all the APIs plus
5
+ * any custom scope defined by the user.
6
+ * @param extraScopes custom user-defined scopes
7
+ * @returns Array of scopes
8
+ */
9
+ export function allDefaultScopes(extraScopes = []) {
10
+ let scopes = allAPIs.map(defaultApiScopes).flat();
11
+ scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform);
12
+ return Array.from(new Set(scopes));
13
+ }
14
+ /**
15
+ * Generate a flat array with the default scopes for the given API plus
16
+ * any custom scope defined by the user
17
+ * @param api API to get the scopes for
18
+ * @param extraScopes custom user-defined scopes
19
+ * @returns Array of scopes
20
+ */
21
+ export function apiScopes(api, extraScopes = []) {
22
+ const scopes = ['openid', ...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform);
23
+ return Array.from(new Set(scopes));
24
+ }
25
+ function defaultApiScopes(api) {
26
+ switch (api) {
27
+ case 'admin':
28
+ return ['graphql', 'themes', 'collaborator'];
29
+ case 'storefront-renderer':
30
+ return ['devtools'];
31
+ case 'partners':
32
+ return ['cli'];
33
+ default:
34
+ throw new Bug(`Unknown API: ${api}`);
35
+ }
36
+ }
37
+ function scopeTransform(scope) {
38
+ switch (scope) {
39
+ case 'graphql':
40
+ return 'https://api.shopify.com/auth/shop.admin.graphql';
41
+ case 'themes':
42
+ return 'https://api.shopify.com/auth/shop.admin.themes';
43
+ case 'collaborator':
44
+ return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly';
45
+ case 'cli':
46
+ return 'https://api.shopify.com/auth/partners.app.cli.access';
47
+ case 'devtools':
48
+ return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools';
49
+ default:
50
+ return scope;
51
+ }
52
+ }
53
+ //# sourceMappingURL=scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../src/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAC/B,OAAO,EAAC,OAAO,EAAM,MAAM,mBAAmB,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwB,EAAE;IACzD,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,CAAA;IACjD,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,cAAwB,EAAE;IAC5D,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAC3G,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ;IAChC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO;YACV,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QAC9C,KAAK,qBAAqB;YACxB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,KAAK,UAAU;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB;YACE,MAAM,IAAI,GAAG,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;KACvC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,QAAQ,KAAK,EAAE;QACb,KAAK,SAAS;YACZ,OAAO,iDAAiD,CAAA;QAC1D,KAAK,QAAQ;YACX,OAAO,gDAAgD,CAAA;QACzD,KAAK,cAAc;YACjB,OAAO,2EAA2E,CAAA;QACpF,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAA;QAC/D,KAAK,UAAU;YACb,OAAO,gEAAgE,CAAA;QACzE;YACE,OAAO,KAAK,CAAA;KACf;AACH,CAAC","sourcesContent":["import {Bug} from '../error.js'\nimport {allAPIs, API} from '../network/api.js'\n\n/**\n * Generate a flat array with all the default scopes for all the APIs plus\n * any custom scope defined by the user.\n * @param extraScopes custom user-defined scopes\n * @returns Array of scopes\n */\nexport function allDefaultScopes(extraScopes: string[] = []): string[] {\n let scopes = allAPIs.map(defaultApiScopes).flat()\n scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\n/**\n * Generate a flat array with the default scopes for the given API plus\n * any custom scope defined by the user\n * @param api API to get the scopes for\n * @param extraScopes custom user-defined scopes\n * @returns Array of scopes\n */\nexport function apiScopes(api: API, extraScopes: string[] = []): string[] {\n const scopes = ['openid', ...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\nfunction defaultApiScopes(api: API): string[] {\n switch (api) {\n case 'admin':\n return ['graphql', 'themes', 'collaborator']\n case 'storefront-renderer':\n return ['devtools']\n case 'partners':\n return ['cli']\n default:\n throw new Bug(`Unknown API: ${api}`)\n }\n}\n\nfunction scopeTransform(scope: string): string {\n switch (scope) {\n case 'graphql':\n return 'https://api.shopify.com/auth/shop.admin.graphql'\n case 'themes':\n return 'https://api.shopify.com/auth/shop.admin.themes'\n case 'collaborator':\n return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly'\n case 'cli':\n return 'https://api.shopify.com/auth/partners.app.cli.access'\n case 'devtools':\n return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools'\n default:\n return scope\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type { Session } from './schema.js';
2
+ /**
3
+ * The identifier of the session in the secure store.
4
+ */
5
+ export declare const identifier = "session";
6
+ /**
7
+ * Serializes the session as a JSON and stores it securely in the system.
8
+ * If the secure store is not available, the session is stored in the local config.
9
+ * @param session {Session} the session to store.
10
+ */
11
+ export declare function store(session: Session): Promise<void>;
12
+ /**
13
+ * Fetches the session from the secure store and returns it.
14
+ * If the secure store is not available, the session is fetched from the local config.
15
+ * If the format of the session is invalid, the method will discard it.
16
+ * In the future might add some logic for supporting migrating the schema
17
+ * of already-persisted sessions.
18
+ * @returns {Promise<Session\undefined>} Returns a promise that resolves with the session if it exists and is valid.
19
+ */
20
+ export declare function fetch(): Promise<Session | undefined>;
21
+ /**
22
+ * Removes a session from the system.
23
+ */
24
+ export declare function remove(): Promise<void>;
@@ -0,0 +1,88 @@
1
+ import { SessionSchema } from './schema.js';
2
+ import constants from '../constants.js';
3
+ import { platformAndArch } from '../os.js';
4
+ import { store as secureStore, fetch as secureFetch, remove as secureRemove } from '../secure-store.js';
5
+ import { cliKitStore } from '../store.js';
6
+ import { content, debug } from '../output.js';
7
+ /**
8
+ * The identifier of the session in the secure store.
9
+ */
10
+ export const identifier = 'session';
11
+ /**
12
+ * Serializes the session as a JSON and stores it securely in the system.
13
+ * If the secure store is not available, the session is stored in the local config.
14
+ * @param session {Session} the session to store.
15
+ */
16
+ export async function store(session) {
17
+ const jsonSession = JSON.stringify(session);
18
+ if (await secureStoreAvailable()) {
19
+ await secureStore(identifier, jsonSession);
20
+ }
21
+ else {
22
+ await cliKitStore().setSession(jsonSession);
23
+ }
24
+ }
25
+ /**
26
+ * Fetches the session from the secure store and returns it.
27
+ * If the secure store is not available, the session is fetched from the local config.
28
+ * If the format of the session is invalid, the method will discard it.
29
+ * In the future might add some logic for supporting migrating the schema
30
+ * of already-persisted sessions.
31
+ * @returns {Promise<Session\undefined>} Returns a promise that resolves with the session if it exists and is valid.
32
+ */
33
+ export async function fetch() {
34
+ let content;
35
+ if (await secureStoreAvailable()) {
36
+ content = await secureFetch(identifier);
37
+ }
38
+ else {
39
+ content = cliKitStore().getSession();
40
+ }
41
+ if (!content) {
42
+ return undefined;
43
+ }
44
+ const contentJson = JSON.parse(content);
45
+ const parsedSession = await SessionSchema.safeParseAsync(contentJson);
46
+ if (parsedSession.success) {
47
+ return parsedSession.data;
48
+ }
49
+ else {
50
+ await remove();
51
+ return undefined;
52
+ }
53
+ }
54
+ /**
55
+ * Removes a session from the system.
56
+ */
57
+ export async function remove() {
58
+ if (await secureStoreAvailable()) {
59
+ await secureRemove(identifier);
60
+ }
61
+ else {
62
+ cliKitStore().removeSession();
63
+ }
64
+ }
65
+ /**
66
+ * Returns true if the secure store is available on the system.
67
+ * Keytar it's not supported on some Linux environments or Windows.
68
+ * More details: https://github.com/Shopify/shopify-cli-planning/issues/261
69
+ * @returns a boolean indicating if the secure store is available.
70
+ */
71
+ async function secureStoreAvailable() {
72
+ try {
73
+ if (platformAndArch().platform === 'windows') {
74
+ debug(content `Secure store not supported on Windows`);
75
+ return false;
76
+ }
77
+ const keytar = await import('keytar');
78
+ await keytar.default.findCredentials(constants.keychain.service);
79
+ debug(content `Secure store is available`);
80
+ return true;
81
+ // eslint-disable-next-line no-catch-all/no-catch-all
82
+ }
83
+ catch (_error) {
84
+ debug(content `Failed to load secure store`);
85
+ return false;
86
+ }
87
+ }
88
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,SAAS,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAC,eAAe,EAAC,MAAM,UAAU,CAAA;AACxC,OAAO,EAAC,KAAK,IAAI,WAAW,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,IAAI,YAAY,EAAC,MAAM,oBAAoB,CAAA;AACrG,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,MAAM,cAAc,CAAA;AAG3C;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAA;AAEnC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAgB;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3C,IAAI,MAAM,oBAAoB,EAAE,EAAE;QAChC,MAAM,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;KAC3C;SAAM;QACL,MAAM,WAAW,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;KAC5C;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,IAAI,OAAO,CAAA;IACX,IAAI,MAAM,oBAAoB,EAAE,EAAE;QAChC,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAA;KACxC;SAAM;QACL,OAAO,GAAG,WAAW,EAAE,CAAC,UAAU,EAAE,CAAA;KACrC;IAED,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,SAAS,CAAA;KACjB;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IACrE,IAAI,aAAa,CAAC,OAAO,EAAE;QACzB,OAAO,aAAa,CAAC,IAAI,CAAA;KAC1B;SAAM;QACL,MAAM,MAAM,EAAE,CAAA;QACd,OAAO,SAAS,CAAA;KACjB;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,IAAI,MAAM,oBAAoB,EAAE,EAAE;QAChC,MAAM,YAAY,CAAC,UAAU,CAAC,CAAA;KAC/B;SAAM;QACL,WAAW,EAAE,CAAC,aAAa,EAAE,CAAA;KAC9B;AACH,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,oBAAoB;IACjC,IAAI;QACF,IAAI,eAAe,EAAE,CAAC,QAAQ,KAAK,SAAS,EAAE;YAC5C,KAAK,CAAC,OAAO,CAAA,uCAAuC,CAAC,CAAA;YACrD,OAAO,KAAK,CAAA;SACb;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAChE,KAAK,CAAC,OAAO,CAAA,2BAA2B,CAAC,CAAA;QACzC,OAAO,IAAI,CAAA;QACX,qDAAqD;KACtD;IAAC,OAAO,MAAM,EAAE;QACf,KAAK,CAAC,OAAO,CAAA,6BAA6B,CAAC,CAAA;QAC3C,OAAO,KAAK,CAAA;KACb;AACH,CAAC","sourcesContent":["import {SessionSchema} from './schema.js'\nimport constants from '../constants.js'\nimport {platformAndArch} from '../os.js'\nimport {store as secureStore, fetch as secureFetch, remove as secureRemove} from '../secure-store.js'\nimport {cliKitStore} from '../store.js'\nimport {content, debug} from '../output.js'\nimport type {Session} from './schema.js'\n\n/**\n * The identifier of the session in the secure store.\n */\nexport const identifier = 'session'\n\n/**\n * Serializes the session as a JSON and stores it securely in the system.\n * If the secure store is not available, the session is stored in the local config.\n * @param session {Session} the session to store.\n */\nexport async function store(session: Session) {\n const jsonSession = JSON.stringify(session)\n if (await secureStoreAvailable()) {\n await secureStore(identifier, jsonSession)\n } else {\n await cliKitStore().setSession(jsonSession)\n }\n}\n\n/**\n * Fetches the session from the secure store and returns it.\n * If the secure store is not available, the session is fetched from the local config.\n * If the format of the session is invalid, the method will discard it.\n * In the future might add some logic for supporting migrating the schema\n * of already-persisted sessions.\n * @returns {Promise<Session\\undefined>} Returns a promise that resolves with the session if it exists and is valid.\n */\nexport async function fetch(): Promise<Session | undefined> {\n let content\n if (await secureStoreAvailable()) {\n content = await secureFetch(identifier)\n } else {\n content = cliKitStore().getSession()\n }\n\n if (!content) {\n return undefined\n }\n const contentJson = JSON.parse(content)\n const parsedSession = await SessionSchema.safeParseAsync(contentJson)\n if (parsedSession.success) {\n return parsedSession.data\n } else {\n await remove()\n return undefined\n }\n}\n\n/**\n * Removes a session from the system.\n */\nexport async function remove() {\n if (await secureStoreAvailable()) {\n await secureRemove(identifier)\n } else {\n cliKitStore().removeSession()\n }\n}\n\n/**\n * Returns true if the secure store is available on the system.\n * Keytar it's not supported on some Linux environments or Windows.\n * More details: https://github.com/Shopify/shopify-cli-planning/issues/261\n * @returns a boolean indicating if the secure store is available.\n */\nasync function secureStoreAvailable(): Promise<boolean> {\n try {\n if (platformAndArch().platform === 'windows') {\n debug(content`Secure store not supported on Windows`)\n return false\n }\n const keytar = await import('keytar')\n await keytar.default.findCredentials(constants.keychain.service)\n debug(content`Secure store is available`)\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (_error) {\n debug(content`Failed to load secure store`)\n return false\n }\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * It represents a temporary token that can be
3
+ * used to send authenticated HTTP requests.
4
+ */
5
+ declare class Token {
6
+ /**
7
+ * A fully-qualified domain name of the service
8
+ * this token is for.
9
+ */
10
+ fqdn: string;
11
+ /**
12
+ * Access token
13
+ */
14
+ accessToken: string;
15
+ /**
16
+ * Token to refresh the access token if it has expired.
17
+ */
18
+ refreshToken?: string;
19
+ /**
20
+ * The expiration date of the session
21
+ */
22
+ expiresAt: Date;
23
+ /**
24
+ * The list of scopes the token has access to.
25
+ */
26
+ scopes: string[];
27
+ constructor(options: {
28
+ fqdn: string;
29
+ accessToken: string;
30
+ refreshToken?: string;
31
+ expiresAt: Date;
32
+ scopes: string[];
33
+ });
34
+ /**
35
+ * Returns true if the session is expired.
36
+ * @returns {boolean} True if the session is expired.
37
+ */
38
+ get isExpired(): boolean;
39
+ }
40
+ export default Token;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * It represents a temporary token that can be
3
+ * used to send authenticated HTTP requests.
4
+ */
5
+ class Token {
6
+ constructor(options) {
7
+ this.fqdn = options.fqdn;
8
+ this.accessToken = options.accessToken;
9
+ this.refreshToken = options.refreshToken;
10
+ this.expiresAt = options.expiresAt;
11
+ this.scopes = options.scopes;
12
+ }
13
+ /**
14
+ * Returns true if the session is expired.
15
+ * @returns {boolean} True if the session is expired.
16
+ */
17
+ get isExpired() {
18
+ return new Date() > this.expiresAt;
19
+ }
20
+ }
21
+ export default Token;
22
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/session/token.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,KAAK;IA2BT,YAAY,OAAsG;QAChH,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;QACxB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAA;QACtC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAA;QACxC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;QAClC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC9B,CAAC;IAED;;;OAGG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAA;IACpC,CAAC;CACF;AAED,eAAe,KAAK,CAAA","sourcesContent":["/**\n * It represents a temporary token that can be\n * used to send authenticated HTTP requests.\n */\nclass Token {\n /**\n * A fully-qualified domain name of the service\n * this token is for.\n */\n fqdn: string\n\n /**\n * Access token\n */\n accessToken: string\n\n /**\n * Token to refresh the access token if it has expired.\n */\n refreshToken?: string\n\n /**\n * The expiration date of the session\n */\n expiresAt: Date\n\n /**\n * The list of scopes the token has access to.\n */\n scopes: string[]\n\n constructor(options: {fqdn: string; accessToken: string; refreshToken?: string; expiresAt: Date; scopes: string[]}) {\n this.fqdn = options.fqdn\n this.accessToken = options.accessToken\n this.refreshToken = options.refreshToken\n this.expiresAt = options.expiresAt\n this.scopes = options.scopes\n }\n\n /**\n * Returns true if the session is expired.\n * @returns {boolean} True if the session is expired.\n */\n get isExpired(): boolean {\n return new Date() > this.expiresAt\n }\n}\n\nexport default Token\n"]}