@shopify/cli-kit 3.0.23 → 3.0.26

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 (287) hide show
  1. package/CHANGELOG.md +28 -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 +11 -0
  12. package/dist/analytics.js +96 -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/functions/app_function_set.d.ts +43 -0
  54. package/dist/api/graphql/functions/app_function_set.js +52 -0
  55. package/dist/api/graphql/functions/app_function_set.js.map +1 -0
  56. package/dist/api/graphql/functions/compile_module.d.ts +15 -0
  57. package/dist/api/graphql/functions/compile_module.js +13 -0
  58. package/dist/api/graphql/functions/compile_module.js.map +1 -0
  59. package/dist/api/graphql/functions/function_service_proxy.d.ts +4 -0
  60. package/dist/api/graphql/functions/function_service_proxy.js +7 -0
  61. package/dist/api/graphql/functions/function_service_proxy.js.map +1 -0
  62. package/dist/api/graphql/functions/get_app_functions.d.ts +1 -0
  63. package/dist/api/graphql/functions/get_app_functions.js +10 -0
  64. package/dist/api/graphql/functions/get_app_functions.js.map +1 -0
  65. package/dist/api/graphql/functions/module_compilation_status.d.ts +15 -0
  66. package/dist/api/graphql/functions/module_compilation_status.js +13 -0
  67. package/dist/api/graphql/functions/module_compilation_status.js.map +1 -0
  68. package/dist/api/graphql/functions/module_upload_url_generate.d.ts +18 -0
  69. package/dist/api/graphql/functions/module_upload_url_generate.js +17 -0
  70. package/dist/api/graphql/functions/module_upload_url_generate.js.map +1 -0
  71. package/dist/api/graphql/generate_signed_upload_url.d.ts +15 -0
  72. package/dist/api/graphql/generate_signed_upload_url.js +15 -0
  73. package/dist/api/graphql/generate_signed_upload_url.js.map +1 -0
  74. package/dist/api/graphql/get_variant_id.d.ts +17 -0
  75. package/dist/api/graphql/get_variant_id.js +20 -0
  76. package/dist/api/graphql/get_variant_id.js.map +1 -0
  77. package/dist/api/graphql/index.d.ts +21 -0
  78. package/dist/api/graphql/index.js +22 -0
  79. package/dist/api/graphql/index.js.map +1 -0
  80. package/dist/api/graphql/update_draft.d.ts +33 -0
  81. package/dist/api/graphql/update_draft.js +24 -0
  82. package/dist/api/graphql/update_draft.js.map +1 -0
  83. package/dist/api/graphql/update_urls.d.ts +14 -0
  84. package/dist/api/graphql/update_urls.js +12 -0
  85. package/dist/api/graphql/update_urls.js.map +1 -0
  86. package/dist/api/identity.d.ts +1 -0
  87. package/dist/api/identity.js +29 -0
  88. package/dist/api/identity.js.map +1 -0
  89. package/dist/api/partners.d.ts +25 -0
  90. package/dist/api/partners.js +100 -0
  91. package/dist/api/partners.js.map +1 -0
  92. package/dist/api.d.ts +5 -0
  93. package/dist/api.js +6 -0
  94. package/dist/api.js.map +1 -0
  95. package/dist/checksum.d.ts +15 -0
  96. package/dist/checksum.js +27 -0
  97. package/dist/checksum.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/colors.d.ts +1 -0
  102. package/dist/colors.js +8 -0
  103. package/dist/colors.js.map +1 -0
  104. package/dist/constants.d.ts +43 -0
  105. package/dist/constants.js +63 -0
  106. package/dist/constants.js.map +1 -0
  107. package/dist/dependency.d.ts +128 -0
  108. package/dist/dependency.js +302 -0
  109. package/dist/dependency.js.map +1 -0
  110. package/dist/dot-env.d.ts +28 -0
  111. package/dist/dot-env.js +31 -0
  112. package/dist/dot-env.js.map +1 -0
  113. package/dist/environment/fqdn.d.ts +23 -0
  114. package/dist/environment/fqdn.js +61 -0
  115. package/dist/environment/fqdn.js.map +1 -0
  116. package/dist/environment/local.d.ts +48 -0
  117. package/dist/environment/local.js +82 -0
  118. package/dist/environment/local.js.map +1 -0
  119. package/dist/environment/service.d.ts +17 -0
  120. package/dist/environment/service.js +41 -0
  121. package/dist/environment/service.js.map +1 -0
  122. package/dist/environment/spin.d.ts +47 -0
  123. package/dist/environment/spin.js +83 -0
  124. package/dist/environment/spin.js.map +1 -0
  125. package/dist/environment/utilities.d.ts +6 -0
  126. package/dist/environment/utilities.js +12 -0
  127. package/dist/environment/utilities.js.map +1 -0
  128. package/dist/environment.d.ts +5 -0
  129. package/dist/environment.js +6 -0
  130. package/dist/environment.js.map +1 -0
  131. package/dist/error.d.ts +44 -0
  132. package/dist/error.js +91 -0
  133. package/dist/error.js.map +1 -0
  134. package/dist/file.d.ts +67 -0
  135. package/dist/file.js +165 -0
  136. package/dist/file.js.map +1 -0
  137. package/dist/git.d.ts +15 -0
  138. package/dist/git.js +48 -0
  139. package/dist/git.js.map +1 -0
  140. package/dist/github.d.ts +33 -0
  141. package/dist/github.js +56 -0
  142. package/dist/github.js.map +1 -0
  143. package/dist/haiku.d.ts +1 -0
  144. package/dist/haiku.js +8 -0
  145. package/dist/haiku.js.map +1 -0
  146. package/dist/http/fetch.d.ts +16 -0
  147. package/dist/http/fetch.js +18 -0
  148. package/dist/http/fetch.js.map +1 -0
  149. package/dist/http/formdata.d.ts +3 -0
  150. package/dist/http/formdata.js +6 -0
  151. package/dist/http/formdata.js.map +1 -0
  152. package/dist/http.d.ts +2 -0
  153. package/dist/http.js +3 -0
  154. package/dist/http.js.map +1 -0
  155. package/dist/id.d.ts +6 -0
  156. package/dist/id.js +18 -0
  157. package/dist/id.js.map +1 -0
  158. package/dist/index.d.ts +37 -2115
  159. package/dist/index.js +38 -46
  160. package/dist/index.js.map +1 -1
  161. package/dist/network/api.d.ts +2 -0
  162. package/dist/network/api.js +2 -0
  163. package/dist/network/api.js.map +1 -0
  164. package/dist/network/service.d.ts +16 -0
  165. package/dist/network/service.js +12 -0
  166. package/dist/network/service.js.map +1 -0
  167. package/dist/node/archiver.d.ts +6 -0
  168. package/dist/node/archiver.js +24 -0
  169. package/dist/node/archiver.js.map +1 -0
  170. package/dist/node/cli.d.ts +18 -0
  171. package/dist/node/cli.js +91 -0
  172. package/dist/node/cli.js.map +1 -0
  173. package/dist/npm.d.ts +27 -0
  174. package/dist/npm.js +20 -0
  175. package/dist/npm.js.map +1 -0
  176. package/dist/os.d.ts +10 -0
  177. package/dist/os.js +70 -0
  178. package/dist/os.js.map +1 -0
  179. package/dist/output.d.ts +142 -0
  180. package/dist/output.js +505 -0
  181. package/dist/output.js.map +1 -0
  182. package/dist/path.d.ts +22 -0
  183. package/dist/path.js +43 -0
  184. package/dist/path.js.map +1 -0
  185. package/dist/plugins.d.ts +9 -0
  186. package/dist/plugins.js +12 -0
  187. package/dist/plugins.js.map +1 -0
  188. package/dist/port.d.ts +5 -0
  189. package/dist/port.js +13 -0
  190. package/dist/port.js.map +1 -0
  191. package/dist/ruby.d.ts +21 -0
  192. package/dist/ruby.js +192 -0
  193. package/dist/ruby.js.map +1 -0
  194. package/dist/schema.d.ts +1 -0
  195. package/dist/schema.js +2 -0
  196. package/dist/schema.js.map +1 -0
  197. package/dist/secure-store.d.ts +19 -0
  198. package/dist/secure-store.js +63 -0
  199. package/dist/secure-store.js.map +1 -0
  200. package/dist/semver.d.ts +3 -0
  201. package/dist/semver.js +6 -0
  202. package/dist/semver.js.map +1 -0
  203. package/dist/session/authorize.d.ts +7 -0
  204. package/dist/session/authorize.js +40 -0
  205. package/dist/session/authorize.js.map +1 -0
  206. package/dist/session/exchange.d.ts +42 -0
  207. package/dist/session/exchange.js +144 -0
  208. package/dist/session/exchange.js.map +1 -0
  209. package/dist/session/identity.d.ts +3 -0
  210. package/dist/session/identity.js +58 -0
  211. package/dist/session/identity.js.map +1 -0
  212. package/dist/session/post-auth.d.ts +13 -0
  213. package/dist/session/post-auth.js +56 -0
  214. package/dist/session/post-auth.js.map +1 -0
  215. package/dist/session/redirect-listener.d.ts +34 -0
  216. package/dist/session/redirect-listener.js +97 -0
  217. package/dist/session/redirect-listener.js.map +1 -0
  218. package/dist/session/schema.d.ts +174 -0
  219. package/dist/session/schema.js +59 -0
  220. package/dist/session/schema.js.map +1 -0
  221. package/dist/session/scopes.d.ts +16 -0
  222. package/dist/session/scopes.js +53 -0
  223. package/dist/session/scopes.js.map +1 -0
  224. package/dist/session/store.d.ts +24 -0
  225. package/dist/session/store.js +88 -0
  226. package/dist/session/store.js.map +1 -0
  227. package/dist/session/token.d.ts +40 -0
  228. package/dist/session/token.js +22 -0
  229. package/dist/session/token.js.map +1 -0
  230. package/dist/session/validate.d.ts +17 -0
  231. package/dist/session/validate.js +75 -0
  232. package/dist/session/validate.js.map +1 -0
  233. package/dist/session.d.ts +88 -0
  234. package/dist/session.js +251 -0
  235. package/dist/session.js.map +1 -0
  236. package/dist/store/schema.d.ts +3 -0
  237. package/dist/store/schema.js +27 -0
  238. package/dist/store/schema.js.map +1 -0
  239. package/dist/store.d.ts +32 -0
  240. package/dist/store.js +102 -0
  241. package/dist/store.js.map +1 -0
  242. package/dist/string.d.ts +22 -0
  243. package/dist/string.js +38 -0
  244. package/dist/string.js.map +1 -0
  245. package/dist/system.d.ts +53 -0
  246. package/dist/system.js +109 -0
  247. package/dist/system.js.map +1 -0
  248. package/dist/template.d.ts +11 -0
  249. package/dist/template.js +50 -0
  250. package/dist/template.js.map +1 -0
  251. package/dist/testing/output.d.ts +9 -0
  252. package/dist/testing/output.js +15 -0
  253. package/dist/testing/output.js.map +1 -0
  254. package/dist/testing/store.d.ts +7 -0
  255. package/dist/testing/store.js +26 -0
  256. package/dist/testing/store.js.map +1 -0
  257. package/dist/toml.d.ts +3 -0
  258. package/dist/toml.js +8 -0
  259. package/dist/toml.js.map +1 -0
  260. package/dist/tsconfig.tsbuildinfo +1 -0
  261. package/dist/ui/autocomplete.d.ts +7 -0
  262. package/dist/ui/autocomplete.js +43 -0
  263. package/dist/ui/autocomplete.js.map +1 -0
  264. package/dist/ui/input.d.ts +7 -0
  265. package/dist/ui/input.js +48 -0
  266. package/dist/ui/input.js.map +1 -0
  267. package/dist/ui/select.d.ts +6 -0
  268. package/dist/ui/select.js +30 -0
  269. package/dist/ui/select.js.map +1 -0
  270. package/dist/ui.d.ts +36 -0
  271. package/dist/ui.js +124 -0
  272. package/dist/ui.js.map +1 -0
  273. package/dist/version.d.ts +19 -0
  274. package/dist/version.js +34 -0
  275. package/dist/version.js.map +1 -0
  276. package/dist/vscode.d.ts +8 -0
  277. package/dist/vscode.js +36 -0
  278. package/dist/vscode.js.map +1 -0
  279. package/dist/yaml.d.ts +2 -0
  280. package/dist/yaml.js +8 -0
  281. package/dist/yaml.js.map +1 -0
  282. package/package.json +32 -21
  283. package/dist/index-160b2bd2.js +0 -175294
  284. package/dist/index-160b2bd2.js.map +0 -1
  285. package/dist/index.d.ts.map +0 -1
  286. package/dist/multipart-parser-7ce1f707.js +0 -477
  287. package/dist/multipart-parser-7ce1f707.js.map +0 -1
@@ -0,0 +1,144 @@
1
+ import { applicationId, clientId as getIdentityClientId } from './identity.js';
2
+ import * as secureStore from './store.js';
3
+ import { Abort } from '../error.js';
4
+ import { fetch } from '../http.js';
5
+ import { identity as identityFqdn } from '../environment/fqdn.js';
6
+ export class InvalidGrantError extends Error {
7
+ }
8
+ const InvalidIdentityError = new Abort('\nError validating auth session', "We've cleared the current session, please try again");
9
+ /**
10
+ * Given a valid authorization code, request an identity access token.
11
+ * This token can then be used to get API specific tokens.
12
+ * @param codeData code and codeVerifier from the authorize endpoint
13
+ * @param clientId
14
+ * @param identityFqdn
15
+ * @returns {Promise<IdentityToken>} An instance with the identity access tokens.
16
+ */
17
+ export async function exchangeCodeForAccessToken(codeData) {
18
+ const clientId = await getIdentityClientId();
19
+ /* eslint-disable @typescript-eslint/naming-convention */
20
+ const params = {
21
+ grant_type: 'authorization_code',
22
+ code: codeData.code,
23
+ redirect_uri: 'http://127.0.0.1:3456',
24
+ client_id: clientId,
25
+ code_verifier: codeData.codeVerifier,
26
+ };
27
+ /* eslint-enable @typescript-eslint/naming-convention */
28
+ return tokenRequest(params).then(buildIdentityToken);
29
+ }
30
+ /**
31
+ * Given an identity token, request an application token.
32
+ * @param token access token obtained in a previous step
33
+ * @param store the store to use, only needed for admin API
34
+ * @param clientId
35
+ * @param identityFqdn
36
+ * @returns {Promise<ApplicationSchema>} An array with the application access tokens.
37
+ */
38
+ export async function exchangeAccessForApplicationTokens(identityToken, scopes, store) {
39
+ const token = identityToken.accessToken;
40
+ const partners = await requestAppToken('partners', token, scopes.partners);
41
+ const storefront = await requestAppToken('storefront-renderer', token, scopes.storefront);
42
+ const result = {
43
+ ...partners,
44
+ ...storefront,
45
+ };
46
+ if (store) {
47
+ const admin = await requestAppToken('admin', token, scopes.admin, store);
48
+ Object.assign(result, admin);
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Given an expired access token, refresh it to get a new one.
54
+ * @param currentToken
55
+ * @returns
56
+ */
57
+ export async function refreshAccessToken(currentToken) {
58
+ const clientId = await getIdentityClientId();
59
+ /* eslint-disable @typescript-eslint/naming-convention */
60
+ const params = {
61
+ grant_type: 'refresh_token',
62
+ access_token: currentToken.accessToken,
63
+ refresh_token: currentToken.refreshToken,
64
+ client_id: clientId,
65
+ };
66
+ /* eslint-enable @typescript-eslint/naming-convention */
67
+ return tokenRequest(params).then(buildIdentityToken);
68
+ }
69
+ /**
70
+ * Given a custom CLI token passed as ENV variable, request a valid partners API token
71
+ * This token does not accept extra scopes, just the cli one.
72
+ * @param token {string} The CLI token passed as ENV variable
73
+ * @returns {Promise<ApplicationToken>} An instance with the application access tokens.
74
+ */
75
+ export async function exchangeCustomPartnerToken(token) {
76
+ const appId = applicationId('partners');
77
+ const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access']);
78
+ return newToken[appId];
79
+ }
80
+ async function requestAppToken(api, token, scopes = [], store) {
81
+ const appId = applicationId(api);
82
+ const clientId = await getIdentityClientId();
83
+ /* eslint-disable @typescript-eslint/naming-convention */
84
+ const params = {
85
+ grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
86
+ requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',
87
+ subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
88
+ client_id: clientId,
89
+ audience: appId,
90
+ scope: scopes.join(' '),
91
+ subject_token: token,
92
+ ...(api === 'admin' && { destination: `https://${store}/admin` }),
93
+ };
94
+ /* eslint-enable @typescript-eslint/naming-convention */
95
+ let identifier = appId;
96
+ if (api === 'admin' && store) {
97
+ identifier = `${store}-${appId}`;
98
+ }
99
+ const appToken = await tokenRequest(params).then(buildApplicationToken);
100
+ return { [identifier]: appToken };
101
+ }
102
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
103
+ async function tokenRequest(params) {
104
+ const fqdn = await identityFqdn();
105
+ const url = new URL(`https://${fqdn}/oauth/token`);
106
+ url.search = new URLSearchParams(Object.entries(params)).toString();
107
+ const res = await fetch(url.href, { method: 'POST' });
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
+ const payload = await res.json();
110
+ if (!res.ok) {
111
+ if (payload.error === 'invalid_grant') {
112
+ // There's an scenario when Identity returns "invalid_grant" when trying to refresh the token
113
+ // using a valid refresh token. When that happens, we take the user through the authentication flow.
114
+ throw new InvalidGrantError(payload.error_description);
115
+ }
116
+ else if (payload.error === 'invalid_request') {
117
+ // There's an scenario when Identity returns "invalid_request" when exchanging an identity token.
118
+ // This means the token is invalid. We clear the session and throw an error to let the caller know.
119
+ secureStore.remove();
120
+ throw InvalidIdentityError;
121
+ }
122
+ else {
123
+ throw new Abort(payload.error_description);
124
+ }
125
+ }
126
+ return payload;
127
+ }
128
+ function buildIdentityToken(result) {
129
+ return {
130
+ accessToken: result.access_token,
131
+ refreshToken: result.refresh_token,
132
+ expiresAt: new Date(Date.now() + result.expires_in * 1000),
133
+ scopes: result.scope.split(' '),
134
+ };
135
+ }
136
+ // eslint-disable-next-line @typescript-eslint/naming-convention
137
+ function buildApplicationToken(result) {
138
+ return {
139
+ accessToken: result.access_token,
140
+ expiresAt: new Date(Date.now() + result.expires_in * 1000),
141
+ scopes: result.scope.split(' '),
142
+ };
143
+ }
144
+ //# sourceMappingURL=exchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {CodeAuthResult} from './authorize.js'\nimport * as secureStore from './store.js'\nimport {Abort} from '../error.js'\nimport {API} from '../network/api.js'\nimport {fetch} from '../http.js'\nimport {identity as identityFqdn} from '../environment/fqdn.js'\n\nexport class InvalidGrantError extends Error {}\n\nconst InvalidIdentityError = new Abort(\n '\\nError validating auth session',\n \"We've cleared the current session, please try again\",\n)\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n}\n/**\n * Given a valid authorization code, request an identity access token.\n * This token can then be used to get API specific tokens.\n * @param codeData code and codeVerifier from the authorize endpoint\n * @param clientId\n * @param identityFqdn\n * @returns {Promise<IdentityToken>} An instance with the identity access tokens.\n */\nexport async function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n /* eslint-disable @typescript-eslint/naming-convention */\n const params = {\n grant_type: 'authorization_code',\n code: codeData.code,\n redirect_uri: 'http://127.0.0.1:3456',\n client_id: clientId,\n code_verifier: codeData.codeVerifier,\n }\n /* eslint-enable @typescript-eslint/naming-convention */\n\n return tokenRequest(params).then(buildIdentityToken)\n}\n\n/**\n * Given an identity token, request an application token.\n * @param token access token obtained in a previous step\n * @param store the store to use, only needed for admin API\n * @param clientId\n * @param identityFqdn\n * @returns {Promise<ApplicationSchema>} An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const partners = await requestAppToken('partners', token, scopes.partners)\n const storefront = await requestAppToken('storefront-renderer', token, scopes.storefront)\n\n const result = {\n ...partners,\n ...storefront,\n }\n\n if (store) {\n const admin = await requestAppToken('admin', token, scopes.admin, store)\n Object.assign(result, admin)\n }\n return result\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n * @param currentToken\n * @returns\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n /* eslint-disable @typescript-eslint/naming-convention */\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n /* eslint-enable @typescript-eslint/naming-convention */\n return tokenRequest(params).then(buildIdentityToken)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token {string} The CLI token passed as ENV variable\n * @returns {Promise<ApplicationToken>} An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<ApplicationToken> {\n const appId = applicationId('partners')\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n /* eslint-disable @typescript-eslint/naming-convention */\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n /* eslint-enable @typescript-eslint/naming-convention */\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const appToken = await tokenRequest(params).then(buildApplicationToken)\n return {[identifier]: appToken}\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function tokenRequest(params: {[key: string]: string}): Promise<any> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await fetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n if (!res.ok) {\n if (payload.error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n throw new InvalidGrantError(payload.error_description)\n } else if (payload.error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n secureStore.remove()\n throw InvalidIdentityError\n } else {\n throw new Abort(payload.error_description)\n }\n }\n return payload\n}\n\nfunction buildIdentityToken(result: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n access_token: string\n // eslint-disable-next-line @typescript-eslint/naming-convention\n refresh_token: string\n // eslint-disable-next-line @typescript-eslint/naming-convention\n expires_in: number\n scope: string\n}): IdentityToken {\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nfunction buildApplicationToken(result: {access_token: string; expires_in: number; scope: string}): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { API } from '../network/api.js';
2
+ export declare function clientId(): string;
3
+ export declare function applicationId(api: API): string;
@@ -0,0 +1,58 @@
1
+ import { Bug } from '../error.js';
2
+ import { shopify as shopifyEnvironment, partners as partnersEnvironment, identity as identityEnvironment, } from '../environment/service.js';
3
+ import { Environment } from '../network/service.js';
4
+ export function clientId() {
5
+ const environment = identityEnvironment();
6
+ if (environment === Environment.Local) {
7
+ return 'e5380e02-312a-7408-5718-e07017e9cf52';
8
+ }
9
+ else if (environment === Environment.Production) {
10
+ return 'fbdb2649-e327-4907-8f67-908d24cfd7e3';
11
+ }
12
+ else {
13
+ return 'e5380e02-312a-7408-5718-e07017e9cf52';
14
+ }
15
+ }
16
+ export function applicationId(api) {
17
+ switch (api) {
18
+ case 'admin': {
19
+ const environment = shopifyEnvironment();
20
+ if (environment === Environment.Local) {
21
+ return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52';
22
+ }
23
+ else if (environment === Environment.Production) {
24
+ return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c';
25
+ }
26
+ else {
27
+ return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52';
28
+ }
29
+ }
30
+ case 'partners': {
31
+ const environment = partnersEnvironment();
32
+ if (environment === Environment.Local) {
33
+ return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978';
34
+ }
35
+ else if (environment === Environment.Production) {
36
+ return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6';
37
+ }
38
+ else {
39
+ return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978';
40
+ }
41
+ }
42
+ case 'storefront-renderer': {
43
+ const environment = shopifyEnvironment();
44
+ if (environment === Environment.Local) {
45
+ return '46f603de-894f-488d-9471-5b721280ff49';
46
+ }
47
+ else if (environment === Environment.Production) {
48
+ return 'ee139b3d-5861-4d45-b387-1bc3ada7811c';
49
+ }
50
+ else {
51
+ return '46f603de-894f-488d-9471-5b721280ff49';
52
+ }
53
+ }
54
+ default:
55
+ throw new Bug(`Application id for API of type: ${api}`);
56
+ }
57
+ }
58
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/session/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAC/B,OAAO,EACL,OAAO,IAAI,kBAAkB,EAC7B,QAAQ,IAAI,mBAAmB,EAC/B,QAAQ,IAAI,mBAAmB,GAChC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAGjD,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAA;IACzC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;QACrC,OAAO,sCAAsC,CAAA;KAC9C;SAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;QACjD,OAAO,sCAAsC,CAAA;KAC9C;SAAM;QACL,OAAO,sCAAsC,CAAA;KAC9C;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO,CAAC,CAAC;YACZ,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,UAAU,CAAC,CAAC;YACf,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAA;YACzC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,qBAAqB,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD;YACE,MAAM,IAAI,GAAG,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAA;KAC1D;AACH,CAAC","sourcesContent":["import {Bug} from '../error.js'\nimport {\n shopify as shopifyEnvironment,\n partners as partnersEnvironment,\n identity as identityEnvironment,\n} from '../environment/service.js'\nimport {Environment} from '../network/service.js'\nimport {API} from '../network/api.js'\n\nexport function clientId(): string {\n const environment = identityEnvironment()\n if (environment === Environment.Local) {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n } else if (environment === Environment.Production) {\n return 'fbdb2649-e327-4907-8f67-908d24cfd7e3'\n } else {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n }\n}\n\nexport function applicationId(api: API): string {\n switch (api) {\n case 'admin': {\n const environment = shopifyEnvironment()\n if (environment === Environment.Local) {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n } else if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n case 'partners': {\n const environment = partnersEnvironment()\n if (environment === Environment.Local) {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n } else if (environment === Environment.Production) {\n return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6'\n } else {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n }\n }\n case 'storefront-renderer': {\n const environment = shopifyEnvironment()\n if (environment === Environment.Local) {\n return '46f603de-894f-488d-9471-5b721280ff49'\n } else if (environment === Environment.Production) {\n return 'ee139b3d-5861-4d45-b387-1bc3ada7811c'\n } else {\n return '46f603de-894f-488d-9471-5b721280ff49'\n }\n }\n default:\n throw new Bug(`Application id for API of type: ${api}`)\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { Bug } from '../error.js';
2
+ export declare const getEmptyUrlHTML: () => Promise<string>;
3
+ export declare const getAuthErrorHTML: () => Promise<string>;
4
+ export declare const getMissingCodeHTML: () => Promise<string>;
5
+ export declare const getMissingStateHTML: () => Promise<string>;
6
+ export declare const getSuccessHTML: () => Promise<string>;
7
+ export declare const getStylesheet: () => Promise<string>;
8
+ export declare const getFavicon: () => Promise<string>;
9
+ export declare const EmptyUrlString = "We received the authentication redirect but the URL is empty.";
10
+ export declare const AuthErrorString = "There was an issue while trying to authenticate.";
11
+ export declare const MissingCodeString = "The authentication can't continue because the redirect doesn't include the code.";
12
+ export declare const MissingStateString = "The authentication can't continue because the redirect doesn't include the state.";
13
+ export declare const RedirectPageAssetNotFoundError: () => Bug;
@@ -0,0 +1,56 @@
1
+ import { findUp, moduleDirectory } from '../path.js';
2
+ import { read } from '../file.js';
3
+ import { Bug } from '../error.js';
4
+ const HTMLFileNames = ['empty-url.html', 'auth-error.html', 'missing-code.html', 'missing-state.html', 'success.html'];
5
+ const StylesheetFilename = 'style.css';
6
+ const FaviconFileName = 'favicon.svg';
7
+ /**
8
+ * Finds the full path of the given file-name from the assets folder.
9
+ *
10
+ * @param {string} fileName The name of the file to look for.
11
+ * @returns {string | null} The full path of the file, or null if not found.
12
+ */
13
+ const getFilePath = async (fileName) => {
14
+ const filePath = await findUp(`assets/${fileName}`, {
15
+ type: 'file',
16
+ cwd: moduleDirectory(import.meta.url),
17
+ });
18
+ if (!filePath) {
19
+ throw RedirectPageAssetNotFoundError();
20
+ }
21
+ return filePath;
22
+ };
23
+ export const getEmptyUrlHTML = async () => {
24
+ const filePath = await getFilePath(HTMLFileNames[0]);
25
+ return read(filePath);
26
+ };
27
+ export const getAuthErrorHTML = async () => {
28
+ const filePath = await getFilePath(HTMLFileNames[1]);
29
+ return read(filePath);
30
+ };
31
+ export const getMissingCodeHTML = async () => {
32
+ const filePath = await getFilePath(HTMLFileNames[2]);
33
+ return read(filePath);
34
+ };
35
+ export const getMissingStateHTML = async () => {
36
+ const filePath = await getFilePath(HTMLFileNames[3]);
37
+ return read(filePath);
38
+ };
39
+ export const getSuccessHTML = async () => {
40
+ const filePath = await getFilePath(HTMLFileNames[4]);
41
+ return read(filePath);
42
+ };
43
+ export const getStylesheet = async () => {
44
+ const filePath = await getFilePath(StylesheetFilename);
45
+ return read(filePath);
46
+ };
47
+ export const getFavicon = async () => {
48
+ const filePath = await getFilePath(FaviconFileName);
49
+ return read(filePath);
50
+ };
51
+ export const EmptyUrlString = 'We received the authentication redirect but the URL is empty.';
52
+ export const AuthErrorString = 'There was an issue while trying to authenticate.';
53
+ export const MissingCodeString = "The authentication can't continue because the redirect doesn't include the code.";
54
+ export const MissingStateString = "The authentication can't continue because the redirect doesn't include the state.";
55
+ export const RedirectPageAssetNotFoundError = () => new Bug(`Redirect page asset not found`);
56
+ //# sourceMappingURL=post-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-auth.js","sourceRoot":"","sources":["../../src/session/post-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,eAAe,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAE/B,MAAM,aAAa,GAAG,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,CAAC,CAAA;AACtH,MAAM,kBAAkB,GAAG,WAAW,CAAA;AACtC,MAAM,eAAe,GAAG,aAAa,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,QAAQ,EAAE,EAAE;QAClD,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACtC,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,8BAA8B,EAAE,CAAA;KACvC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,IAAqB,EAAE;IACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAqB,EAAE;IAC1D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,IAAqB,EAAE;IAC5D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,IAAqB,EAAE;IAC7D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IACxD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAqB,EAAE;IACvD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,kBAAkB,CAAC,CAAA;IACtD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAqB,EAAE;IACpD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,CAAA;IACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,+DAA+D,CAAA;AAE7F,MAAM,CAAC,MAAM,eAAe,GAAG,kDAAkD,CAAA;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,kFAAkF,CAAA;AAEnH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mFAAmF,CAAA;AAErH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,+BAA+B,CAAC,CAAA","sourcesContent":["import {findUp, moduleDirectory} from '../path.js'\nimport {read} from '../file.js'\nimport {Bug} from '../error.js'\n\nconst HTMLFileNames = ['empty-url.html', 'auth-error.html', 'missing-code.html', 'missing-state.html', 'success.html']\nconst StylesheetFilename = 'style.css'\nconst FaviconFileName = 'favicon.svg'\n\n/**\n * Finds the full path of the given file-name from the assets folder.\n *\n * @param {string} fileName The name of the file to look for.\n * @returns {string | null} The full path of the file, or null if not found.\n */\nconst getFilePath = async (fileName: string): Promise<string> => {\n const filePath = await findUp(`assets/${fileName}`, {\n type: 'file',\n cwd: moduleDirectory(import.meta.url),\n })\n if (!filePath) {\n throw RedirectPageAssetNotFoundError()\n }\n return filePath\n}\n\nexport const getEmptyUrlHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[0])\n return read(filePath)\n}\n\nexport const getAuthErrorHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[1])\n return read(filePath)\n}\n\nexport const getMissingCodeHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[2])\n return read(filePath)\n}\n\nexport const getMissingStateHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[3])\n return read(filePath)\n}\n\nexport const getSuccessHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[4])\n return read(filePath)\n}\n\nexport const getStylesheet = async (): Promise<string> => {\n const filePath = await getFilePath(StylesheetFilename)\n return read(filePath)\n}\n\nexport const getFavicon = async (): Promise<string> => {\n const filePath = await getFilePath(FaviconFileName)\n return read(filePath)\n}\n\nexport const EmptyUrlString = 'We received the authentication redirect but the URL is empty.'\n\nexport const AuthErrorString = 'There was an issue while trying to authenticate.'\n\nexport const MissingCodeString = \"The authentication can't continue because the redirect doesn't include the code.\"\n\nexport const MissingStateString = \"The authentication can't continue because the redirect doesn't include the state.\"\n\nexport const RedirectPageAssetNotFoundError = () => new Bug(`Redirect page asset not found`)\n"]}
@@ -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 {};